From 930d38ed2a3c2131be3305a585602c7a5a275fe3 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期二, 19 五月 2026 17:09:12 +0800
Subject: [PATCH] Merge branch 'dev-new_pro_OA' of http://114.132.189.42:9002/r/product-inventory-management into dev-new_pro_OA
---
src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js | 475 ++++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 308 insertions(+), 167 deletions(-)
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js b/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
index c3c3241..337b00d 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-list/useApproveList.js
@@ -1,57 +1,52 @@
-import { Search } from "@element-plus/icons-vue";
-import dayjs from "dayjs";
+import {
+ getApprovalTemplateDetail,
+ listApprovalTemplate,
+ TEMPLATE_TYPE_BUILTIN,
+ TEMPLATE_TYPE_CUSTOM,
+} from "@/api/officeProcessAutomation/approvalTemplate.js";
+import {
+ approveApprovalInstance,
+ deleteApprovalInstance,
+ listApprovalInstancePage,
+ saveApprovalInstance,
+ updateApprovalInstance,
+} from "@/api/officeProcessAutomation/approvalInstance.js";
import useUserStore from "@/store/modules/user";
-import { computed, reactive, ref, watch } from "vue";
+import { Search } from "@element-plus/icons-vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { computed, reactive, ref } from "vue";
+import {
+ formatDisplayTime,
+ mapEnabledFromApi,
+ mapTemplateFromApi,
+ unwrapTemplateDetail,
+ unwrapTemplateList,
+} from "../approve-template/approveTemplateConstants.js";
+import { buildSubmitTemplateFromRow } from "../approve-template/formConfigUtils.js";
import {
APPROVAL_TYPE_OPTIONS,
- SUBMIT_TEMPLATES,
- approvalModeLabel,
approvalStatusLabel,
approvalStatusTagType,
approvalTypeLabel,
+ buildApprovalInstanceListParams,
+ buildApproveInstanceDto,
+ buildEditFormFromInstanceRow,
+ buildInstanceDto,
+ clearLegacyApproveListStorage,
createEmptySubmitForm,
- createInitialMockRows,
- loadStoredRows,
- saveStoredRows,
- buildDefaultFlowNodes,
+ mapInstanceFromApi,
+ mapSubmitTemplateCard,
+ validateSubmitFlowNodes,
+ unwrapInstancePage,
} from "./approveListConstants.js";
-import { buildSubmitTemplateFromRow } from "../approve-template/formConfigUtils.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() {
+ clearLegacyApproveListStorage();
const userStore = useUserStore();
- const stored = loadStoredRows();
- const allRows = ref(stored?.length ? stored : createInitialMockRows());
+
+ const tableData = ref([]);
+ const submitTemplateCards = ref([]);
+ const submitTemplatesLoading = ref(false);
const searchForm = reactive({
approvalType: "",
@@ -67,59 +62,37 @@
const approveDialog = reactive({ visible: false, row: null });
const approveOpinion = ref("");
+ const approveSubmitting = ref(false);
- const submitDialog = reactive({ visible: false, step: 1 });
+ const submitDialog = reactive({ visible: false, step: 1, mode: "add" });
+ const submitEditRow = ref(null);
const submitForm = reactive(createEmptySubmitForm(""));
const submitFormRef = ref();
+ const submitSaving = ref(false);
- const filteredList = computed(() => {
- let list = [...allRows.value];
- if (searchForm.approvalType) {
- list = list.filter((r) => r.approvalType === searchForm.approvalType);
+ const isSubmitEdit = computed(() => submitDialog.mode === "edit");
+ const submitDialogTitle = computed(() => {
+ if (submitDialog.mode === "edit") {
+ return `淇敼${activeTemplate.value?.label || submitForm.templateName || "瀹℃壒"}`;
}
- 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));
+ if (submitDialog.step === 1) return "閫夋嫨瀹℃壒妯℃澘";
+ return `鎻愪氦${activeTemplate.value?.label || "瀹℃壒"}`;
});
- 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 activeTemplate = computed(() => submitForm.templateSnapshot || null);
- const tableData = computed(() => {
- const start = (page.current - 1) * page.size;
- return filteredList.value.slice(start, start + page.size);
+ /** 濉姤椤瑰畾涔夛紙鏂板/淇敼涓� formConfig 涓�鑷达級 */
+ const submitFormFields = computed(() => {
+ const tplFields = activeTemplate.value?.fields;
+ if (tplFields?.length) return tplFields;
+ return submitForm.formFieldDefs || [];
});
-
- const activeTemplate = computed(
- () => submitForm.templateSnapshot || SUBMIT_TEMPLATES[submitForm.templateKey] || null
- );
const submitFormRules = computed(() => {
const rules = {
templateKey: [{ required: true, message: "璇烽�夋嫨瀹℃壒绫诲瀷", trigger: "change" }],
};
- (activeTemplate.value?.fields || []).forEach((f) => {
+ submitFormFields.value.forEach((f) => {
if (!f.required) return;
if (f.type === "number") {
rules[`formPayload.${f.key}`] = [{ required: true, message: `璇峰~鍐�${f.label}`, trigger: "blur" }];
@@ -135,6 +108,7 @@
const tableColumn = ref([
{ label: "鐢宠浜虹紪鍙�", prop: "applicantNo", width: 110 },
{ label: "鐢宠浜哄悕绉�", prop: "applicantName", minWidth: 100 },
+ { label: "涓氬姟绫诲瀷", prop: "businessName", minWidth: 120 },
{
label: "瀹℃壒绫诲瀷",
prop: "approvalType",
@@ -143,14 +117,7 @@
slot: "approveType",
},
{
- label: "瀹℃壒鏂瑰紡",
- prop: "approvalMode",
- width: 90,
- dataType: "slot",
- slot: "approvalMethod",
- },
- {
- label: "鏄惁鏈",
+ label: "寰呮垜瀹℃壒",
prop: "unread",
width: 90,
align: "center",
@@ -164,35 +131,82 @@
formatData: (v) => approvalStatusLabel(v),
formatType: (v) => approvalStatusTagType(v),
},
- { label: "鍒涘缓鏃堕棿", prop: "createTime", width: 170 },
+ {
+ label: "鍒涘缓鏃堕棿",
+ prop: "createTime",
+ width: 170,
+ formatData: (v) => formatDisplayTime(v),
+ },
{
dataType: "action",
label: "鎿嶄綔",
align: "center",
fixed: "right",
- width: 160,
+ width: 240,
operation: [
{ name: "璇︽儏", type: "text", clickFun: (row) => openDetail(row) },
{
- name: "瀹℃壒",
+ name: "淇敼",
type: "text",
disabled: (row) => row.approvalStatus !== "pending",
+ clickFun: (row) => openEditDialog(row),
+ },
+ {
+ name: "瀹℃壒",
+ type: "text",
+ disabled: (row) => row.approvalStatus !== "pending" || !row.isApprove,
clickFun: (row) => openApprove(row),
+ },
+ {
+ name: "鍒犻櫎",
+ type: "danger",
+ clickFun: (row) => removeInstance(row),
},
],
},
]);
- function persist() {
- saveStoredRows(allRows.value);
+ async function fetchApprovalList() {
+ tableLoading.value = true;
+ try {
+ const res = await listApprovalInstancePage(
+ buildApprovalInstanceListParams({ page, searchForm })
+ );
+ const { records, total } = unwrapInstancePage(res);
+ tableData.value = records.map(mapInstanceFromApi);
+ page.total = total;
+ } catch {
+ tableData.value = [];
+ page.total = 0;
+ ElMessage.error("瀹℃壒鍒楄〃鍔犺浇澶辫触");
+ } finally {
+ tableLoading.value = false;
+ }
+ }
+
+ async function loadSubmitTemplates() {
+ submitTemplatesLoading.value = true;
+ try {
+ const [builtinRes, customRes] = await Promise.all([
+ listApprovalTemplate(TEMPLATE_TYPE_BUILTIN),
+ listApprovalTemplate(TEMPLATE_TYPE_CUSTOM),
+ ]);
+ const merged = [
+ ...unwrapTemplateList(builtinRes),
+ ...unwrapTemplateList(customRes),
+ ].filter((row) => mapEnabledFromApi(row.enabled));
+ submitTemplateCards.value = merged.map(mapSubmitTemplateCard);
+ } catch {
+ submitTemplateCards.value = [];
+ ElMessage.error("鍔犺浇瀹℃壒妯℃澘澶辫触");
+ } finally {
+ submitTemplatesLoading.value = false;
+ }
}
function handleQuery() {
- tableLoading.value = true;
page.current = 1;
- setTimeout(() => {
- tableLoading.value = false;
- }, 200);
+ fetchApprovalList();
}
function resetSearch() {
@@ -205,50 +219,81 @@
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();
- }
+ fetchApprovalList();
}
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(""));
+ function resetSubmitDialogState() {
+ submitDialog.mode = "add";
submitDialog.step = 1;
+ submitEditRow.value = null;
+ Object.assign(submitForm, createEmptySubmitForm(""));
+ }
+
+ function openSubmitDialog() {
+ resetSubmitDialogState();
+ submitDialog.visible = true;
+ loadSubmitTemplates();
+ }
+
+ function openEditDialog(row) {
+ if (row?.approvalStatus !== "pending") {
+ ElMessage.warning("浠呭鏍镐腑鐨勫鎵瑰彲淇敼");
+ return;
+ }
+ if (!row?.id) {
+ ElMessage.warning("鏃犳硶淇敼锛氱己灏戝鎵瑰疄渚� ID");
+ return;
+ }
+ submitDialog.mode = "edit";
+ submitDialog.step = 2;
+ submitEditRow.value = { ...row };
+ Object.assign(submitForm, buildEditFormFromInstanceRow(row));
submitDialog.visible = true;
}
- /** @param {string} key 鍐呯疆妯℃澘 key 鎴栬嚜瀹氫箟 id */
- function onTemplatePick(key, templateRow) {
- const base = templateRow
- ? createEmptySubmitForm(key, buildSubmitTemplateFromRow(templateRow))
- : createEmptySubmitForm(key);
- Object.assign(submitForm, {
- ...base,
- templateSnapshot: templateRow ? buildSubmitTemplateFromRow(templateRow) : null,
- });
- submitDialog.step = 2;
+ async function onTemplatePick(card) {
+ if (!card?.id) return;
+ submitTemplatesLoading.value = true;
+ try {
+ const res = await getApprovalTemplateDetail(card.id);
+ const mapped = mapTemplateFromApi(unwrapTemplateDetail(res));
+ const tpl = {
+ ...buildSubmitTemplateFromRow(mapped),
+ templateId: mapped.id,
+ };
+ const base = createEmptySubmitForm(String(card.id), tpl, mapped.flowNodes);
+ Object.assign(submitForm, {
+ ...base,
+ templateName: mapped.templateName || tpl.label || "",
+ templateSnapshot: tpl,
+ formFieldDefs: tpl.fields || [],
+ });
+ submitDialog.step = 2;
+ } catch {
+ ElMessage.error("鍔犺浇妯℃澘璇︽儏澶辫触");
+ } finally {
+ submitTemplatesLoading.value = false;
+ }
}
function backToTemplatePick() {
submitDialog.step = 1;
+ }
+
+ async function submitInstanceForm() {
+ if (submitDialog.mode === "edit") return submitEditApproval();
+ return submitNewApproval();
}
async function submitNewApproval() {
@@ -258,56 +303,143 @@
} 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;
+ if (!activeTemplate.value) return false;
+ const flowCheck = validateSubmitFlowNodes(submitForm.flowNodes);
+ if (!flowCheck.ok) {
+ ElMessage.warning(flowCheck.message);
+ return false;
+ }
+ if (!submitForm.templateId) {
+ ElMessage.warning("缂哄皯妯℃澘 ID锛屾棤娉曟彁浜�");
+ return false;
+ }
+ if (submitSaving.value) return false;
+ submitSaving.value = true;
+ try {
+ await saveApprovalInstance(
+ buildInstanceDto({
+ submitForm,
+ activeTemplate: activeTemplate.value,
+ userStore,
+ flowNodes: flowCheck.nodes,
+ })
+ );
+ submitDialog.visible = false;
+ page.current = 1;
+ await fetchApprovalList();
+ return true;
+ } catch {
+ return false;
+ } finally {
+ submitSaving.value = false;
+ }
}
- function submitApprove(result) {
+ async function submitEditApproval() {
+ if (!submitFormRef.value) return false;
+ try {
+ await submitFormRef.value.validate();
+ } catch {
+ return false;
+ }
+ if (!activeTemplate.value) return false;
+ const flowCheck = validateSubmitFlowNodes(submitForm.flowNodes);
+ if (!flowCheck.ok) {
+ ElMessage.warning(flowCheck.message);
+ return false;
+ }
+ if (!submitForm.instanceId) {
+ ElMessage.warning("缂哄皯瀹℃壒瀹炰緥 ID锛屾棤娉曚繚瀛�");
+ return false;
+ }
+ if (submitSaving.value) return false;
+ submitSaving.value = true;
+ try {
+ await updateApprovalInstance(
+ buildInstanceDto({
+ submitForm,
+ activeTemplate: activeTemplate.value,
+ flowNodes: flowCheck.nodes,
+ existingRow: submitEditRow.value,
+ })
+ );
+ submitDialog.visible = false;
+ await fetchApprovalList();
+ if (detailDialog.visible && detailRow.value?.id === submitForm.instanceId) {
+ const hit = tableData.value.find((r) => r.id === submitForm.instanceId);
+ if (hit) detailRow.value = { ...hit };
+ else detailDialog.visible = false;
+ }
+ return true;
+ } catch {
+ return false;
+ } finally {
+ submitSaving.value = false;
+ }
+ }
+
+ async function removeInstance(row) {
+ if (row?.id == null || row.id === "") {
+ ElMessage.warning("鏃犳硶鍒犻櫎锛氱己灏戝鎵瑰疄渚� ID");
+ return;
+ }
+ const title = row.title || row.templateName || row.instanceNo || "璇ュ鎵�";
+ try {
+ await ElMessageBox.confirm(
+ `纭畾瑕佸垹闄ゅ鎵广��${title}銆嶅悧锛熷垹闄ゅ悗涓嶅彲鎭㈠銆俙,
+ "鍒犻櫎纭",
+ {
+ type: "warning",
+ confirmButtonText: "纭畾鍒犻櫎",
+ cancelButtonText: "鍙栨秷",
+ distinguishCancelAndClose: true,
+ autofocus: false,
+ }
+ );
+ } catch {
+ return;
+ }
+ try {
+ await deleteApprovalInstance([row.id]);
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ if (detailDialog.visible && detailRow.value?.id === row.id) {
+ detailDialog.visible = false;
+ }
+ if (approveDialog.visible && approveDialog.row?.id === row.id) {
+ approveDialog.visible = false;
+ }
+ await fetchApprovalList();
+ } catch {
+ /* 閿欒鐢辨嫤鎴櫒鎻愮ず */
+ }
+ }
+
+ async 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 (!row?.id) return { ok: false };
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 };
+ if (approveSubmitting.value) return { ok: false };
+ approveSubmitting.value = true;
+ try {
+ await approveApprovalInstance(
+ buildApproveInstanceDto(row, result, approveOpinion.value)
+ );
+ approveDialog.visible = false;
+ await fetchApprovalList();
+ if (detailDialog.visible && detailRow.value?.id === row.id) {
+ const hit = tableData.value.find((r) => r.id === row.id);
+ if (hit) detailRow.value = { ...hit };
+ else detailDialog.visible = false;
+ }
+ return { ok: true, result };
+ } catch {
+ ElMessage.error("瀹℃壒鎿嶄綔澶辫触");
+ return { ok: false };
+ } finally {
+ approveSubmitting.value = false;
}
- return { ok: true };
}
function approvalActionLabel(result) {
@@ -319,9 +451,7 @@
return {
Search,
APPROVAL_TYPE_OPTIONS,
- SUBMIT_TEMPLATES,
approvalTypeLabel,
- approvalModeLabel,
approvalStatusLabel,
approvalStatusTagType,
approvalActionLabel,
@@ -334,20 +464,31 @@
detailRow,
approveDialog,
approveOpinion,
+ approveSubmitting,
submitDialog,
+ isSubmitEdit,
+ submitDialogTitle,
submitForm,
submitFormRef,
+ submitSaving,
activeTemplate,
+ submitFormFields,
submitFormRules,
+ submitTemplateCards,
+ submitTemplatesLoading,
handleQuery,
resetSearch,
pagination,
+ resetSubmitDialogState,
openSubmitDialog,
+ openEditDialog,
onTemplatePick,
backToTemplatePick,
+ submitInstanceForm,
submitNewApproval,
submitApprove,
openDetail,
openApprove,
+ fetchApprovalList,
};
}
--
Gitblit v1.9.3