import { getDictionary } from '@/api/system/dictbiz'; import { hasMkProcessInstance, processDelete, processSubmit } from '@/api/system/business-process'; import { ElMessage } from 'element-plus'; export const MK_BIZ = { 'customer-archive': { dictName: '提交客商审核流', subjectPrefix: '客商准入审批', rejected: ['rejected'], approved: ['approved'], }, 'project-apply': { dictName: '提交项目审核流', subjectPrefix: '项目审批', rejected: ['rejected', 'change_rejected', 'withdrawn'], approved: ['approved', 'change_approved'], }, 'project-change': { dictName: '提交项目变更审核流', subjectPrefix: '项目变更审批', rejected: ['rejected', 'withdrawn'], approved: ['approved'], }, /** 项目备案流程(本部/运输部)共用 */ 'project-record-change': { dictName: '提交项目备案审核流', subjectPrefix: '项目备案审批', rejected: ['rejected', 'withdrawn'], approved: ['approved'], }, 'temporary-credit-limit': { dictName: '提交临时额度审核流', subjectPrefix: '临时额度审批', rejected: ['rejected', 'withdrawn'], approved: ['approved'], }, 'contract-manage': { dictName: '提交合同审核流', subjectPrefix: '合同审批', rejected: ['rejected', 'change_rejected', 'withdrawn'], approved: ['approved', 'change_approved'], }, 'contract-change': { dictName: '提交合同变更审核流', subjectPrefix: '合同变更审批', rejected: ['rejected', 'withdrawn'], approved: ['approved'], }, 'pre-settlement': { dictName: '提交预结算审核流', subjectPrefix: '预付结算审批', rejected: ['returned'], approved: ['approved'], }, 'formal-settlement': { dictName: '提交正式结算审核流', subjectPrefix: '正式结算审批', rejected: ['returned'], approved: ['approved'], }, 'payment-application': { dictName: '提交付款审核流', subjectPrefix: '付款审批', rejected: ['returned'], approved: ['approved'], }, 'invoice-application': { dictName: '提交开票审核流', subjectPrefix: '开票审批', rejected: ['returned'], approved: ['approved'], }, 'invoice-receipt': { dictName: '提交收票审核流', subjectPrefix: '收票审批', rejected: ['returned'], approved: ['approved'], }, 'bill-payment': { dictName: '提交汇票付款审核流', subjectPrefix: '汇票付款审批', rejected: ['returned'], approved: ['approved'], }, 'cert-audit-driver': { dictName: '提交司机审核流', subjectPrefix: '司机认证审批', // 认证记录 status:0审核中 1已通过 2已驳回 rejected: ['2'], approved: ['1'], }, 'cert-audit-vehicle': { dictName: '提交车辆审核流', subjectPrefix: '车辆认证审批', rejected: ['2'], approved: ['1'], }, }; /** 按认证对象类型解析 MK 业务类型 */ export function resolveCertAuditMkBizType(bizType) { return String(bizType || '') === 'vehicle' ? 'cert-audit-vehicle' : 'cert-audit-driver'; } const MK_SWITCH_NAME = '开启MK'; /** 项目备案类变更类型(含历史「项目备案调整」) */ export const PROJECT_RECORD_CHANGE_TYPES = [ '项目备案流程(本部流程)', '项目备案流程(运输部流程)', '项目备案调整', ]; /** 按变更类型选择项目变更 / 项目备案 MK 业务类型 */ export function resolveProjectChangeMkBizType(changeType) { return PROJECT_RECORD_CHANGE_TYPES.includes(String(changeType || '').trim()) ? 'project-record-change' : 'project-change'; } /** 进程内缓存,避免每次提交都打字典;登录后同一会话开关一般不变 */ let mkEnabledCache = null; let mkEnabledPromise = null; let mkTemplateListCache = null; async function loadMkTemplateList(force = false) { if (!force && mkTemplateListCache) { return mkTemplateListCache; } const res = await getDictionary({ code: 'mk_template' }); mkTemplateListCache = res?.data?.data || []; return mkTemplateListCache; } /** 业务字典 mk_template:名称「开启MK」且键值为 1 时才请求 MK */ export function isMkEnabled(list = []) { const matched = list.find(item => String(item.dictValue || '').trim() === MK_SWITCH_NAME); return String(matched?.dictKey ?? '').trim() === '1'; } /** 清除 MK 开关缓存(字典变更后可调用) */ export function clearMkEnabledCache() { mkEnabledCache = null; mkEnabledPromise = null; mkTemplateListCache = null; } /** * 加载业务字典并判断是否开启 MK * @param {boolean} [force=false] 是否强制刷新缓存 */ export async function loadMkEnabled(force = false) { if (!force && mkEnabledCache !== null) { return mkEnabledCache; } if (!force && mkEnabledPromise) { return mkEnabledPromise; } mkEnabledPromise = loadMkTemplateList(force) .then(list => { mkEnabledCache = isMkEnabled(list); return mkEnabledCache; }) .catch(error => { mkEnabledCache = false; throw error; }) .finally(() => { mkEnabledPromise = null; }); return mkEnabledPromise; } export async function resolveMkTemplateCode(dictName, list) { const dictList = list || (await loadMkTemplateList()); const matched = dictList.find(item => String(item.dictValue || '').trim() === dictName); const templateCode = matched?.dictKey; if (!templateCode) { ElMessage.warning(`未配置业务字典 mk_template「${dictName}」,无法提交审核流`); return Promise.reject(new Error(`未配置业务字典 mk_template「${dictName}」`)); } return String(templateCode); } /** * 是否属于「审核通过后再提交」需要新建表单实例的状态 */ export function isMkApprovedStatus(bizType, approvalStatus) { const conf = MK_BIZ[bizType]; if (!conf) return false; return (conf.approved || []).includes(approvalStatus); } /** * 提交 MK 审核流。未开启 MK 时直接跳过,不请求流程实例相关接口。 * @param {Object} options * @param {string} options.bizType 业务类型 * @param {string|number} options.bizId 业务主键 * @param {string} [options.subjectName] 标题后缀 * @param {string} [options.approvalStatus] 提交前的审批状态 * @param {boolean} [options.mkEnabled] 调用方已知开关时传入,false 时立即跳过 * @param {Object} [options.tempVarData] 传给 MK 的临时变量(如项目类型 projectType、用印类型 sealTypes) * @returns {Promise} true=已发起/复用 MK 流程,false=未开启或已跳过 */ export async function submitMkApprovalFlow({ bizType, bizId, subjectName = '', approvalStatus = '', mkEnabled, tempVarData, } = {}) { const conf = MK_BIZ[bizType]; if (!conf) { return Promise.reject(new Error(`不支持的MK业务类型:${bizType}`)); } if (bizId == null || bizId === '') { return Promise.reject(new Error('业务id不能为空')); } // 调用方显式关闭,或字典未开启:不请求 hasMkProcessInstance / processSubmit 等 MK 接口 if (mkEnabled === false) { return false; } const enabled = mkEnabled === true ? true : await loadMkEnabled(); if (!enabled) { return false; } const list = await loadMkTemplateList(); if (!isMkEnabled(list)) { mkEnabledCache = false; return false; } const bizIdText = String(bizId); const forceNewFormInstance = isMkApprovedStatus(bizType, approvalStatus); // 审核通过后再提交必须新建流程;其余场景已有有效实例则跳过 if (!forceNewFormInstance) { const existsRes = await hasMkProcessInstance({ bizId: bizIdText }); if (existsRes?.data?.data) { return true; } } if ((conf.rejected || []).includes(approvalStatus)) { await processDelete({ bizId: bizIdText }); } const templateCode = await resolveMkTemplateCode(conf.dictName, list); const subject = subjectName ? `${conf.subjectPrefix}:${subjectName}` : `${conf.subjectPrefix}:${bizIdText}`; const submitPayload = { templateCode, bizId: bizIdText, subject, bizType, forceNewFormInstance, }; if (tempVarData != null && typeof tempVarData === 'object') { submitPayload.tempVarData = tempVarData; } await processSubmit(submitPayload); return true; }