import { getApprovalTemplateDetail, listApprovalTemplate, TEMPLATE_TYPE_CUSTOM, } from "@/api/officeProcessAutomation/approvalTemplate.js"; import { computed, reactive, ref } from "vue"; import { ElMessage } from "element-plus"; import { fetchBusinessTypeOptions, mapEnabledFromApi, unwrapTemplateList, } from "../approve-template/approveTemplateConstants.js"; import { createEmptySubmitForm, mapSubmitTemplateCard, matchBusinessTypeValue, } from "../approve-list/approveListConstants.js"; import { getApprovalModuleConfig, resolveModuleBusinessType, } from "./approvalModuleRegistry.js"; import { buildFormPayloadRules, buildTemplateBindingFromDetail, validateTemplateBinding, } from "./approvalTemplateBindingUtils.js"; /** * 审批模板绑定(业务模块固定类型 / 审批列表通用) * * @param {object} options * @param {string} [options.moduleKey] 业务模块 key,见 approvalModuleRegistry * @param {string|number} [options.businessType] 直接指定类型(优先级高于 moduleKey) * @param {'module'|'universal'} [options.mode] module=仅本类型模板;universal=需先选类型 */ export function useApprovalTemplateBinding(options = {}) { const { moduleKey = null, businessType: fixedBusinessType = null, mode = moduleKey ? "module" : "universal" } = options; const isUniversal = mode === "universal" && !moduleKey && fixedBusinessType == null; const allTemplates = ref([]); const businessTypeOptions = ref([]); const selectedBusinessType = ref(fixedBusinessType ?? ""); const templatesLoading = ref(false); const step = ref(isUniversal ? 1 : 1); const bindingForm = reactive(createEmptySubmitForm("")); const moduleConfig = computed(() => getApprovalModuleConfig(moduleKey)); const resolvedBusinessType = computed(() => { if (fixedBusinessType != null && fixedBusinessType !== "") return fixedBusinessType; if (selectedBusinessType.value != null && selectedBusinessType.value !== "") { return selectedBusinessType.value; } if (moduleKey) { return resolveModuleBusinessType(moduleKey, businessTypeOptions.value); } return ""; }); const templateCards = computed(() => { const type = resolvedBusinessType.value; if (type == null || type === "") return []; return allTemplates.value.filter((card) => matchBusinessTypeValue(card.businessType, type)); }); const activeTemplate = computed(() => bindingForm.templateSnapshot || null); const formFields = computed(() => { const tplFields = activeTemplate.value?.fields; if (tplFields?.length) return tplFields; return bindingForm.formFieldDefs || []; }); const formRules = computed(() => buildFormPayloadRules(formFields.value)); const hasTemplateBound = computed(() => Boolean(activeTemplate.value?.templateId || bindingForm.templateId)); function businessTypeLabel(type) { if (type == null || type === "") return ""; const hit = businessTypeOptions.value.find((x) => matchBusinessTypeValue(x.value, type)); return hit?.label || moduleConfig.value?.label || ""; } const selectedBusinessTypeLabel = computed(() => businessTypeLabel(resolvedBusinessType.value)); function countTemplatesByBusinessType(type) { return allTemplates.value.filter((card) => matchBusinessTypeValue(card.businessType, type)).length; } async function loadTemplates() { templatesLoading.value = true; try { const [typeOptions, customRes] = await Promise.all([ fetchBusinessTypeOptions(), listApprovalTemplate(TEMPLATE_TYPE_CUSTOM), ]); businessTypeOptions.value = typeOptions; allTemplates.value = unwrapTemplateList(customRes) .filter((row) => mapEnabledFromApi(row.enabled)) .map(mapSubmitTemplateCard); if (moduleKey && !fixedBusinessType) { const resolved = resolveModuleBusinessType(moduleKey, typeOptions); if (resolved != null && resolved !== "") selectedBusinessType.value = resolved; } } catch { businessTypeOptions.value = []; allTemplates.value = []; ElMessage.error("加载审批模板失败"); } finally { templatesLoading.value = false; } } function resetBinding() { step.value = isUniversal ? 1 : 1; if (!fixedBusinessType && !moduleKey) selectedBusinessType.value = ""; else if (moduleKey) { selectedBusinessType.value = fixedBusinessType ?? resolveModuleBusinessType(moduleKey, businessTypeOptions.value) ?? ""; } Object.assign(bindingForm, createEmptySubmitForm("")); } function pickBusinessType(type) { if (!countTemplatesByBusinessType(type)) { ElMessage.warning("该类型下暂无可用审批模板"); return; } selectedBusinessType.value = type; step.value = 2; } function backToBusinessTypePick() { selectedBusinessType.value = ""; step.value = 1; } function backToTemplatePick() { step.value = isUniversal ? 2 : 1; } async function pickTemplate(card) { if (!card?.id) return false; templatesLoading.value = true; try { const res = await getApprovalTemplateDetail(card.id); const applied = buildTemplateBindingFromDetail(res); Object.assign(bindingForm, { templateKey: String(card.id), ...applied, }); step.value = isUniversal ? 3 : 2; return true; } catch { ElMessage.error("加载模板详情失败"); return false; } finally { templatesLoading.value = false; } } /** 直接以详情行绑定(编辑回显) */ function applyBindingState(state) { if (!state) return; Object.assign(bindingForm, createEmptySubmitForm(""), state); step.value = isUniversal ? 3 : 2; } async function validateBinding(formRef) { if (formRef?.validate) { try { await formRef.validate(); } catch { return { ok: false }; } } if (!hasTemplateBound.value) { return { ok: false, message: "请选择审批模板" }; } return validateTemplateBinding({ flowNodes: bindingForm.flowNodes }); } function getBindingPayload() { return { templateId: bindingForm.templateId, templateName: bindingForm.templateName, businessType: bindingForm.businessType ?? resolvedBusinessType.value, templateSnapshot: bindingForm.templateSnapshot, formFieldDefs: bindingForm.formFieldDefs, formPayload: bindingForm.formPayload, flowNodes: bindingForm.flowNodes, templateAttachments: bindingForm.templateAttachments, storageBlobDTOs: bindingForm.storageBlobDTOs, }; } return { isUniversal, moduleConfig, step, bindingForm, allTemplates, businessTypeOptions, selectedBusinessType, resolvedBusinessType, selectedBusinessTypeLabel, templateCards, activeTemplate, formFields, formRules, hasTemplateBound, templatesLoading, loadTemplates, resetBinding, pickBusinessType, backToBusinessTypePick, backToTemplatePick, pickTemplate, applyBindingState, validateBinding, getBindingPayload, countTemplatesByBusinessType, businessTypeLabel, }; }