From 1ed524f80fd48655164a0a74c83a1b15c099e9d8 Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Tue, 29 Sep 2026 03:15:27 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E7=BB=84=E7=BB=87=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=8E=A5=E4=B8=9A=E5=8A=A1=E5=AD=97=E5=85=B8=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E6=94=AF=E6=8C=81=E5=A4=9A=E6=89=80=E5=B1=9E=E7=BB=84?= =?UTF-8?q?=E7=BB=87=E4=B8=8EMK=E5=86=8D=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 组织管理类型改为 organization_type;用户所属组织支持多选;提交MK前保留原审批状态以识别通过后再提交。 Co-authored-by: Cursor --- src/utils/mk-approval.js | 13 ++- src/views/business/contract-manage.vue | 3 +- src/views/business/project-apply.vue | 3 +- src/views/payment/bill-payment-form.vue | 3 +- src/views/payment/bill-payment.vue | 3 +- .../payment/invoice-application-form.vue | 3 +- src/views/payment/invoice-application.vue | 3 +- src/views/payment/invoice-receipt-form.vue | 3 +- src/views/payment/invoice-receipt.vue | 3 +- .../payment/payment-application-form.vue | 3 +- src/views/payment/payment-application.vue | 3 +- .../components/pre-settlement-editor.vue | 3 +- src/views/settlement/formal-settlement.vue | 3 +- src/views/settlement/pre-settlement.vue | 3 +- src/views/system/dept.vue | 107 +++++++++++++----- src/views/system/user.vue | 81 +++++++++++-- 16 files changed, 182 insertions(+), 58 deletions(-) diff --git a/src/utils/mk-approval.js b/src/utils/mk-approval.js index 3562545..60ee800 100644 --- a/src/utils/mk-approval.js +++ b/src/utils/mk-approval.js @@ -89,13 +89,22 @@ export async function resolveMkTemplateCode(dictName, list) { return String(templateCode); } +/** + * 是否属于「审核通过后再提交」需要新建表单实例的状态 + */ +export function isMkApprovedStatus(bizType, approvalStatus) { + const conf = MK_BIZ[bizType]; + if (!conf) return false; + return (conf.approved || []).includes(approvalStatus); +} + /** * 提交 MK 审核流 * @param {Object} options * @param {string} options.bizType 业务类型 * @param {string|number} options.bizId 业务主键(后端据此生成/复用 formInstanceId) * @param {string} [options.subjectName] 标题后缀 - * @param {string} [options.approvalStatus] 当前审批状态(驳回态会先 delete;通过态强制新建实例) + * @param {string} [options.approvalStatus] 提交前的审批状态(须在业务 submit 改状态前取值;通过态强制新建实例) */ export async function submitMkApprovalFlow({ bizType, @@ -115,7 +124,7 @@ export async function submitMkApprovalFlow({ return; } const bizIdText = String(bizId); - const forceNewFormInstance = (conf.approved || []).includes(approvalStatus); + const forceNewFormInstance = isMkApprovedStatus(bizType, approvalStatus); // 审核通过后再提交必须新建流程;其余场景已有有效实例则跳过 if (!forceNewFormInstance) { const existsRes = await hasMkProcessInstance({ bizId: bizIdText }); diff --git a/src/views/business/contract-manage.vue b/src/views/business/contract-manage.vue index 3c2fd7b..c57b980 100644 --- a/src/views/business/contract-manage.vue +++ b/src/views/business/contract-manage.vue @@ -1872,6 +1872,7 @@ export default { submitCreate(action) { if (this.submitAction || !this.validateBase(action)) return; this.submitAction = action; + const previousApprovalStatus = this.form.approvalStatus || ''; const submit = { ...this.normalizeSubmit(), contractStage: action === 'formal' ? 'temporary' : 'draft', @@ -1892,7 +1893,7 @@ export default { bizType: 'contract-manage', bizId: id, subjectName: saved.contractName || submit.contractName || '', - approvalStatus: saved.approvalStatus || submit.approvalStatus || '', + approvalStatus: previousApprovalStatus || saved.approvalStatus || submit.approvalStatus || '', }) ); } diff --git a/src/views/business/project-apply.vue b/src/views/business/project-apply.vue index ee1b8bd..6062b93 100644 --- a/src/views/business/project-apply.vue +++ b/src/views/business/project-apply.vue @@ -1907,7 +1907,8 @@ export default { const data = res.data?.data || {}; const id = data.id || this.form.id; const name = data.projectName || this.form.projectName || ''; - const status = data.approvalStatus || this.form.approvalStatus || ''; + // 必须用提交前状态:业务 submit 后可能已变成 reviewing,导致无法识别「通过后再提交」 + const status = this.form.approvalStatus || data.approvalStatus || ''; if (!id) { this.$message.success('操作成功!'); this.closeProjectForm(); diff --git a/src/views/payment/bill-payment-form.vue b/src/views/payment/bill-payment-form.vue index 745fc2e..d16b681 100644 --- a/src/views/payment/bill-payment-form.vue +++ b/src/views/payment/bill-payment-form.vue @@ -341,12 +341,13 @@ export default { try { const id = this.unwrapData(await api.save(this.payload())); this.form.id = id; + const previousApprovalStatus = this.form.approvalStatus || ''; await api.submit({ id: this.form.id }); await submitMkApprovalFlow({ bizType: 'bill-payment', bizId: this.form.id, subjectName: this.form.paymentNo || this.form.billNo || '', - approvalStatus: this.form.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.goBack(); diff --git a/src/views/payment/bill-payment.vue b/src/views/payment/bill-payment.vue index e1d1e40..1f63ccb 100644 --- a/src/views/payment/bill-payment.vue +++ b/src/views/payment/bill-payment.vue @@ -121,12 +121,13 @@ export default { this.loadTable(); }, async handleSubmit(row) { + const previousApprovalStatus = row.approvalStatus || ''; await api.submit({ id: row.id }); await submitMkApprovalFlow({ bizType: 'bill-payment', bizId: row.id, subjectName: row.paymentNo || row.billNo || '', - approvalStatus: row.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.loadTable(); diff --git a/src/views/payment/invoice-application-form.vue b/src/views/payment/invoice-application-form.vue index a968b04..ee2bf75 100644 --- a/src/views/payment/invoice-application-form.vue +++ b/src/views/payment/invoice-application-form.vue @@ -1194,12 +1194,13 @@ export default { } const saved = await this.saveDraft(); if (!saved) return; + const previousApprovalStatus = this.form.approvalStatus || ''; await api.submit({ id: this.form.id }); await submitMkApprovalFlow({ bizType: 'invoice-application', bizId: this.form.id, subjectName: this.form.applicationNo || '', - approvalStatus: this.form.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.goBack(); diff --git a/src/views/payment/invoice-application.vue b/src/views/payment/invoice-application.vue index a52a064..6d69539 100644 --- a/src/views/payment/invoice-application.vue +++ b/src/views/payment/invoice-application.vue @@ -344,12 +344,13 @@ export default { this.loadTable(); }, async handleSubmit(row) { + const previousApprovalStatus = row.approvalStatus || ''; await api.submit({ id: row.id }); await submitMkApprovalFlow({ bizType: 'invoice-application', bizId: row.id, subjectName: row.applicationNo || '', - approvalStatus: row.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.loadTable(); diff --git a/src/views/payment/invoice-receipt-form.vue b/src/views/payment/invoice-receipt-form.vue index 57cbbe7..97556b4 100644 --- a/src/views/payment/invoice-receipt-form.vue +++ b/src/views/payment/invoice-receipt-form.vue @@ -766,12 +766,13 @@ export default { async submitForm() { const saved = await this.saveDraft(); if (!saved) return; + const previousApprovalStatus = this.form.approvalStatus || ''; await api.submit({ id: this.form.id }); await submitMkApprovalFlow({ bizType: 'invoice-receipt', bizId: this.form.id, subjectName: this.form.invoiceNo || '', - approvalStatus: this.form.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.goBack(); diff --git a/src/views/payment/invoice-receipt.vue b/src/views/payment/invoice-receipt.vue index da8b05a..462d04f 100644 --- a/src/views/payment/invoice-receipt.vue +++ b/src/views/payment/invoice-receipt.vue @@ -309,12 +309,13 @@ export default { this.loadTable(); }, async handleSubmit(row) { + const previousApprovalStatus = row.approvalStatus || ''; await api.submit({ id: row.id }); await submitMkApprovalFlow({ bizType: 'invoice-receipt', bizId: row.id, subjectName: row.invoiceNo || '', - approvalStatus: row.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.loadTable(); diff --git a/src/views/payment/payment-application-form.vue b/src/views/payment/payment-application-form.vue index 9e7e278..851b550 100644 --- a/src/views/payment/payment-application-form.vue +++ b/src/views/payment/payment-application-form.vue @@ -2632,12 +2632,13 @@ export default { // 提交前静默保存,避免同时弹出「保存成功」与材料缺失 toast const saved = await this.saveDraft({ showSuccess: false }); if (!saved) return; + const previousApprovalStatus = this.form.approvalStatus || ''; await api.submit({ id: this.form.id }); await submitMkApprovalFlow({ bizType: 'payment-application', bizId: this.form.id, subjectName: this.form.paymentNo || '', - approvalStatus: this.form.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.goBack(); diff --git a/src/views/payment/payment-application.vue b/src/views/payment/payment-application.vue index 1d4042e..597ad6f 100644 --- a/src/views/payment/payment-application.vue +++ b/src/views/payment/payment-application.vue @@ -364,12 +364,13 @@ export default { this.loadTable(); }, async handleSubmit(row) { + const previousApprovalStatus = row.approvalStatus || ''; await api.submit({ id: row.id }); await submitMkApprovalFlow({ bizType: 'payment-application', bizId: row.id, subjectName: row.paymentNo || '', - approvalStatus: row.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.loadTable(); diff --git a/src/views/settlement/components/pre-settlement-editor.vue b/src/views/settlement/components/pre-settlement-editor.vue index 1c5f134..dfba02c 100644 --- a/src/views/settlement/components/pre-settlement-editor.vue +++ b/src/views/settlement/components/pre-settlement-editor.vue @@ -1601,12 +1601,13 @@ export default { await this.loadDetail(); await this.persistPendingAdjustments(); if (shouldSubmit) { + const previousApprovalStatus = this.form.approvalStatus || ''; await submit({ id: this.form.id }); await submitMkApprovalFlow({ bizType: 'pre-settlement', bizId: this.form.id, subjectName: this.form.preSettlementNo || this.form.contractName || '', - approvalStatus: this.form.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('审批流程已发起'); this.visible = false; diff --git a/src/views/settlement/formal-settlement.vue b/src/views/settlement/formal-settlement.vue index a5aca35..86a8ac7 100644 --- a/src/views/settlement/formal-settlement.vue +++ b/src/views/settlement/formal-settlement.vue @@ -349,12 +349,13 @@ export default { }, async handleSubmit(row) { await this.$confirm('提交后来源预结算将保持锁定,确认提交?', '提示', { type: 'warning' }); + const previousApprovalStatus = row.approvalStatus || ''; await api.submit({ id: row.id }); await submitMkApprovalFlow({ bizType: 'formal-settlement', bizId: row.id, subjectName: row.formalSettlementNo || '', - approvalStatus: row.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.loadTable(); diff --git a/src/views/settlement/pre-settlement.vue b/src/views/settlement/pre-settlement.vue index 2a7e1b6..5a0d123 100644 --- a/src/views/settlement/pre-settlement.vue +++ b/src/views/settlement/pre-settlement.vue @@ -641,12 +641,13 @@ export default { downloadFile(data, `预结算单${this.$dayjs().format('YYYY-MM-DD HH-mm-ss')}.xlsx`); }, async handleSubmit(row) { + const previousApprovalStatus = row.approvalStatus || ''; await submit({ id: row.id }); await submitMkApprovalFlow({ bizType: 'pre-settlement', bizId: row.id, subjectName: row.preSettlementNo || '', - approvalStatus: row.approvalStatus || '', + approvalStatus: previousApprovalStatus, }); this.$message.success('提交成功'); this.loadTable(); diff --git a/src/views/system/dept.vue b/src/views/system/dept.vue index 565ad53..f6a4f72 100644 --- a/src/views/system/dept.vue +++ b/src/views/system/dept.vue @@ -48,7 +48,7 @@ @@ -214,11 +221,25 @@ - + + + + + 仅所属组织全部组织自定义 - 包含下级仅本级 + 包含下级仅本级 @@ -505,7 +526,24 @@ export default { password: [{ required: true, validator: validateLoginPassword, trigger: 'blur' }], realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }], phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }], - deptId: [{ required: true, message: '请选择所属组织', trigger: 'change' }], + deptId: [ + { + required: true, + validator: (rule, value, callback) => { + const ids = Array.isArray(value) + ? value.filter(item => item !== undefined && item !== null && item !== '') + : value + ? String(value).split(',').filter(Boolean) + : []; + if (!ids.length) { + callback(new Error('请选择所属组织')); + return; + } + callback(); + }, + trigger: 'change', + }, + ], }, excelForm: {}, excelOption: excelOption, @@ -561,31 +599,36 @@ export default { } return undefined; }, - // 所属组织级联配置:checkStrictly 为 true 时任意一级都可选择 + // 所属组织级联配置:多选,checkStrictly 为 true 时任意一级都可选择 deptCascaderProps() { return { label: 'title', value: 'id', children: 'children', emitPath: false, + multiple: true, checkStrictly: true, expandTrigger: 'click', - leaf: data => !data.children || data.children.length === 0, }; }, - // 所属组织为单选级联:form.deptId 为数组(提交时 join),级联返回单个 id 值 + // 所属组织多选级联:form.deptId 为 id 数组(提交时 join) deptCascaderValue: { get() { const ids = Array.isArray(this.form.deptId) ? this.form.deptId : this.form.deptId - ? [this.form.deptId] + ? String(this.form.deptId).split(',').filter(Boolean) : []; - const id = ids.find(item => item !== undefined && item !== null && item !== ''); - return id === undefined ? '' : id; + return ids + .filter(item => item !== undefined && item !== null && item !== '') + .map(item => (typeof item === 'number' ? item : String(item))); }, set(value) { - this.form.deptId = value ? [value] : []; + this.form.deptId = Array.isArray(value) + ? value.filter(item => item !== undefined && item !== null && item !== '') + : value + ? [value] + : []; this.$refs.userFormRef?.validateField('deptId'); }, }, @@ -844,6 +887,15 @@ export default { handleCustomerSelection(rows) { this.form.customerIds = rows.map(row => row.id); }, + formatDeptNames(deptName) { + if (!deptName) { + return []; + } + return String(deptName) + .split(',') + .map(item => item.trim()) + .filter(Boolean); + }, openUserDialog(mode, row = {}) { this.userDialogMode = mode; if (mode === 'add') { @@ -872,9 +924,10 @@ export default { } getUser(row.id).then(res => { const user = res.data.data; + const deptIds = func.split(user.deptId || ''); this.form = { ...user, - deptId: func.split(user.deptId || ''), + deptId: Array.isArray(deptIds) ? deptIds : [], postId: func.split(user.postId || '')[0] || '', roleId: func.join(user.roleId || ''), dataScopeDeptIds: user.dataScopeDeptIds || [], @@ -1416,6 +1469,10 @@ export default { justify-content: flex-start; } +.user-dept-tag + .user-dept-tag { + margin-left: 6px; +} + .avue-dialog .el-form-item__label { white-space: nowrap; }