1
yyb
14 小时以前 69b917fa605be8ccd0984e5c095f24d6476dce95
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=仅本类型模板;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 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,
  };
}