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,
|
};
|
}
|