import { Search } from "@element-plus/icons-vue"; import dayjs from "dayjs"; import useUserStore from "@/store/modules/user"; import { computed, reactive, ref, watch } from "vue"; import { APPROVAL_TYPE_OPTIONS, SUBMIT_TEMPLATES, approvalModeLabel, approvalStatusLabel, approvalStatusTagType, approvalTypeLabel, createEmptySubmitForm, createInitialMockRows, loadStoredRows, saveStoredRows, buildDefaultFlowNodes, } from "./approveListConstants.js"; function advanceFlow(row, result, opinion) { const nodes = row.approvalFlowNodes || []; const idx = row.currentNodeIndex ?? 0; const node = nodes[idx]; if (!node) return; node.nodeStatus = result === "approved" ? "finish" : "error"; node.approveOpinion = opinion || (result === "approved" ? "同意" : "驳回"); node.approveTime = dayjs().format("YYYY-MM-DD HH:mm:ss"); row.approvalRecords = row.approvalRecords || []; row.approvalRecords.push({ operatorName: node.approverName || "审批人", result, opinion: node.approveOpinion, time: node.approveTime, }); if (result === "rejected") { row.approvalStatus = "rejected"; row.rejectReason = opinion || node.approveOpinion; return; } const next = idx + 1; if (next < nodes.length) { row.currentNodeIndex = next; nodes[next].nodeStatus = "process"; row.approvalStatus = "pending"; } else { row.approvalStatus = "approved"; row.rejectReason = ""; } } export function useApproveList() { const userStore = useUserStore(); const stored = loadStoredRows(); const allRows = ref(stored?.length ? stored : createInitialMockRows()); const searchForm = reactive({ approvalType: "", applicantKeyword: "", createTimeRange: [], }); const tableLoading = ref(false); const page = reactive({ current: 1, size: 10, total: 0 }); const detailDialog = reactive({ visible: false }); const detailRow = ref({}); const approveDialog = reactive({ visible: false, row: null }); const approveOpinion = ref(""); const submitDialog = reactive({ visible: false, step: 1 }); const submitForm = reactive(createEmptySubmitForm("")); const submitFormRef = ref(); const filteredList = computed(() => { let list = [...allRows.value]; if (searchForm.approvalType) { list = list.filter((r) => r.approvalType === searchForm.approvalType); } const kw = (searchForm.applicantKeyword || "").trim().toLowerCase(); if (kw) { list = list.filter((r) => { const name = (r.applicantName || "").toLowerCase(); const no = (r.applicantNo || "").toLowerCase(); return name.includes(kw) || no.includes(kw); }); } const range = searchForm.createTimeRange; if (range?.length === 2) { const [from, to] = range; list = list.filter((r) => { const t = (r.createTime || "").slice(0, 10); return t && t >= from && t <= to; }); } return list.sort((a, b) => (String(a.createTime) < String(b.createTime) ? 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 activeTemplate = computed(() => SUBMIT_TEMPLATES[submitForm.templateKey] || null); const submitFormRules = computed(() => { const rules = { templateKey: [{ required: true, message: "请选择审批类型", trigger: "change" }], }; (activeTemplate.value?.fields || []).forEach((f) => { if (!f.required) return; if (f.type === "number") { rules[`formPayload.${f.key}`] = [{ required: true, message: `请填写${f.label}`, trigger: "blur" }]; } else if (f.type === "datetimerange") { rules[`formPayload.${f.key}`] = [{ required: true, message: `请选择${f.label}`, trigger: "change" }]; } else { rules[`formPayload.${f.key}`] = [{ required: true, message: `请填写${f.label}`, trigger: "blur" }]; } }); return rules; }); const tableColumn = ref([ { label: "申请人编号", prop: "applicantNo", width: 110 }, { label: "申请人名称", prop: "applicantName", minWidth: 100 }, { label: "审批类型", prop: "approvalType", minWidth: 140, dataType: "slot", slot: "approveType", }, { label: "审批方式", prop: "approvalMode", width: 90, dataType: "slot", slot: "approvalMethod", }, { label: "是否未读", prop: "unread", width: 90, align: "center", formatData: (v) => (v ? "是" : "否"), }, { label: "审批状态", prop: "approvalStatus", width: 100, dataType: "tag", formatData: (v) => approvalStatusLabel(v), formatType: (v) => approvalStatusTagType(v), }, { label: "创建时间", prop: "createTime", width: 170 }, { dataType: "action", label: "操作", align: "center", fixed: "right", width: 160, operation: [ { name: "详情", type: "text", clickFun: (row) => openDetail(row) }, { name: "审批", type: "text", disabled: (row) => row.approvalStatus !== "pending", clickFun: (row) => openApprove(row), }, ], }, ]); function persist() { saveStoredRows(allRows.value); } function handleQuery() { tableLoading.value = true; page.current = 1; setTimeout(() => { tableLoading.value = false; }, 200); } function resetSearch() { searchForm.approvalType = ""; searchForm.applicantKeyword = ""; searchForm.createTimeRange = []; handleQuery(); } function pagination({ page: p, limit }) { page.current = p; page.size = limit; } function markRead(row) { if (!row.unread) return; const hit = allRows.value.find((r) => r.id === row.id); if (hit) { hit.unread = false; persist(); } } function openDetail(row) { markRead(row); detailRow.value = { ...row }; detailDialog.visible = true; } function openApprove(row) { markRead(row); approveDialog.row = { ...row }; approveOpinion.value = ""; approveDialog.visible = true; } function openSubmitDialog() { Object.assign(submitForm, createEmptySubmitForm("")); submitDialog.step = 1; submitDialog.visible = true; } function onTemplatePick(key) { Object.assign(submitForm, createEmptySubmitForm(key)); submitDialog.step = 2; } function backToTemplatePick() { submitDialog.step = 1; } async function submitNewApproval() { if (!submitFormRef.value) return false; try { await submitFormRef.value.validate(); } catch { return false; } const tpl = activeTemplate.value; if (!tpl) return false; const id = `user_${Date.now()}`; const summary = submitForm.formPayload.summary || submitForm.formPayload.handoverTo || `${tpl.label}申请`; const row = { id, bizId: `BIZ${dayjs().format("YYYYMMDDHHmmss")}`, applicantNo: userStore.name || String(userStore.id || "当前用户"), applicantName: userStore.nickName || userStore.name || "当前用户", approvalType: tpl.approvalType, approvalMode: submitForm.approvalMode, unread: false, approvalStatus: "pending", createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), summary, formPayload: { ...submitForm.formPayload }, approvalFlowNodes: (submitForm.approvalFlowNodes?.length ? submitForm.approvalFlowNodes : buildDefaultFlowNodes() ).map((n, i) => ({ ...n, nodeStatus: i === 0 ? "process" : n.nodeStatus || "wait" })), currentNodeIndex: 0, approvalRecords: [], rejectReason: "", }; allRows.value.unshift(row); persist(); submitDialog.visible = false; page.current = 1; return true; } function submitApprove(result) { const row = approveDialog.row; if (!row) return; const hit = allRows.value.find((r) => r.id === row.id); if (!hit || hit.approvalStatus !== "pending") return; if (result === "rejected" && !(approveOpinion.value || "").trim()) { return { needOpinion: true }; } advanceFlow(hit, result, (approveOpinion.value || "").trim()); hit.unread = false; persist(); approveDialog.visible = false; if (detailDialog.visible && detailRow.value?.id === hit.id) { detailRow.value = { ...hit }; } return { ok: true }; } function approvalActionLabel(result) { if (result === "approved") return "通过"; if (result === "rejected") return "驳回"; return "待处理"; } return { Search, APPROVAL_TYPE_OPTIONS, SUBMIT_TEMPLATES, approvalTypeLabel, approvalModeLabel, approvalStatusLabel, approvalStatusTagType, approvalActionLabel, searchForm, tableLoading, page, tableData, tableColumn, detailDialog, detailRow, approveDialog, approveOpinion, submitDialog, submitForm, submitFormRef, activeTemplate, submitFormRules, handleQuery, resetSearch, pagination, openSubmitDialog, onTemplatePick, backToTemplatePick, submitNewApproval, submitApprove, openDetail, openApprove, }; }