From 69b917fa605be8ccd0984e5c095f24d6476dce95 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 05 六月 2026 00:55:46 +0800
Subject: [PATCH] 1

---
 src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalTemplateBinding.js |  259 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 259 insertions(+), 0 deletions(-)

diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalTemplateBinding.js b/src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalTemplateBinding.js
new file mode 100644
index 0000000..d49ec53
--- /dev/null
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-shared/useApprovalTemplateBinding.js
@@ -0,0 +1,259 @@
+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,
+  getModuleMatchingBusinessTypes,
+  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=浠呮湰绫诲瀷妯℃澘锛泆niversal=闇�鍏堥�夌被鍨�
+ */
+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 matchingBusinessTypes = computed(() => {
+    if (fixedBusinessType != null && fixedBusinessType !== "") return [fixedBusinessType];
+    if (isUniversal) {
+      const t = selectedBusinessType.value;
+      return t != null && t !== "" ? [t] : [];
+    }
+    if (moduleKey) {
+      return getModuleMatchingBusinessTypes(moduleKey, businessTypeOptions.value);
+    }
+    const t = resolvedBusinessType.value;
+    return t != null && t !== "" ? [t] : [];
+  });
+
+  const templateCards = computed(() => {
+    const types = matchingBusinessTypes.value;
+    if (!types.length) return [];
+    return allTemplates.value.filter((card) =>
+      types.some(
+        (t) =>
+          matchBusinessTypeValue(card.businessType, t) ||
+          matchBusinessTypeValue(card.approvalType, t)
+      )
+    );
+  });
+
+  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) {
+    const types =
+      moduleKey && !fixedBusinessType
+        ? getModuleMatchingBusinessTypes(moduleKey, businessTypeOptions.value)
+        : [type];
+    return allTemplates.value.filter((card) =>
+      types.some(
+        (t) =>
+          matchBusinessTypeValue(card.businessType, t) ||
+          matchBusinessTypeValue(card.approvalType, t)
+      )
+    ).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,
+  };
+}

--
Gitblit v1.9.3