import { Search } from "@element-plus/icons-vue"; import dayjs from "dayjs"; import { ElMessageBox } from "element-plus"; import { computed, reactive, ref, watch } from "vue"; import { createEmptyTemplateForm, createInitialMockTemplates, flowNodesSummary, getBuiltinTemplates, loadStoredTemplates, nodeSignModeLabel, saveStoredTemplates, validateTemplateForm, } from "./approveTemplateConstants.js"; export function useApproveTemplate() { const stored = loadStoredTemplates(); const allTemplates = ref(stored?.length ? stored : createInitialMockTemplates()); const activeTab = ref("custom"); const builtinTemplates = getBuiltinTemplates(); const searchForm = reactive({ keyword: "", enabledOnly: false, }); const tableLoading = ref(false); const page = reactive({ current: 1, size: 10, total: 0 }); const formDialog = reactive({ visible: false, title: "", mode: "add" }); const form = reactive(createEmptyTemplateForm()); const formRef = ref(); const detailDialog = reactive({ visible: false }); const detailRow = ref({}); const filteredList = computed(() => { let list = [...allTemplates.value]; const kw = (searchForm.keyword || "").trim().toLowerCase(); if (kw) { list = list.filter((r) => { const name = (r.templateName || "").toLowerCase(); const desc = (r.description || "").toLowerCase(); return name.includes(kw) || desc.includes(kw); }); } if (searchForm.enabledOnly) { list = list.filter((r) => r.enabled !== false); } return list.sort((a, b) => (String(a.updateTime) < String(b.updateTime) ? 1 : -1)); }); watch( filteredList, (list) => { page.total = list.length; const maxPage = Math.max(1, Math.ceil(list.length / page.size) || 1); if (page.current > maxPage) page.current = maxPage; }, { immediate: true } ); const tableData = computed(() => { const start = (page.current - 1) * page.size; return filteredList.value.slice(start, start + page.size); }); const formRules = { templateName: [{ required: true, message: "请输入模板名称", trigger: "blur" }], }; const tableColumn = ref([ { label: "模板名称", prop: "templateName", minWidth: 140 }, { label: "说明", prop: "description", minWidth: 160, showOverflowTooltip: true }, { label: "节点数", prop: "flowNodes", width: 80, align: "center", formatData: (v) => (Array.isArray(v) ? v.length : 0), }, { label: "流程概要", prop: "flowNodes", minWidth: 220, showOverflowTooltip: true, formatData: (v) => flowNodesSummary(v), }, { label: "状态", prop: "enabled", width: 90, align: "center", dataType: "tag", formatData: (v) => (v !== false ? "启用" : "停用"), formatType: (v) => (v !== false ? "success" : "info"), }, { label: "更新时间", prop: "updateTime", width: 170 }, { dataType: "action", label: "操作", align: "center", fixed: "right", width: 200, operation: [ { name: "详情", type: "text", clickFun: (row) => openDetail(row) }, { name: "编辑", type: "text", clickFun: (row) => openFormDialog("edit", row) }, { name: "删除", type: "text", clickFun: (row) => removeTemplate(row) }, ], }, ]); function persist() { saveStoredTemplates(allTemplates.value); } function handleQuery() { tableLoading.value = true; page.current = 1; setTimeout(() => { tableLoading.value = false; }, 150); } function resetSearch() { searchForm.keyword = ""; searchForm.enabledOnly = false; handleQuery(); } function pagination({ page: p, limit }) { page.current = p; page.size = limit; } function resetForm(row) { const base = createEmptyTemplateForm(); if (!row) { Object.assign(form, base); return; } Object.assign(form, { ...base, id: row.id, templateName: row.templateName || "", description: row.description || "", enabled: row.enabled !== false, flowNodes: JSON.parse(JSON.stringify(row.flowNodes || [base.flowNodes[0]])), }); } function openFormDialog(mode, row) { formDialog.mode = mode; formDialog.title = mode === "add" ? "新建自定义审批模板" : "编辑自定义审批模板"; resetForm(mode === "edit" ? row : null); formDialog.visible = true; } function openDetail(row) { detailRow.value = { ...row }; detailDialog.visible = true; } function isNameDuplicate(name, excludeId) { const n = (name || "").trim(); return allTemplates.value.some((t) => t.templateName?.trim() === n && t.id !== excludeId); } async function submitForm() { if (!formRef.value) return false; try { await formRef.value.validate(); } catch { return false; } const validated = validateTemplateForm(form); if (!validated.ok) { return { message: validated.message }; } if (isNameDuplicate(validated.name, form.id)) { return { message: "模板名称已存在,请更换名称" }; } const now = dayjs().format("YYYY-MM-DD HH:mm:ss"); if (formDialog.mode === "add") { allTemplates.value.unshift({ id: `tpl_${Date.now()}`, templateName: validated.name, description: (form.description || "").trim(), enabled: form.enabled !== false, createTime: now, updateTime: now, flowNodes: validated.nodes, }); } else { const hit = allTemplates.value.find((t) => t.id === form.id); if (!hit) return { message: "模板不存在或已删除" }; hit.templateName = validated.name; hit.description = (form.description || "").trim(); hit.enabled = form.enabled !== false; hit.flowNodes = validated.nodes; hit.updateTime = now; } persist(); formDialog.visible = false; page.current = 1; return { ok: true }; } async function removeTemplate(row) { try { await ElMessageBox.confirm(`确定删除模板「${row.templateName}」吗?`, "提示", { type: "warning", confirmButtonText: "删除", cancelButtonText: "取消", }); } catch { return; } const idx = allTemplates.value.findIndex((t) => t.id === row.id); if (idx >= 0) { allTemplates.value.splice(idx, 1); persist(); } } function toggleEnabled(row) { const hit = allTemplates.value.find((t) => t.id === row.id); if (!hit) return; hit.enabled = !hit.enabled; hit.updateTime = dayjs().format("YYYY-MM-DD HH:mm:ss"); persist(); } return { Search, activeTab, builtinTemplates, nodeSignModeLabel, flowNodesSummary, searchForm, tableLoading, page, tableData, tableColumn, formDialog, form, formRef, formRules, detailDialog, detailRow, handleQuery, resetSearch, pagination, openFormDialog, openDetail, submitForm, toggleEnabled, }; }