From ab264123941cd3d345687af92aab2a9e04968960 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 27 五月 2026 14:21:35 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' into dev_宁夏_英泽防锈
---
src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalInstanceModule.js | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 408 insertions(+), 0 deletions(-)
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalInstanceModule.js b/src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalInstanceModule.js
new file mode 100644
index 0000000..b474bb2
--- /dev/null
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalInstanceModule.js
@@ -0,0 +1,408 @@
+import {
+ deleteApprovalInstance,
+ listApprovalInstancePage,
+ saveApprovalInstance,
+ updateApprovalInstance,
+} from "@/api/officeProcessAutomation/approvalInstance.js";
+import useUserStore from "@/store/modules/user";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { computed, reactive, ref } from "vue";
+import {
+ applyBindingToForm,
+ buildFormPayloadRules,
+ validateTemplateBinding,
+} from "./approvalTemplateBindingUtils.js";
+import {
+ buildApprovalInstanceListParams,
+ buildEditFormFromInstanceRow,
+ buildInstanceDto,
+ canEditBusinessInstanceRow,
+ createEmptySubmitForm,
+ mapInstanceFromApi,
+ resolveInstanceFormFields,
+ unwrapInstancePage,
+} from "../approve-list/approveListConstants.js";
+import { fetchBusinessTypeOptions } from "../approve-template/approveTemplateConstants.js";
+import {
+ collectOptionSourcesFromFields,
+ fetchSelectOptionCaches,
+} from "../approve-template/selectOptionSource.js";
+import { enrichInstanceRowFromFormConfig } from "./approvalInstanceFormConfigTable.js";
+import {
+ filterInstanceRowsByModuleSearch,
+ hasActiveModuleSearch,
+} from "./approvalInstanceListSearch.js";
+import {
+ getApprovalModuleConfig,
+ getModuleListBusinessType,
+ resolveModuleBusinessType,
+} from "./approvalModuleRegistry.js";
+
+/**
+ * 涓氬姟鐢宠椤靛叡鐢細瀹℃壒瀹炰緥鍒楄〃鏌ヨ銆佹柊澧�/淇敼淇濆瓨銆佽鎯�/缂栬緫寮圭獥锛堜笌瀹℃壒鍒楄〃涓�鑷达級
+ *
+ * @param {object} options
+ * @param {string} options.moduleKey approvalModuleRegistry 涓殑 key
+ * @param {(row: object) => object} [options.enrichListRow] 鍒楄〃琛屽寮猴紙浠� formPayload 瑙f瀽灞曠ず瀛楁锛�
+ * @param {(base: object) => object} [options.buildExtraListParams] 杩藉姞鏌ヨ鍙傛暟
+ * @param {() => void} [options.beforeSave] 淇濆瓨鍓嶉挬瀛愶紙濡傚悓姝ヤ笟鍔″瓧娈靛埌 formPayload锛�
+ * @param {import('vue').ComputedRef|object} [options.extraFormRules] 棰濆琛ㄥ崟鏍¢獙
+ */
+export function useApprovalInstanceModule(options = {}) {
+ const {
+ moduleKey,
+ enrichListRow,
+ buildExtraListParams,
+ beforeSave,
+ extraFormRules,
+ } = options;
+
+ const userStore = useUserStore();
+ const moduleConfig = computed(() => getApprovalModuleConfig(moduleKey));
+ const businessTypeOptions = ref([]);
+
+ /** 鍒楄〃鏌ヨ businessType锛氫紭鍏� registry 鍐欐鏋氫妇锛屽啀鍥為�� TypeEnums */
+ const defaultListBusinessType = computed(() => {
+ const fixed = getModuleListBusinessType(moduleKey);
+ if (fixed != null && fixed !== "") return fixed;
+ const resolved = resolveModuleBusinessType(moduleKey, businessTypeOptions.value);
+ if (resolved != null && resolved !== "") return resolved;
+ return "";
+ });
+
+ async function loadBusinessTypeOptions() {
+ if (businessTypeOptions.value.length) return;
+ try {
+ businessTypeOptions.value = await fetchBusinessTypeOptions();
+ } catch {
+ businessTypeOptions.value = [];
+ }
+ }
+
+ const tableData = ref([]);
+ const tableLoading = ref(false);
+ const page = reactive({ current: 1, size: 10, total: 0 });
+
+ const detailDialog = reactive({ visible: false });
+ const detailRow = ref({});
+
+ const submitDialog = reactive({ visible: false, mode: "add" });
+ const submitEditRow = ref(null);
+ const submitForm = reactive(createEmptySubmitForm(""));
+ const submitFormRef = ref();
+ const submitSaving = ref(false);
+
+ const templateBindVisible = ref(false);
+ const pendingTemplateBinding = ref(null);
+ /** 鏈�杩戜竴娆″垪琛ㄦ煡璇㈡潯浠讹紙淇濆瓨鍚庡埛鏂板垪琛ㄦ椂娌跨敤锛� */
+ let lastListSearchForm = null;
+
+ const isSubmitEdit = computed(() => submitDialog.mode === "edit");
+ const activeTemplate = computed(() => submitForm.templateSnapshot || null);
+ const submitFormFields = computed(() => {
+ const tplFields = activeTemplate.value?.fields;
+ if (tplFields?.length) return tplFields;
+ return submitForm.formFieldDefs || [];
+ });
+
+ const submitFormRules = computed(() => ({
+ ...buildFormPayloadRules(submitFormFields.value),
+ ...(extraFormRules?.value ?? extraFormRules ?? {}),
+ }));
+
+ const submitDialogTitle = computed(() => {
+ const label = moduleConfig.value?.label || "鐢宠";
+ if (submitDialog.mode === "edit") {
+ return `淇敼${activeTemplate.value?.label || submitForm.templateName || label}`;
+ }
+ return `鏂板${label}`;
+ });
+
+ function mapListRow(row, caches) {
+ const mapped = mapInstanceFromApi(row);
+ const fromFormConfig = enrichInstanceRowFromFormConfig(mapped, caches);
+ return enrichListRow ? enrichListRow(fromFormConfig) : fromFormConfig;
+ }
+
+ async function fetchList(searchForm = {}) {
+ await loadBusinessTypeOptions();
+ tableLoading.value = true;
+ try {
+ let extraParams = {};
+ if (buildExtraListParams) {
+ extraParams = buildExtraListParams(searchForm) || {};
+ }
+ const res = await listApprovalInstancePage(
+ buildApprovalInstanceListParams({
+ page,
+ searchForm,
+ businessType: defaultListBusinessType.value,
+ extraParams,
+ })
+ );
+ const { records, total } = unwrapInstancePage(res);
+ const mapped = records.map(mapInstanceFromApi);
+ const allFields = [];
+ for (const row of mapped) {
+ const { fields } = resolveInstanceFormFields(row);
+ allFields.push(...fields);
+ }
+ const caches = await fetchSelectOptionCaches(
+ collectOptionSourcesFromFields(allFields)
+ );
+ let rows = mapped.map((row) => mapListRow(row, caches));
+ if (hasActiveModuleSearch(moduleKey, searchForm)) {
+ rows = filterInstanceRowsByModuleSearch(moduleKey, rows, searchForm);
+ }
+ tableData.value = rows;
+ page.total = hasActiveModuleSearch(moduleKey, searchForm)
+ ? rows.length
+ : total;
+ } catch {
+ tableData.value = [];
+ page.total = 0;
+ ElMessage.error(`${moduleConfig.value?.label || "鐢宠"}鍒楄〃鍔犺浇澶辫触`);
+ } finally {
+ tableLoading.value = false;
+ }
+ }
+
+ function handleQuery(searchForm) {
+ lastListSearchForm = searchForm;
+ page.current = 1;
+ return fetchList(searchForm);
+ }
+
+ /** 杩涘叆椤甸潰锛氬厛鎷� TypeEnums 瑙f瀽 businessType锛屽啀鏌ュ垪琛� */
+ async function initModuleList(searchForm) {
+ await loadBusinessTypeOptions();
+ return handleQuery(searchForm);
+ }
+
+ function pagination({ page: p, limit }, searchForm) {
+ page.current = p;
+ page.size = limit;
+ return fetchList(searchForm);
+ }
+
+ function openDetail(row) {
+ detailRow.value = { ...row };
+ detailDialog.visible = true;
+ }
+
+ function openEdit(row) {
+ if (!canEditBusinessInstanceRow(row)) {
+ ElMessage.warning("杩涜涓垨宸插畬鎴愮殑瀹℃壒涓嶅彲淇敼");
+ return;
+ }
+ if (!row?.id) {
+ ElMessage.warning("鏃犳硶淇敼锛氱己灏戝鎵瑰疄渚� ID");
+ return;
+ }
+ submitDialog.mode = "edit";
+ submitEditRow.value = { ...row };
+ Object.assign(submitForm, buildEditFormFromInstanceRow(row));
+ submitDialog.visible = true;
+ }
+
+ function openEditFromDetail() {
+ const row = detailRow.value;
+ detailDialog.visible = false;
+ openEdit(row);
+ }
+
+ function resetSubmitForm() {
+ Object.assign(submitForm, createEmptySubmitForm(""));
+ submitEditRow.value = null;
+ }
+
+ function openAddWithTemplate() {
+ submitDialog.visible = false;
+ pendingTemplateBinding.value = null;
+ templateBindVisible.value = true;
+ }
+
+ function onTemplateBound(binding) {
+ pendingTemplateBinding.value = binding;
+ }
+
+ function onTemplateBindClosed() {
+ const binding = pendingTemplateBinding.value;
+ if (!binding) return;
+ pendingTemplateBinding.value = null;
+ openAddFromBinding(binding);
+ }
+
+ function openAddFromBinding(binding) {
+ resetSubmitForm();
+ applyBindingToForm(submitForm, binding);
+ submitDialog.mode = "add";
+ submitEditRow.value = null;
+ submitDialog.visible = true;
+ }
+
+ function closeSubmitDialog() {
+ submitDialog.visible = false;
+ }
+
+ async function submitInstanceForm(options = {}) {
+ const { skipValidate = false } = options;
+ if (!skipValidate) {
+ if (!submitFormRef.value?.validate) {
+ ElMessage.warning("琛ㄥ崟鏈氨缁紝璇峰叧闂脊绐楀悗閲嶈瘯");
+ return false;
+ }
+ try {
+ await submitFormRef.value.validate();
+ } catch {
+ ElMessage.warning("璇峰畬鍠勮〃鍗曞繀濉」鍚庡啀淇濆瓨");
+ return false;
+ }
+ }
+ if (!activeTemplate.value) {
+ ElMessage.warning("鏈姞杞藉鎵规ā鏉匡紝鏃犳硶淇濆瓨");
+ return false;
+ }
+ const bindingCheck = validateTemplateBinding({ flowNodes: submitForm.flowNodes });
+ if (!bindingCheck.ok) {
+ ElMessage.warning(bindingCheck.message);
+ return false;
+ }
+ if (!submitForm.templateId) {
+ ElMessage.warning("缂哄皯妯℃澘 ID锛屾棤娉曟彁浜�");
+ return false;
+ }
+ if (beforeSave) {
+ try {
+ await beforeSave(submitForm, { isEdit: isSubmitEdit.value, editRow: submitEditRow.value });
+ } catch {
+ return false;
+ }
+ }
+ if (submitSaving.value) return false;
+ submitSaving.value = true;
+ try {
+ const dto = buildInstanceDto({
+ submitForm,
+ activeTemplate: activeTemplate.value,
+ userStore,
+ flowNodes: bindingCheck.nodes,
+ existingRow: isSubmitEdit.value ? submitEditRow.value : null,
+ });
+ if (isSubmitEdit.value) {
+ await updateApprovalInstance(dto);
+ } else {
+ await saveApprovalInstance(dto);
+ }
+ submitDialog.visible = false;
+ if (!isSubmitEdit.value) page.current = 1;
+ await fetchList(lastListSearchForm ?? {});
+ 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 {
+ ElMessage.error(isSubmitEdit.value ? "淇濆瓨澶辫触" : "鎻愪氦澶辫触");
+ 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 (submitDialog.visible && submitEditRow.value?.id === row.id) {
+ submitDialog.visible = false;
+ }
+ await fetchList(lastListSearchForm ?? {});
+ } catch {
+ /* 閿欒鐢辨嫤鎴櫒鎻愮ず */
+ }
+ }
+
+ /** 鏋勫缓鏍囧噯鎿嶄綔鍒楋細璇︽儏銆佷慨鏀广�佸垹闄わ紙涓庡鎵瑰垪琛ㄤ竴鑷达級 */
+ function buildTableActions(extraOperations = []) {
+ return [
+ { name: "璇︽儏", type: "text", clickFun: (row) => openDetail(row) },
+ {
+ name: "淇敼",
+ type: "text",
+ disabled: (row) => !canEditBusinessInstanceRow(row),
+ clickFun: (row) => openEdit(row),
+ },
+ {
+ name: "鍒犻櫎",
+ type: "danger",
+ clickFun: (row) => removeInstance(row),
+ },
+ ...extraOperations,
+ ];
+ }
+
+ return {
+ moduleConfig,
+ defaultListBusinessType,
+ tableData,
+ tableLoading,
+ page,
+ detailDialog,
+ detailRow,
+ submitDialog,
+ submitEditRow,
+ submitForm,
+ submitFormRef,
+ submitSaving,
+ isSubmitEdit,
+ activeTemplate,
+ submitFormFields,
+ submitFormRules,
+ submitDialogTitle,
+ templateBindVisible,
+ pendingTemplateBinding,
+ fetchList,
+ handleQuery,
+ initModuleList,
+ pagination,
+ openDetail,
+ openEdit,
+ openEditFromDetail,
+ openAddWithTemplate,
+ onTemplateBound,
+ onTemplateBindClosed,
+ openAddFromBinding,
+ closeSubmitDialog,
+ resetSubmitForm,
+ submitInstanceForm,
+ removeInstance,
+ buildTableActions,
+ loadBusinessTypeOptions,
+ canEditBusinessInstanceRow,
+ };
+}
--
Gitblit v1.9.3