| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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 è§£æå±ç¤ºåæ®µï¼ |
| | | * @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 è§£æ 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, |
| | | }; |
| | | } |