diff --git a/src/views/business/contract-manage-change.vue b/src/views/business/contract-manage-change.vue index bc76ee6..2dae27a 100644 --- a/src/views/business/contract-manage-change.vue +++ b/src/views/business/contract-manage-change.vue @@ -66,11 +66,41 @@ - - + + + + - - + + + + import * as contractApi from '@/api/business/contract-manage'; import * as changeApi from '@/api/business/contract-change'; +import { getDetail as getProjectDetail } from '@/api/business/project-apply'; +import { getBusinessDeptSelect, getPlatformCompanySelect } from '@/api/system/dept'; import { getMkPublicDetail } from '@/api/mk-process'; import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval'; +import { normalizeBusinessDeptOptions } from '@/utils/dept'; import BillingPlanEditor from './components/billing-plan-editor.vue'; import ContractAttachmentSection, { isContractSealMaterialLocation, @@ -740,6 +773,10 @@ export default { settlementCurrencyOptions: [], settlementModeDictOptions: [], contractFormatDictOptions: [], + selectedOrganizationId: '', + businessDeptOptions: [], + businessDeptLoading: false, + platformCompanyOptions: [], planDialogVisible: false, planEditor: { planName: '', remark: '', rules: [] }, planEditorIndex: -1, @@ -772,6 +809,34 @@ export default { }, ], contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }], + organizationName: [ + { + validator: (rule, value, callback) => { + if (this.isSettlementRuleChange) { + return callback(); + } + if (!String(value || '').trim()) { + return callback(new Error('请选择合同负责部门')); + } + callback(); + }, + trigger: 'change', + }, + ], + platformCompanyName: [ + { + validator: (rule, value, callback) => { + if (this.isSettlementRuleChange) { + return callback(); + } + if (!String(value || '').trim()) { + return callback(new Error('请选择平台公司')); + } + callback(); + }, + trigger: 'change', + }, + ], contractAmount: [ { required: true, message: '请输入合同金额', trigger: 'blur' }, { @@ -924,6 +989,136 @@ export default { formatContractAmountField() { this.form.contractAmount = formatContractAmountInput(this.form.contractAmount); }, + handleOrganizationChange(id) { + const organizationId = Array.isArray(id) ? id.at(-1) : id; + const organization = this.businessDeptOptions.find( + item => String(item.id) === String(organizationId) + ); + Object.assign( + this.form, + organization + ? { + organizationId: organization.id, + organizationName: organization.rawLabel || organization.label, + } + : { organizationId: '', organizationName: '' } + ); + this.selectedOrganizationId = this.form.organizationId + ? String(this.form.organizationId) + : ''; + }, + handlePlatformCompanyChange(value) { + const matched = this.platformCompanyOptions.find(item => String(item.id) === String(value)); + this.form.platformCompanyId = matched ? matched.id : ''; + this.form.platformCompanyName = matched ? matched.label : ''; + }, + loadBusinessDeptOptions() { + if (this.businessDeptLoading) return; + this.businessDeptLoading = true; + getBusinessDeptSelect() + .then(res => { + this.businessDeptOptions = normalizeBusinessDeptOptions(res.data?.data || []); + this.syncCurrentBusinessDeptOption(); + }) + .finally(() => { + this.businessDeptLoading = false; + }); + }, + syncCurrentBusinessDeptOption() { + if (!this.form.organizationId || !this.form.organizationName) return; + if ( + this.businessDeptOptions.some(item => String(item.id) === String(this.form.organizationId)) + ) { + return; + } + this.businessDeptOptions.unshift({ + id: String(this.form.organizationId), + value: String(this.form.organizationId), + label: this.form.organizationName, + rawLabel: this.form.organizationName, + }); + }, + parseUndertakeDeptIds(value) { + if (Array.isArray(value)) { + return value.map(item => String(item || '').trim()).filter(Boolean); + } + return String(value || '') + .split(',') + .map(item => item.trim()) + .filter(Boolean); + }, + parseUndertakeDeptNames(value) { + if (Array.isArray(value)) { + return value.map(item => String(item || '').trim()).filter(Boolean); + } + return String(value || '') + .split(/[、,,]/) + .map(item => item.trim()) + .filter(Boolean); + }, + loadProjectPlatformCompanies() { + const projectId = this.form.projectId; + if (!projectId || String(projectId) === '-1') { + this.syncCurrentPlatformCompanyOption(); + return Promise.resolve([]); + } + return getProjectDetail(projectId) + .then(res => { + const project = res.data?.data || res.data || {}; + const ids = this.parseUndertakeDeptIds(project.undertakeDeptId); + const names = this.parseUndertakeDeptNames(project.undertakeDeptName); + return this.resolveProjectPlatformCompanyOptions(ids, names); + }) + .then(options => { + this.platformCompanyOptions = options; + this.syncCurrentPlatformCompanyOption(); + return options; + }) + .catch(() => { + this.syncCurrentPlatformCompanyOption(); + return this.platformCompanyOptions; + }); + }, + resolveProjectPlatformCompanyOptions(ids, names) { + const fallback = ids.map((id, index) => ({ + id: String(id), + label: names[index] || String(id), + })); + if (!ids.length) return Promise.resolve([]); + return getPlatformCompanySelect() + .then(res => { + const liveList = (res.data?.data || []).map(item => ({ + id: String(item.id), + label: item.deptName || item.fullName || String(item.id), + })); + return ids.map((id, index) => { + const name = String(names[index] || '').trim(); + const byId = liveList.find(item => String(item.id) === String(id)); + if (byId) return byId; + const byName = name ? liveList.find(item => item.label === name) : null; + if (byName) return byName; + return { + id: String(id), + label: name || String(id), + }; + }); + }) + .catch(() => fallback); + }, + syncCurrentPlatformCompanyOption() { + if (!this.form.platformCompanyId || !this.form.platformCompanyName) return; + if ( + this.platformCompanyOptions.some( + item => String(item.id) === String(this.form.platformCompanyId) + ) + ) { + return; + } + this.platformCompanyOptions.unshift({ + id: String(this.form.platformCompanyId), + label: this.form.platformCompanyName, + }); + }, loadDictionaries() { Promise.all([ getSystemDictionary({ code: 'currency_type' }), @@ -972,6 +1167,10 @@ export default { ...data, // 独立变更单保留 contractId;旧路由以合同 id 作为主键 contractId: data.contractId || (isChangeRecord ? data.contractId : data.id), + organizationId: data.organizationId ? String(data.organizationId) : '', + organizationName: data.organizationName || '', + platformCompanyId: data.platformCompanyId ? String(data.platformCompanyId) : '', + platformCompanyName: data.platformCompanyName || '', changeContent: isChangeRecord ? data.changeContent || '' : '', changeReason: isChangeRecord ? data.changeReason || '' : '', changeAttachmentsJson: data.changeAttachmentsJson || '', @@ -984,6 +1183,7 @@ export default { archiveStatus: data.archiveStatus || '未归档', changeType: data.changeType || '合同信息变更', }; + this.selectedOrganizationId = this.form.organizationId ? String(this.form.organizationId) : ''; this.changeMaterials = this.parse(data.changeAttachmentsJson); this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : []; this.partyARows = normalizePartyRows(data.partyAJson, data.partyA, true); @@ -1033,6 +1233,8 @@ export default { this.feeGenerationMode = data.feeGenerationMode || (Number(data.billingEnabled) === 0 ? 'manual' : 'system'); this.paymentRatioRows = this.parse(data.paymentRatioJson); + this.loadBusinessDeptOptions(); + this.loadProjectPlatformCompanies(); }, goBack() { if (this.isContractChangeModule) { @@ -1231,6 +1433,14 @@ export default { return; } this.form.contractNo = contractNo; + if (!String(this.form.organizationName || '').trim()) { + this.$message.warning('请选择合同负责部门'); + return; + } + if (!String(this.form.platformCompanyName || '').trim()) { + this.$message.warning('请选择平台公司'); + return; + } const total = this.paymentRatioRows.reduce((sum, row) => sum + Number(row.ratioLimit || 0), 0); if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) { this.$message.warning('付款比例上限合计必须等于100%');