refactor event
This commit is contained in:
@@ -95,8 +95,8 @@
|
||||
class="delete bg-white"
|
||||
theme="danger"
|
||||
variant="outline"
|
||||
:loading="removing"
|
||||
:disabled="saving || removing"
|
||||
:loading="isRemoving"
|
||||
:disabled="isSaving || isRemoving"
|
||||
@click="confirmRemoveEventItem"
|
||||
>
|
||||
删除事件
|
||||
@@ -105,8 +105,8 @@
|
||||
v-can="savePermissionCode"
|
||||
class="save"
|
||||
theme="primary"
|
||||
:loading="saving"
|
||||
:disabled="removing"
|
||||
:loading="isSaving"
|
||||
:disabled="isRemoving"
|
||||
@click="saveEventItem"
|
||||
>
|
||||
保存
|
||||
@@ -201,6 +201,7 @@ defineOptions({
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const routeId = computed(() => String(route.params.id || ""));
|
||||
|
||||
const isCreateMode = computed(() => !routeId.value);
|
||||
const savePermissionCode = computed(() => isCreateMode.value ? permissionCodes.event.create : permissionCodes.event.update);
|
||||
const deletePermissionCode = permissionCodes.event.delete;
|
||||
@@ -208,44 +209,12 @@ const pageAccess = computed(() => ({
|
||||
value: [permissionCodes.event.read, permissionCodes.user.read, savePermissionCode.value],
|
||||
mode: "and" as const
|
||||
}));
|
||||
|
||||
// ---------- 基础表单 ----------
|
||||
|
||||
const roleOptions = ref<Role[]>([]);
|
||||
const colorPickerVisible = ref(false);
|
||||
const colorPickerRenderKey = ref(0);
|
||||
const colorDraft = ref("#2f88ff");
|
||||
const beginAtPickerVisible = ref(false);
|
||||
const endAtPickerVisible = ref(false);
|
||||
const beginAtDraftText = ref("");
|
||||
const endAtDraftText = ref("");
|
||||
const saving = ref(false);
|
||||
const removing = ref(false);
|
||||
const colorSwatchList = [
|
||||
"#2F88FF",
|
||||
"#0EA5E9",
|
||||
"#10B981",
|
||||
"#22C55E",
|
||||
"#F59E0B",
|
||||
"#F97316",
|
||||
"#EF4444",
|
||||
"#EC4899",
|
||||
"#8B5CF6",
|
||||
"#64748B"
|
||||
];
|
||||
const limitOptions: LimitOption[] = [
|
||||
{ label: "不限", value: "NONE" },
|
||||
{ label: "上午和下午各一次", value: "DAILY_HALF_DAY" },
|
||||
{ label: "间隔小时内一次", value: "INTERVAL_HOUR" },
|
||||
{ label: "每个自然日一次", value: "NATURAL_DAY" },
|
||||
{ label: "每个自然月一次", value: "NATURAL_MONTH" },
|
||||
{ label: "事件总次数", value: "TOTAL_LIMIT" },
|
||||
{ label: "单客户总次数", value: "CUSTOMER_TOTAL_LIMIT" }
|
||||
];
|
||||
const statusOptions: Array<{ label: string; value: EventStatus }> = [
|
||||
{ label: "草稿", value: "DRAFT" },
|
||||
{ label: "可登记", value: "ACTIVE" },
|
||||
{ label: "不可登记", value: "INACTIVE" }
|
||||
];
|
||||
const limitPickerColumns = [limitOptions];
|
||||
const statusPickerColumns = [statusOptions];
|
||||
const isSaving = ref(false);
|
||||
const isRemoving = ref(false);
|
||||
const formModel = reactive({
|
||||
id: "",
|
||||
name: "",
|
||||
@@ -259,10 +228,57 @@ const formModel = reactive({
|
||||
endAtText: "",
|
||||
roleCodeList: [] as string[]
|
||||
});
|
||||
|
||||
// ---------- 颜色 ----------
|
||||
|
||||
const colorPickerVisible = ref(false);
|
||||
const colorPickerRenderKey = ref(0);
|
||||
const colorDraft = ref("#2f88ff");
|
||||
const colorSwatchList = [
|
||||
"#2F88FF",
|
||||
"#0EA5E9",
|
||||
"#10B981",
|
||||
"#22C55E",
|
||||
"#F59E0B",
|
||||
"#F97316",
|
||||
"#EF4444",
|
||||
"#EC4899",
|
||||
"#8B5CF6",
|
||||
"#64748B"
|
||||
];
|
||||
|
||||
// ---------- 次数限制 ----------
|
||||
|
||||
const limitOptions: LimitOption[] = [
|
||||
{ label: "不限", value: "NONE" },
|
||||
{ label: "上午和下午各一次", value: "DAILY_HALF_DAY" },
|
||||
{ label: "间隔小时内一次", value: "INTERVAL_HOUR" },
|
||||
{ label: "每个自然日一次", value: "NATURAL_DAY" },
|
||||
{ label: "每个自然月一次", value: "NATURAL_MONTH" },
|
||||
{ label: "事件总次数", value: "TOTAL_LIMIT" },
|
||||
{ label: "单客户总次数", value: "CUSTOMER_TOTAL_LIMIT" }
|
||||
];
|
||||
const limitPickerColumns = [limitOptions];
|
||||
const limitPickerVisible = ref(false);
|
||||
const limitPickerDraft = ref<string[]>([formModel.limitType]);
|
||||
|
||||
// ---------- 状态 ----------
|
||||
|
||||
const statusOptions: Array<{ label: string; value: EventStatus }> = [
|
||||
{ label: "草稿", value: "DRAFT" },
|
||||
{ label: "可登记", value: "ACTIVE" },
|
||||
{ label: "不可登记", value: "INACTIVE" }
|
||||
];
|
||||
const statusPickerColumns = [statusOptions];
|
||||
const statusPickerVisible = ref(false);
|
||||
const statusPickerDraft = ref<EventStatus[]>([formModel.status]);
|
||||
|
||||
// ---------- 生效时间 ----------
|
||||
|
||||
const beginAtPickerVisible = ref(false);
|
||||
const endAtPickerVisible = ref(false);
|
||||
const beginAtDraftText = ref("");
|
||||
const endAtDraftText = ref("");
|
||||
const minimumDateTimeText = "1970-01-01 00:00";
|
||||
const nowDateTimeText = computed(() => Time.formatDateTime(new Date()));
|
||||
const endAtMinimumDateTimeText = computed(() => formModel.beginAtText || minimumDateTimeText);
|
||||
@@ -281,6 +297,8 @@ const limitValuePlaceholder = computed(() => {
|
||||
return "请输入总次数上限";
|
||||
});
|
||||
|
||||
// ---------- 颜色 ----------
|
||||
|
||||
function openColorPicker(): void {
|
||||
colorDraft.value = formModel.color;
|
||||
colorPickerVisible.value = true;
|
||||
@@ -304,6 +322,8 @@ function updateColorDraftFromPalette(context: { color: ColorObject }): void {
|
||||
colorDraft.value = context.color.hex8;
|
||||
}
|
||||
|
||||
// ---------- 选项文案 ----------
|
||||
|
||||
function getLimitText(value: EventLimitType): string {
|
||||
return limitOptions.find(option => option.value === value)?.label || "不限";
|
||||
}
|
||||
@@ -312,6 +332,8 @@ function getStatusText(value: EventStatus): string {
|
||||
return statusOptions.find(option => option.value === value)?.label || "可登记";
|
||||
}
|
||||
|
||||
// ---------- 次数限制 ----------
|
||||
|
||||
function openLimitPicker(): void {
|
||||
limitPickerDraft.value = [formModel.limitType];
|
||||
limitPickerVisible.value = true;
|
||||
@@ -325,6 +347,8 @@ function confirmLimitPicker(value: Array<string | number>): void {
|
||||
limitPickerVisible.value = false;
|
||||
}
|
||||
|
||||
// ---------- 状态 ----------
|
||||
|
||||
function openStatusPicker(): void {
|
||||
statusPickerDraft.value = [formModel.status];
|
||||
statusPickerVisible.value = true;
|
||||
@@ -351,6 +375,8 @@ function resolveLimitValue(): number | undefined {
|
||||
return 0 < value ? Math.floor(value) : undefined;
|
||||
}
|
||||
|
||||
// ---------- 表单转换 ----------
|
||||
|
||||
function resolveTimestamp(valueText: string): number | undefined {
|
||||
if (!valueText.trim()) {
|
||||
return undefined;
|
||||
@@ -363,41 +389,27 @@ function resolveTimestamp(valueText: string): number | undefined {
|
||||
|
||||
function validateForm(): boolean {
|
||||
if (!formModel.name.trim()) {
|
||||
showToast("请输入登记事件名称", "warning");
|
||||
Toast.warning("请输入登记事件名称");
|
||||
return false;
|
||||
}
|
||||
if (!formModel.roleCodeList.length) {
|
||||
showToast("请至少选择一个可登记角色", "warning");
|
||||
Toast.warning("请至少选择一个可登记角色");
|
||||
return false;
|
||||
}
|
||||
if (isValueLimitType(formModel.limitType) && !resolveLimitValue()) {
|
||||
showToast("请输入有效的约束数值", "warning");
|
||||
Toast.warning("请输入有效的约束数值");
|
||||
return false;
|
||||
}
|
||||
const beginAt = resolveTimestamp(formModel.beginAtText);
|
||||
const endAt = resolveTimestamp(formModel.endAtText);
|
||||
if (beginAt !== undefined && endAt !== undefined && endAt < beginAt) {
|
||||
showToast("终止时间不能早于起始时间", "warning");
|
||||
Toast.warning("终止时间不能早于起始时间");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function buildPayload(): EventItem {
|
||||
return {
|
||||
id: formModel.id || undefined,
|
||||
name: formModel.name.trim(),
|
||||
description: formModel.description,
|
||||
color: formModel.color,
|
||||
status: formModel.status,
|
||||
requirePhoto: formModel.requirePhoto,
|
||||
limitType: formModel.limitType,
|
||||
limitValue: resolveLimitValue(),
|
||||
beginAt: resolveTimestamp(formModel.beginAtText),
|
||||
endAt: resolveTimestamp(formModel.endAtText),
|
||||
roleCodeList: [...formModel.roleCodeList]
|
||||
};
|
||||
}
|
||||
// ---------- 生效时间 ----------
|
||||
|
||||
function openBeginAtPicker(): void {
|
||||
beginAtDraftText.value = formModel.beginAtText || nowDateTimeText.value;
|
||||
@@ -431,34 +443,48 @@ function clearEndAt(): void {
|
||||
endAtPickerVisible.value = false;
|
||||
}
|
||||
|
||||
// ---------- 保存 ----------
|
||||
|
||||
async function saveEventItem(): Promise<void> {
|
||||
if (!validateForm()) {
|
||||
return;
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
isSaving.value = true;
|
||||
try {
|
||||
const payload = buildPayload();
|
||||
const payload: EventItem = {
|
||||
id: formModel.id || undefined,
|
||||
name: formModel.name.trim(),
|
||||
description: formModel.description,
|
||||
color: formModel.color,
|
||||
status: formModel.status,
|
||||
requirePhoto: formModel.requirePhoto,
|
||||
limitType: formModel.limitType,
|
||||
limitValue: resolveLimitValue(),
|
||||
beginAt: resolveTimestamp(formModel.beginAtText),
|
||||
endAt: resolveTimestamp(formModel.endAtText),
|
||||
roleCodeList: [...formModel.roleCodeList]
|
||||
};
|
||||
if (isCreateMode.value) {
|
||||
await EventAPI.create(payload);
|
||||
} else {
|
||||
await EventAPI.update(payload);
|
||||
}
|
||||
showToast("登记事件已保存");
|
||||
Toast.success("登记事件已保存");
|
||||
await router.replace("/management/registration-events");
|
||||
} catch {
|
||||
showToast("登记事件保存失败", "error");
|
||||
Toast.error("登记事件保存失败");
|
||||
} finally {
|
||||
saving.value = false;
|
||||
isSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 删除 ----------
|
||||
|
||||
async function confirmRemoveEventItem(): Promise<void> {
|
||||
const id = formModel.id || routeId.value;
|
||||
if (!id || removing.value) {
|
||||
if (!id || isRemoving.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const eventName = formModel.name.trim() || "未命名事件";
|
||||
const dialog = DialogPlugin.confirm({
|
||||
title: "删除登记事件",
|
||||
@@ -476,36 +502,28 @@ async function confirmRemoveEventItem(): Promise<void> {
|
||||
}
|
||||
|
||||
async function removeEventItem(id: string): Promise<void> {
|
||||
if (removing.value) {
|
||||
if (isRemoving.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
removing.value = true;
|
||||
isRemoving.value = true;
|
||||
try {
|
||||
await EventAPI.remove(id);
|
||||
showToast("登记事件已删除");
|
||||
Toast.success("登记事件已删除");
|
||||
await router.replace("/management/registration-events");
|
||||
} catch {
|
||||
showToast("登记事件删除失败", "error");
|
||||
Toast.error("登记事件删除失败");
|
||||
} finally {
|
||||
removing.value = false;
|
||||
isRemoving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function showToast(message: string, theme: "success" | "error" | "warning" = "success"): void {
|
||||
Toast({
|
||||
theme,
|
||||
direction: "row",
|
||||
message
|
||||
});
|
||||
}
|
||||
// ---------- 页面数据 ----------
|
||||
|
||||
async function fillForm(): Promise<void> {
|
||||
roleOptions.value = await ManagedUserAPI.roleList();
|
||||
if (isCreateMode.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const current = await EventAPI.detail(routeId.value);
|
||||
Object.assign(formModel, {
|
||||
id: current.id || "",
|
||||
@@ -516,8 +534,8 @@ async function fillForm(): Promise<void> {
|
||||
requirePhoto: current.requirePhoto ?? false,
|
||||
limitType: current.limitType || "NONE",
|
||||
limitValueText: current.limitValue ? String(current.limitValue) : "",
|
||||
beginAtText: current.beginAt ? Time.formatDateTime(new Date(current.beginAt)) : "",
|
||||
endAtText: current.endAt ? Time.formatDateTime(new Date(current.endAt)) : "",
|
||||
beginAtText: current.beginAt ? Time.toDateTime(current.beginAt) : "",
|
||||
endAtText: current.endAt ? Time.toDateTime(current.endAt) : "",
|
||||
roleCodeList: [...(current.roleCodeList || [])]
|
||||
});
|
||||
colorDraft.value = formModel.color;
|
||||
@@ -527,7 +545,7 @@ onMounted(async () => {
|
||||
try {
|
||||
await fillForm();
|
||||
} catch {
|
||||
showToast("登记事件加载失败", "error");
|
||||
Toast.error("登记事件加载失败");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -696,4 +714,3 @@ onMounted(async () => {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user