@@ -66,11 +66,41 @@
|
|||||||
<el-form-item label="项目">
|
<el-form-item label="项目">
|
||||||
<el-input v-model="form.projectName" disabled />
|
<el-input v-model="form.projectName" disabled />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合同负责部门">
|
<el-form-item label="合同负责部门" prop="organizationName">
|
||||||
<el-input v-model="form.organizationName" disabled />
|
<el-select
|
||||||
|
v-model="selectedOrganizationId"
|
||||||
|
placeholder="请选择"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
:loading="businessDeptLoading"
|
||||||
|
:disabled="isSettlementRuleChange"
|
||||||
|
@visible-change="visible => visible && loadBusinessDeptOptions()"
|
||||||
|
@change="handleOrganizationChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in businessDeptOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="平台公司">
|
<el-form-item label="平台公司" prop="platformCompanyName">
|
||||||
<el-input v-model="form.platformCompanyName" disabled />
|
<el-select
|
||||||
|
v-model="form.platformCompanyId"
|
||||||
|
placeholder="请选择平台公司"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
:disabled="isSettlementRuleChange || !form.projectId"
|
||||||
|
@change="handlePlatformCompanyChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in platformCompanyOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="签订日期">
|
<el-form-item label="签订日期">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
@@ -575,8 +605,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import * as contractApi from '@/api/business/contract-manage';
|
import * as contractApi from '@/api/business/contract-manage';
|
||||||
import * as changeApi from '@/api/business/contract-change';
|
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 { getMkPublicDetail } from '@/api/mk-process';
|
||||||
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||||
|
import { normalizeBusinessDeptOptions } from '@/utils/dept';
|
||||||
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
||||||
import ContractAttachmentSection, {
|
import ContractAttachmentSection, {
|
||||||
isContractSealMaterialLocation,
|
isContractSealMaterialLocation,
|
||||||
@@ -740,6 +773,10 @@ export default {
|
|||||||
settlementCurrencyOptions: [],
|
settlementCurrencyOptions: [],
|
||||||
settlementModeDictOptions: [],
|
settlementModeDictOptions: [],
|
||||||
contractFormatDictOptions: [],
|
contractFormatDictOptions: [],
|
||||||
|
selectedOrganizationId: '',
|
||||||
|
businessDeptOptions: [],
|
||||||
|
businessDeptLoading: false,
|
||||||
|
platformCompanyOptions: [],
|
||||||
planDialogVisible: false,
|
planDialogVisible: false,
|
||||||
planEditor: { planName: '', remark: '', rules: [] },
|
planEditor: { planName: '', remark: '', rules: [] },
|
||||||
planEditorIndex: -1,
|
planEditorIndex: -1,
|
||||||
@@ -772,6 +809,34 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
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: [
|
contractAmount: [
|
||||||
{ required: true, message: '请输入合同金额', trigger: 'blur' },
|
{ required: true, message: '请输入合同金额', trigger: 'blur' },
|
||||||
{
|
{
|
||||||
@@ -924,6 +989,136 @@ export default {
|
|||||||
formatContractAmountField() {
|
formatContractAmountField() {
|
||||||
this.form.contractAmount = formatContractAmountInput(this.form.contractAmount);
|
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() {
|
loadDictionaries() {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
getSystemDictionary({ code: 'currency_type' }),
|
getSystemDictionary({ code: 'currency_type' }),
|
||||||
@@ -972,6 +1167,10 @@ export default {
|
|||||||
...data,
|
...data,
|
||||||
// 独立变更单保留 contractId;旧路由以合同 id 作为主键
|
// 独立变更单保留 contractId;旧路由以合同 id 作为主键
|
||||||
contractId: data.contractId || (isChangeRecord ? data.contractId : data.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 || '' : '',
|
changeContent: isChangeRecord ? data.changeContent || '' : '',
|
||||||
changeReason: isChangeRecord ? data.changeReason || '' : '',
|
changeReason: isChangeRecord ? data.changeReason || '' : '',
|
||||||
changeAttachmentsJson: data.changeAttachmentsJson || '',
|
changeAttachmentsJson: data.changeAttachmentsJson || '',
|
||||||
@@ -984,6 +1183,7 @@ export default {
|
|||||||
archiveStatus: data.archiveStatus || '未归档',
|
archiveStatus: data.archiveStatus || '未归档',
|
||||||
changeType: data.changeType || '合同信息变更',
|
changeType: data.changeType || '合同信息变更',
|
||||||
};
|
};
|
||||||
|
this.selectedOrganizationId = this.form.organizationId ? String(this.form.organizationId) : '';
|
||||||
this.changeMaterials = this.parse(data.changeAttachmentsJson);
|
this.changeMaterials = this.parse(data.changeAttachmentsJson);
|
||||||
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
||||||
this.partyARows = normalizePartyRows(data.partyAJson, data.partyA, true);
|
this.partyARows = normalizePartyRows(data.partyAJson, data.partyA, true);
|
||||||
@@ -1033,6 +1233,8 @@ export default {
|
|||||||
this.feeGenerationMode =
|
this.feeGenerationMode =
|
||||||
data.feeGenerationMode || (Number(data.billingEnabled) === 0 ? 'manual' : 'system');
|
data.feeGenerationMode || (Number(data.billingEnabled) === 0 ? 'manual' : 'system');
|
||||||
this.paymentRatioRows = this.parse(data.paymentRatioJson);
|
this.paymentRatioRows = this.parse(data.paymentRatioJson);
|
||||||
|
this.loadBusinessDeptOptions();
|
||||||
|
this.loadProjectPlatformCompanies();
|
||||||
},
|
},
|
||||||
goBack() {
|
goBack() {
|
||||||
if (this.isContractChangeModule) {
|
if (this.isContractChangeModule) {
|
||||||
@@ -1231,6 +1433,14 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.form.contractNo = contractNo;
|
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);
|
const total = this.paymentRatioRows.reduce((sum, row) => sum + Number(row.ratioLimit || 0), 0);
|
||||||
if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) {
|
if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) {
|
||||||
this.$message.warning('付款比例上限合计必须等于100%');
|
this.$message.warning('付款比例上限合计必须等于100%');
|
||||||
|
|||||||
Reference in New Issue
Block a user