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,
|
};
|
}
|