✨ 合同结算币种联动计费与运单计价单位,并完善合同与派车交互
结算币种驱动计费单价单位及运单/计划/总单计价单位;同步合同编号预览、部门前缀配置、派车备注与查看弹窗等交互优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -171,7 +171,7 @@
|
||||
:label="item.label"
|
||||
:value="item.value" /></el-select></template
|
||||
></el-table-column>
|
||||
<el-table-column label="单价(元)" width="180"
|
||||
<el-table-column :label="unitPriceColumnLabel" width="180"
|
||||
><template #default="{ row }"
|
||||
><div v-if="readonly && usesRangeUnitPrice(row)" class="limit-list">
|
||||
<span v-for="(item, rangeIndex) in getRanges(row)" :key="rangeIndex">{{
|
||||
@@ -379,6 +379,7 @@ import { getLazyTree as getRegionLazyTree } from '@/api/base/region';
|
||||
import { InfoFilled } from '@element-plus/icons-vue';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import SectionCard from '@/components/section-card/main.vue';
|
||||
import { currencyUnit } from '@/utils/currency';
|
||||
|
||||
const clone = value => JSON.parse(JSON.stringify(value));
|
||||
/** 计费要素与计量单位维度的对应关系(这些要素可选计费单位) */
|
||||
@@ -431,6 +432,7 @@ export default {
|
||||
value: { type: Object, default: () => ({}) },
|
||||
index: { type: Number, default: -1 },
|
||||
readonly: Boolean,
|
||||
settlementCurrency: { type: String, default: 'RMB' },
|
||||
},
|
||||
emits: ['update:modelValue', 'save'],
|
||||
data() {
|
||||
@@ -500,6 +502,9 @@ export default {
|
||||
emitPath: true,
|
||||
};
|
||||
},
|
||||
unitPriceColumnLabel() {
|
||||
return `单价(${currencyUnit(this.settlementCurrency)})`;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadDictionaries();
|
||||
|
||||
@@ -173,13 +173,41 @@ import { downloadFileByUrl } from '@/utils/util';
|
||||
import { getDictionary as getBizDictionary } from '@/api/system/dictbiz';
|
||||
|
||||
const CONTRACT_ATTACHMENT_TYPE_OTHER = '其他文件';
|
||||
/** 用印材料历史取值兼容别名 */
|
||||
export const CONTRACT_SEAL_MATERIAL_LOCATION = '用印材料';
|
||||
export const CONTRACT_SEAL_MATERIAL_TYPE_ALIASES = {
|
||||
合同文件: CONTRACT_SEAL_MATERIAL_LOCATION,
|
||||
};
|
||||
/** 佐证材料附件位置(历史:其它附件) */
|
||||
export const CONTRACT_SUPPORTING_ATTACHMENT_LOCATION = '附件(佐证材料等)';
|
||||
export const CONTRACT_ATTACHMENT_TYPE_DICT = 'contract_attachment_type';
|
||||
export const CONTRACT_SUPPORTING_ATTACHMENT_TYPE_DICT = 'contract_supporting_attachment_type';
|
||||
export const isContractSupportingAttachmentLocation = location => {
|
||||
const text = String(location || '');
|
||||
return (
|
||||
text === CONTRACT_SUPPORTING_ATTACHMENT_LOCATION ||
|
||||
text === '其它附件' ||
|
||||
text === '其他附件'
|
||||
);
|
||||
};
|
||||
export const resolveAttachmentTypeDictCode = (location, fallback = CONTRACT_ATTACHMENT_TYPE_DICT) =>
|
||||
isContractSupportingAttachmentLocation(location)
|
||||
? CONTRACT_SUPPORTING_ATTACHMENT_TYPE_DICT
|
||||
: fallback || CONTRACT_ATTACHMENT_TYPE_DICT;
|
||||
export const defaultContractAttachmentTypeOptions = [
|
||||
{ label: '合同文件', value: '合同文件' },
|
||||
{ label: '用印材料', value: '用印材料' },
|
||||
{ label: '双章归档文件', value: '双章归档文件' },
|
||||
{ label: '其他文件', value: CONTRACT_ATTACHMENT_TYPE_OTHER },
|
||||
];
|
||||
/** @deprecated 兼容旧引用,实际选项由业务字典 contract_attachment_type 动态加载 */
|
||||
export const defaultContractSupportingAttachmentTypeOptions = [
|
||||
{ label: '其他文件', value: CONTRACT_ATTACHMENT_TYPE_OTHER },
|
||||
];
|
||||
/** @deprecated 兼容旧引用,实际选项由业务字典动态加载 */
|
||||
export const contractAttachmentTypeOptions = defaultContractAttachmentTypeOptions;
|
||||
export const isContractSealMaterialLocation = location => {
|
||||
const text = String(location || '');
|
||||
return text === CONTRACT_SEAL_MATERIAL_LOCATION || text === '合同文件';
|
||||
};
|
||||
export const attachmentFileTypes = [
|
||||
'pdf',
|
||||
'bmp',
|
||||
@@ -234,8 +262,11 @@ const isOtherAttachmentTypeOption = item => {
|
||||
const attachmentTypeKeywords = fileType => {
|
||||
const text = String(fileType || '');
|
||||
if (text.includes('双章')) return ['双章归档文件', '双章归档', '双章'];
|
||||
if (text.includes('合同') && !text.includes('其他') && !text.includes('其它')) {
|
||||
return ['合同文件', '合同'];
|
||||
if (
|
||||
text.includes('用印') ||
|
||||
(text.includes('合同') && !text.includes('其他') && !text.includes('其它'))
|
||||
) {
|
||||
return ['用印材料', '合同文件', '用印', '合同'];
|
||||
}
|
||||
if (isOtherAttachmentTypeOption({ label: text, value: text })) return [];
|
||||
return text ? [text] : [];
|
||||
@@ -254,8 +285,13 @@ export const resolveContractAttachmentType = (
|
||||
const list = options.length ? options : defaultContractAttachmentTypeOptions;
|
||||
const otherType = resolveOtherAttachmentType(list);
|
||||
const values = list.map(item => item.value);
|
||||
if (values.includes(row.fileType)) return row.fileType;
|
||||
const matchedByLabel = list.find(item => String(item.label) === String(row.fileType));
|
||||
const rawFileType = String(row.fileType || '');
|
||||
const aliasedFileType = CONTRACT_SEAL_MATERIAL_TYPE_ALIASES[rawFileType] || rawFileType;
|
||||
if (values.includes(aliasedFileType)) return aliasedFileType;
|
||||
if (values.includes(rawFileType)) return rawFileType;
|
||||
const matchedByLabel = list.find(
|
||||
item => String(item.label) === aliasedFileType || String(item.label) === rawFileType
|
||||
);
|
||||
if (matchedByLabel) return matchedByLabel.value;
|
||||
const fileName = normalizeAttachmentTypeText(attachmentName(row));
|
||||
if (!fileName) return otherType;
|
||||
@@ -283,17 +319,32 @@ export const normalizeContractFileRows = (rows, options = defaultContractAttachm
|
||||
description: row.description || '',
|
||||
}));
|
||||
|
||||
const mapDictOptions = response => {
|
||||
const mapDictOptions = (response, dictCode = CONTRACT_ATTACHMENT_TYPE_DICT) => {
|
||||
const data = response?.data?.data || response?.data || [];
|
||||
const records = Array.isArray(data) ? data : data.records || [];
|
||||
const applySealAlias = dictCode === CONTRACT_ATTACHMENT_TYPE_DICT;
|
||||
return records
|
||||
.map(item => ({
|
||||
label: item.dictValue,
|
||||
value: item.dictKey,
|
||||
}))
|
||||
.map(item => {
|
||||
const rawLabel = String(item.dictValue || '');
|
||||
const rawValue = String(item.dictKey || '');
|
||||
const label = applySealAlias
|
||||
? CONTRACT_SEAL_MATERIAL_TYPE_ALIASES[rawLabel] ||
|
||||
(rawLabel === '合同文件' ? CONTRACT_SEAL_MATERIAL_LOCATION : rawLabel)
|
||||
: rawLabel;
|
||||
const value = applySealAlias
|
||||
? CONTRACT_SEAL_MATERIAL_TYPE_ALIASES[rawValue] ||
|
||||
(rawValue === '合同文件' ? CONTRACT_SEAL_MATERIAL_LOCATION : rawValue)
|
||||
: rawValue;
|
||||
return { label, value };
|
||||
})
|
||||
.filter(item => item.label && item.value);
|
||||
};
|
||||
|
||||
const defaultOptionsByDictCode = dictCode =>
|
||||
dictCode === CONTRACT_SUPPORTING_ATTACHMENT_TYPE_DICT
|
||||
? [...defaultContractSupportingAttachmentTypeOptions]
|
||||
: [...defaultContractAttachmentTypeOptions];
|
||||
|
||||
export default {
|
||||
name: 'ContractAttachmentSection',
|
||||
components: { UploadFilled },
|
||||
@@ -307,8 +358,13 @@ export default {
|
||||
markApprovedOnUpload: Boolean,
|
||||
useUploadDialog: Boolean,
|
||||
dialogOnly: Boolean,
|
||||
attachmentLocation: { type: String, default: '合同文件' },
|
||||
attachmentLocation: { type: String, default: CONTRACT_SEAL_MATERIAL_LOCATION },
|
||||
attachmentLocationOptions: { type: Array, default: null },
|
||||
/** 附件类型业务字典 code,默认用印材料字典;佐证材料传 contract_supporting_attachment_type */
|
||||
attachmentTypeDictCode: {
|
||||
type: String,
|
||||
default: CONTRACT_ATTACHMENT_TYPE_DICT,
|
||||
},
|
||||
preview: { type: Function, default: null },
|
||||
},
|
||||
emits: ['update:rows', 'upload-to-location', 'upload-confirmed'],
|
||||
@@ -317,8 +373,9 @@ export default {
|
||||
selected: [],
|
||||
attachmentFileTypes,
|
||||
contractAttachmentTypeOptions: [...defaultContractAttachmentTypeOptions],
|
||||
activeAttachmentTypeDictCode: CONTRACT_ATTACHMENT_TYPE_DICT,
|
||||
uploadDialogVisible: false,
|
||||
uploadDialogLocation: '合同文件',
|
||||
uploadDialogLocation: CONTRACT_SEAL_MATERIAL_LOCATION,
|
||||
uploadDialogType: resolveOtherAttachmentType(defaultContractAttachmentTypeOptions),
|
||||
uploadDialogFiles: [],
|
||||
uploadDialogFileList: [],
|
||||
@@ -337,48 +394,91 @@ export default {
|
||||
defaultAttachmentType() {
|
||||
return resolveOtherAttachmentType(this.contractAttachmentTypeOptions);
|
||||
},
|
||||
resolvedAttachmentTypeDictCode() {
|
||||
return this.attachmentTypeDictCode || CONTRACT_ATTACHMENT_TYPE_DICT;
|
||||
},
|
||||
resolvedLocationOptions() {
|
||||
const options = (this.attachmentLocationOptions || []).filter(Boolean);
|
||||
if (options.length) return options;
|
||||
return ['合同文件', '其它附件'];
|
||||
if (options.length) {
|
||||
return options.map(item => {
|
||||
if (item === '合同文件') return CONTRACT_SEAL_MATERIAL_LOCATION;
|
||||
if (item === '其它附件' || item === '其他附件') {
|
||||
return CONTRACT_SUPPORTING_ATTACHMENT_LOCATION;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
return [CONTRACT_SEAL_MATERIAL_LOCATION, CONTRACT_SUPPORTING_ATTACHMENT_LOCATION];
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
attachmentTypeDictCode: {
|
||||
immediate: false,
|
||||
handler() {
|
||||
this.loadAttachmentTypeOptions(this.resolvedAttachmentTypeDictCode, true);
|
||||
},
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadAttachmentTypeOptions();
|
||||
this.loadAttachmentTypeOptions(this.resolvedAttachmentTypeDictCode, true);
|
||||
},
|
||||
methods: {
|
||||
attachmentName,
|
||||
loadAttachmentTypeOptions() {
|
||||
return getBizDictionary({ code: 'contract_attachment_type' })
|
||||
currentUploadUserName() {
|
||||
const raw = this.$store.getters.userInfo;
|
||||
const userInfo = raw && !Array.isArray(raw) ? raw : {};
|
||||
// 与顶部栏一致优先 real_name;用印材料 / 佐证材料共用
|
||||
return (
|
||||
userInfo.real_name ||
|
||||
userInfo.realName ||
|
||||
userInfo.nick_name ||
|
||||
userInfo.nickName ||
|
||||
userInfo.user_name ||
|
||||
userInfo.userName ||
|
||||
userInfo.account ||
|
||||
''
|
||||
);
|
||||
},
|
||||
loadAttachmentTypeOptions(dictCode = this.resolvedAttachmentTypeDictCode, alignRows = false) {
|
||||
const code = dictCode || CONTRACT_ATTACHMENT_TYPE_DICT;
|
||||
this.activeAttachmentTypeDictCode = code;
|
||||
const fallbackOptions = defaultOptionsByDictCode(code);
|
||||
return getBizDictionary({ code })
|
||||
.then(res => {
|
||||
const options = mapDictOptions(res);
|
||||
// 切换字典期间若已发起更新请求,忽略过期响应
|
||||
if (this.activeAttachmentTypeDictCode !== code) return;
|
||||
const options = mapDictOptions(res, code);
|
||||
if (options.length) {
|
||||
// 字典缺少「其他文件」时补上,保证未匹配文件名可默认选中
|
||||
this.contractAttachmentTypeOptions = options.some(isOtherAttachmentTypeOption)
|
||||
? options
|
||||
: [...options, { label: '其他文件', value: CONTRACT_ATTACHMENT_TYPE_OTHER }];
|
||||
if (
|
||||
!this.contractAttachmentTypeOptions.some(
|
||||
item => String(item.value) === String(this.uploadDialogType)
|
||||
)
|
||||
) {
|
||||
this.uploadDialogType = this.defaultAttachmentType;
|
||||
}
|
||||
// 字典加载后,把已有行的中文类型名对齐到 dictKey,保证下拉可选中
|
||||
if (this.attachmentType && (this.rows || []).length) {
|
||||
const aligned = (this.rows || []).map(row => ({
|
||||
...row,
|
||||
fileType: resolveContractAttachmentType(row, this.contractAttachmentTypeOptions),
|
||||
}));
|
||||
const changed = aligned.some(
|
||||
(row, index) => row.fileType !== this.rows[index]?.fileType
|
||||
);
|
||||
if (changed) this.update(aligned);
|
||||
}
|
||||
} else {
|
||||
this.contractAttachmentTypeOptions = fallbackOptions;
|
||||
}
|
||||
if (
|
||||
!this.contractAttachmentTypeOptions.some(
|
||||
item => String(item.value) === String(this.uploadDialogType)
|
||||
)
|
||||
) {
|
||||
this.uploadDialogType = this.defaultAttachmentType;
|
||||
}
|
||||
// 字典加载后,把已有行的中文类型名对齐到 dictKey,保证下拉可选中
|
||||
if (alignRows && this.attachmentType && (this.rows || []).length) {
|
||||
const aligned = (this.rows || []).map(row => ({
|
||||
...row,
|
||||
fileType: resolveContractAttachmentType(row, this.contractAttachmentTypeOptions),
|
||||
}));
|
||||
const changed = aligned.some(
|
||||
(row, index) => row.fileType !== this.rows[index]?.fileType
|
||||
);
|
||||
if (changed) this.update(aligned);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 字典加载失败时保留默认选项
|
||||
if (this.activeAttachmentTypeDictCode !== code) return;
|
||||
this.contractAttachmentTypeOptions = fallbackOptions;
|
||||
this.uploadDialogType = this.defaultAttachmentType;
|
||||
});
|
||||
},
|
||||
isRowLocked(row) {
|
||||
@@ -388,13 +488,14 @@ export default {
|
||||
this.$emit('update:rows', Array.isArray(rows) ? rows.map(item => ({ ...item })) : []);
|
||||
},
|
||||
enrichUploadedRow(row, existing) {
|
||||
const uploadUserName = this.$store.getters.userInfo?.realName || '';
|
||||
const uploadUserName = this.currentUploadUserName();
|
||||
const uploadTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
const next = {
|
||||
...existing,
|
||||
...row,
|
||||
description: row.description || existing?.description || '',
|
||||
uploadUserName: existing?.uploadUserName || row.uploadUserName || uploadUserName,
|
||||
// 新上传行始终写入当前用户;已有行保留原上传人
|
||||
uploadUserName: existing?.uploadUserName || uploadUserName || row.uploadUserName || '',
|
||||
uploadTime: existing?.uploadTime || row.uploadTime || uploadTime,
|
||||
approved: existing?.approved || row.approved || false,
|
||||
};
|
||||
@@ -434,20 +535,38 @@ export default {
|
||||
resolveTypeByLocation(location) {
|
||||
const options = this.contractAttachmentTypeOptions || [];
|
||||
const locationText = String(location || '');
|
||||
if (locationText.includes('其它') || locationText.includes('其他')) {
|
||||
if (
|
||||
isContractSupportingAttachmentLocation(locationText) ||
|
||||
locationText.includes('佐证') ||
|
||||
locationText.includes('其它') ||
|
||||
locationText.includes('其他')
|
||||
) {
|
||||
return this.defaultAttachmentType;
|
||||
}
|
||||
const matched = options.find(
|
||||
item =>
|
||||
String(item.value) === locationText ||
|
||||
String(item.label) === locationText ||
|
||||
String(item.value).includes('用印') ||
|
||||
String(item.label).includes('用印') ||
|
||||
String(item.value).includes('合同') ||
|
||||
String(item.label).includes('合同')
|
||||
);
|
||||
return matched?.value || options[0]?.value || this.defaultAttachmentType;
|
||||
},
|
||||
syncUploadDialogTypeByLocation() {
|
||||
this.uploadDialogType = this.resolveTypeByLocation(this.uploadDialogLocation);
|
||||
const dictCode = resolveAttachmentTypeDictCode(
|
||||
this.uploadDialogLocation,
|
||||
this.resolvedAttachmentTypeDictCode
|
||||
);
|
||||
const applyType = () => {
|
||||
this.uploadDialogType = this.resolveTypeByLocation(this.uploadDialogLocation);
|
||||
};
|
||||
if (dictCode !== this.activeAttachmentTypeDictCode) {
|
||||
this.loadAttachmentTypeOptions(dictCode, false).finally(applyType);
|
||||
return;
|
||||
}
|
||||
applyType();
|
||||
},
|
||||
openUploadDialog() {
|
||||
const options = this.resolvedLocationOptions;
|
||||
@@ -544,13 +663,13 @@ export default {
|
||||
this.$message.warning('请选择附件类型');
|
||||
return;
|
||||
}
|
||||
const uploadUserName = this.$store.getters.userInfo?.realName || '';
|
||||
const uploadUserName = this.currentUploadUserName();
|
||||
const uploadTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
const appended = this.uploadDialogFiles.map(row => ({
|
||||
...row,
|
||||
fileType: this.uploadDialogType,
|
||||
description: row.description || '',
|
||||
uploadUserName: row.uploadUserName || uploadUserName,
|
||||
uploadUserName: uploadUserName || row.uploadUserName || '',
|
||||
uploadTime: row.uploadTime || uploadTime,
|
||||
...(this.markApprovedOnUpload ? { approved: true } : {}),
|
||||
}));
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
<el-col :span="6">
|
||||
<el-form-item label="单价">
|
||||
<el-input :model-value="freightGroupUnitPrice(group)" inputmode="decimal" placeholder="请输入" @input="value => handleFreightGroupUnitPriceInput(group, value)" @clear="() => handleFreightGroupUnitPriceInput(group, '')">
|
||||
<template #append><el-select :model-value="freightGroupPriceUnit(group)" class="freight-unit-select" @change="value => handleFreightGroupPriceUnitChange(group, value)"><el-option label="元/吨" value="元/吨" /><el-option label="元/件" value="元/件" /><el-option label="元/方" value="元/方" /></el-select></template>
|
||||
<template #append><el-select :model-value="freightGroupPriceUnit(group)" class="freight-unit-select" @change="value => handleFreightGroupPriceUnitChange(group, value)"><el-option v-for="item in priceUnitOptions(route)" :key="item.value" :label="item.label" :value="item.value" /></el-select></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -318,6 +318,11 @@
|
||||
import * as api from '@/api/business/master-order';
|
||||
import { fetchDriversByCarrierOrganizations } from '@/utils/carrier-org-resource';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import {
|
||||
currencyUnit,
|
||||
remapPriceUnitCurrency,
|
||||
resolvePriceUnitByQuantityUnit,
|
||||
} from '@/utils/currency';
|
||||
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||
import { isMobile } from '@/utils/validate';
|
||||
|
||||
@@ -429,8 +434,10 @@ export default {
|
||||
},
|
||||
async loadContractCurrency() {
|
||||
const directCurrency = this.master?.settlementCurrency || this.master?.settlementCurrencyCode || this.master?.currency;
|
||||
const previousCurrency = this.master?.settlementCurrency;
|
||||
if (!this.master?.projectId || !this.master?.contractId) {
|
||||
this.master.settlementCurrency = this.normalizeCurrencyValue(directCurrency || 'RMB');
|
||||
this.syncRouteCurrency(previousCurrency, this.master.settlementCurrency);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -444,6 +451,20 @@ export default {
|
||||
this.master.customerContractPartyB = '';
|
||||
this.master.settlementCurrency = 'RMB';
|
||||
}
|
||||
this.syncRouteCurrency(previousCurrency, this.master.settlementCurrency);
|
||||
},
|
||||
syncRouteCurrency(_previousCurrency, nextCurrency) {
|
||||
const currency = this.normalizeCurrencyValue(nextCurrency || 'RMB');
|
||||
(this.routes || []).forEach(route => {
|
||||
route.currency = currency;
|
||||
(route.freightItems || []).forEach(item => {
|
||||
if (item.priceUnit) {
|
||||
item.priceUnit = remapPriceUnitCurrency(item.priceUnit, currency);
|
||||
} else if (item.quantityUnit) {
|
||||
item.priceUnit = resolvePriceUnitByQuantityUnit(item.quantityUnit, currency);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
dispatchRouteNodes() {
|
||||
const routes = Array.isArray(this.master?.routes) ? this.master.routes : [];
|
||||
@@ -618,8 +639,23 @@ export default {
|
||||
const prices = (group.rows || []).map(item => String(item.unitPrice ?? '').trim()).filter(Boolean);
|
||||
return !prices.length || prices.some(price => price !== prices[0]) ? '' : prices[0];
|
||||
},
|
||||
freightGroupPriceUnit(group = {}) { return group.rows?.[0]?.priceUnit || (group.quantityUnit ? `元/${group.quantityUnit}` : ''); },
|
||||
freightGroupPriceUnit(group = {}) {
|
||||
if (group.rows?.[0]?.priceUnit) return group.rows[0].priceUnit;
|
||||
if (!group.quantityUnit) return '';
|
||||
return (
|
||||
resolvePriceUnitByQuantityUnit(group.quantityUnit, this.master?.settlementCurrency || 'RMB') ||
|
||||
`${currencyUnit(this.master?.settlementCurrency || 'RMB')}/${group.quantityUnit}`
|
||||
);
|
||||
},
|
||||
freightGroupAmount(group = {}) { return (group.rows || []).reduce((sum, item) => sum + this.freightAmount(item), 0); },
|
||||
priceUnitOptions(route = {}) {
|
||||
const unit = currencyUnit(route.currency || this.master?.settlementCurrency || 'RMB');
|
||||
return [
|
||||
{ label: `${unit}/吨`, value: `${unit}/吨` },
|
||||
{ label: `${unit}/件`, value: `${unit}/件` },
|
||||
{ label: `${unit}/方`, value: `${unit}/方` },
|
||||
];
|
||||
},
|
||||
handleFreightGroupUnitPriceInput(group, value) {
|
||||
const [integer = '', decimal = ''] = String(value || '').replace(/[^\d.]/g, '').split('.');
|
||||
const normalized = decimal || String(value || '').includes('.') ? `${integer}.${decimal.slice(0, 2)}` : integer;
|
||||
@@ -629,6 +665,10 @@ export default {
|
||||
handleFreightGroupQuantityUnitChange(route, group, value) {
|
||||
(group.rows || []).forEach(item => {
|
||||
item.quantityUnit = value || '';
|
||||
item.priceUnit = resolvePriceUnitByQuantityUnit(
|
||||
value,
|
||||
route.currency || this.master?.settlementCurrency || 'RMB'
|
||||
) || item.priceUnit;
|
||||
const goods = (route.goods || []).find(row => String(row.sourceIndex) === String(item.sourceIndex));
|
||||
if (goods) goods.quantityUnit = value || '';
|
||||
});
|
||||
@@ -651,7 +691,7 @@ export default {
|
||||
})),
|
||||
});
|
||||
},
|
||||
currencyLabel(value) { return ({ CNY: '元', RMB: '元', USD: '美元', EUR: '欧元' })[value] || value || '元'; },
|
||||
currencyLabel(value) { return currencyUnit(value); },
|
||||
quantityNumber(value) { return Number(value || 0); },
|
||||
goodsKey(goods = {}, includeUnit = true) {
|
||||
return [
|
||||
@@ -841,6 +881,7 @@ export default {
|
||||
removeGoods(route, index) { route.goods.splice(index, 1); this.syncFreightItems(route); },
|
||||
syncFreightItems(route) {
|
||||
const oldItems = route.freightItems || [];
|
||||
const currency = route.currency || this.master?.settlementCurrency || 'RMB';
|
||||
route.freightItems = (route.goods || [])
|
||||
.filter(item => item.sourceIndex !== undefined && item.sourceIndex !== '')
|
||||
.map(item => {
|
||||
@@ -852,7 +893,10 @@ export default {
|
||||
quantity: item.dispatchQuantity || '',
|
||||
quantityUnit: item.quantityUnit || '',
|
||||
unitPrice: old.unitPrice || '',
|
||||
priceUnit: old.priceUnit || `元/${item.quantityUnit || '吨'}`,
|
||||
priceUnit:
|
||||
old.priceUnit ||
|
||||
resolvePriceUnitByQuantityUnit(item.quantityUnit || '吨', currency) ||
|
||||
`${currencyUnit(currency)}/${item.quantityUnit || '吨'}`,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1744,11 +1744,11 @@
|
||||
><el-select
|
||||
:model-value="dispatchFreightGroupPriceUnit(group)"
|
||||
class="transport-plan-page__dispatch-unit-select"
|
||||
placeholder="元/吨"
|
||||
:placeholder="defaultPriceUnit"
|
||||
@change="value => handleDispatchFreightGroupPriceUnitChange(group, value)"
|
||||
@visible-change="visible => visible && loadTaskFeeUnitOptions()"
|
||||
><el-option
|
||||
v-for="item in taskFeeUnitOptions"
|
||||
v-for="item in taskFeeUnitSelectOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value" /></el-select
|
||||
@@ -1969,17 +1969,17 @@
|
||||
<el-select
|
||||
v-model="dispatchItemForm.priceUnit"
|
||||
class="transport-plan-page__dispatch-unit-select"
|
||||
placeholder="元/吨"
|
||||
:placeholder="defaultPriceUnit"
|
||||
:loading="taskFeeUnitLoading"
|
||||
@visible-change="visible => visible && loadTaskFeeUnitOptions()"
|
||||
>
|
||||
<el-option
|
||||
v-if="!taskFeeUnitOptions.some(item => item.value === '元/吨')"
|
||||
label="元/吨"
|
||||
value="元/吨"
|
||||
v-if="!taskFeeUnitSelectOptions.some(item => item.value === defaultPriceUnit)"
|
||||
:label="defaultPriceUnit"
|
||||
:value="defaultPriceUnit"
|
||||
/>
|
||||
<el-option
|
||||
v-for="item in taskFeeUnitOptions"
|
||||
v-for="item in taskFeeUnitSelectOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@@ -2741,6 +2741,12 @@ import { addressTypeOptions } from '@/option/base/common-address';
|
||||
import { packageOptions } from '@/option/business/common';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { getToken, isAdministrator } from '@/utils/auth';
|
||||
import {
|
||||
currencyUnit,
|
||||
mapFeeUnitOptions,
|
||||
remapPriceUnitCurrency,
|
||||
resolvePriceUnitByQuantityUnit,
|
||||
} from '@/utils/currency';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||
@@ -3612,6 +3618,22 @@ export default {
|
||||
const value = this.dispatchItemForm.freightCurrency || 'RMB';
|
||||
return this.currencyRemark(value);
|
||||
},
|
||||
taskFeeUnitSelectOptions() {
|
||||
const currency =
|
||||
this.dispatchItemForm.freightCurrency ||
|
||||
this.dispatchContractCurrency ||
|
||||
this.form.settlementCurrency ||
|
||||
'RMB';
|
||||
return mapFeeUnitOptions(this.taskFeeUnitOptions, currency);
|
||||
},
|
||||
defaultPriceUnit() {
|
||||
return `${currencyUnit(
|
||||
this.dispatchItemForm.freightCurrency ||
|
||||
this.dispatchContractCurrency ||
|
||||
this.form.settlementCurrency ||
|
||||
'RMB'
|
||||
)}/吨`;
|
||||
},
|
||||
isAdmin() {
|
||||
return isAdministrator(this.userInfo);
|
||||
},
|
||||
@@ -4806,19 +4828,49 @@ export default {
|
||||
contract.customerNames ||
|
||||
this.form.customerName ||
|
||||
'';
|
||||
const nextCurrency = this.getContractCurrency(contract);
|
||||
this.remapTransportPlanPriceUnits(nextCurrency);
|
||||
this.$refs.crud?.validateField?.('contractName');
|
||||
},
|
||||
remapTransportPlanPriceUnits(currency) {
|
||||
if (this.form.priceUnit) {
|
||||
this.form.priceUnit = remapPriceUnitCurrency(this.form.priceUnit, currency);
|
||||
}
|
||||
if (this.dispatchItemForm.priceUnit) {
|
||||
this.dispatchItemForm.priceUnit = remapPriceUnitCurrency(
|
||||
this.dispatchItemForm.priceUnit,
|
||||
currency
|
||||
);
|
||||
}
|
||||
this.dispatchItemForm.freightCurrency = currency;
|
||||
(this.dispatchItemCargoRows || []).forEach(cargo => {
|
||||
if (cargo.priceUnit) {
|
||||
cargo.priceUnit = remapPriceUnitCurrency(cargo.priceUnit, currency);
|
||||
}
|
||||
});
|
||||
(this.transportCargoRows || []).forEach(cargo => {
|
||||
if (cargo.priceUnit) {
|
||||
cargo.priceUnit = remapPriceUnitCurrency(cargo.priceUnit, currency);
|
||||
}
|
||||
});
|
||||
},
|
||||
loadDispatchContractCurrency(plan = {}) {
|
||||
const findContract = () =>
|
||||
this.contractOptions.find(item => String(item.id) === String(plan.contractId)) ||
|
||||
this.contractOptions.find(item => item.contractName === plan.contractName);
|
||||
const applyCurrency = contract => {
|
||||
const previousCurrency = this.dispatchContractCurrency;
|
||||
this.dispatchContractCurrency = this.getContractCurrency(
|
||||
contract &&
|
||||
(contract.settlementCurrency || contract.settlementCurrencyCode || contract.currency)
|
||||
? contract
|
||||
: { settlementCurrency: plan.settlementCurrency }
|
||||
);
|
||||
if (previousCurrency && previousCurrency !== this.dispatchContractCurrency) {
|
||||
this.remapTransportPlanPriceUnits(this.dispatchContractCurrency);
|
||||
} else {
|
||||
this.dispatchItemForm.freightCurrency = this.dispatchContractCurrency;
|
||||
}
|
||||
return this.dispatchContractCurrency;
|
||||
};
|
||||
const current = findContract();
|
||||
@@ -5217,7 +5269,7 @@ export default {
|
||||
},
|
||||
addTransportCargoRow(index = -1, row = {}) {
|
||||
const nextRow = this.normalizeTransportCargoRow({
|
||||
priceUnit: this.form.priceUnit || '元/吨',
|
||||
priceUnit: this.form.priceUnit || this.defaultPriceUnit,
|
||||
...row,
|
||||
});
|
||||
if (
|
||||
@@ -7680,7 +7732,10 @@ export default {
|
||||
this.dispatchItemCargoRows = this.dispatchItemCargoRows.map((cargo, itemIndex) => ({
|
||||
...cargo,
|
||||
unitPrice: cargo.unitPrice || freightInfo.freightItems[itemIndex]?.unitPrice || '',
|
||||
priceUnit: cargo.priceUnit || freightInfo.freightItems[itemIndex]?.priceUnit || '元/吨',
|
||||
priceUnit:
|
||||
cargo.priceUnit ||
|
||||
freightInfo.freightItems[itemIndex]?.priceUnit ||
|
||||
this.defaultPriceUnit,
|
||||
freightAmount:
|
||||
cargo.freightAmount || freightInfo.freightItems[itemIndex]?.freightAmount || '',
|
||||
}));
|
||||
@@ -7929,7 +7984,7 @@ export default {
|
||||
return value;
|
||||
},
|
||||
addDispatchCargoRow(index = -1) {
|
||||
const nextRow = this.normalizeTransportCargoRow({ priceUnit: '元/吨' });
|
||||
const nextRow = this.normalizeTransportCargoRow({ priceUnit: this.defaultPriceUnit });
|
||||
if (index > -1) this.dispatchItemCargoRows.splice(index + 1, 0, nextRow);
|
||||
else this.dispatchItemCargoRows.push(nextRow);
|
||||
},
|
||||
@@ -7973,7 +8028,14 @@ export default {
|
||||
return prices[0];
|
||||
},
|
||||
dispatchFreightGroupPriceUnit(group = {}) {
|
||||
return group.rows?.[0]?.priceUnit || (group.quantityUnit ? `元/${group.quantityUnit}` : '');
|
||||
if (group.rows?.[0]?.priceUnit) return group.rows[0].priceUnit;
|
||||
if (!group.quantityUnit) return '';
|
||||
return (
|
||||
resolvePriceUnitByQuantityUnit(
|
||||
group.quantityUnit,
|
||||
this.dispatchItemForm.freightCurrency || this.dispatchContractCurrency || 'RMB'
|
||||
) || `${currencyUnit(this.dispatchContractCurrency || 'RMB')}/${group.quantityUnit}`
|
||||
);
|
||||
},
|
||||
dispatchFreightGroupAmount(group = {}) {
|
||||
const amount = (group.rows || []).reduce(
|
||||
|
||||
@@ -270,15 +270,22 @@
|
||||
prop="mileage"
|
||||
label="里程(km)"
|
||||
width="100"
|
||||
/><el-table-column prop="unitPrice" label="单价" width="90" /><el-table-column
|
||||
prop="freight"
|
||||
label="运费"
|
||||
width="100"
|
||||
/><el-table-column prop="otherFeeTotal" label="其他费用合计" width="120" /><el-table-column
|
||||
prop="freightTotal"
|
||||
label="运费合计"
|
||||
width="100"
|
||||
/><el-table-column
|
||||
>
|
||||
<template #default="{ row }">{{ formatOptionalNumber(row.mileage) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="unitPrice" label="单价" width="90">
|
||||
<template #default="{ row }">{{ formatOptionalNumber(row.unitPrice) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="freight" label="运费" width="100">
|
||||
<template #default="{ row }">{{ formatOptionalNumber(row.freight) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="otherFeeTotal" label="其他费用合计" width="120">
|
||||
<template #default="{ row }">{{ formatOptionalNumber(row.otherFeeTotal) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="freightTotal" label="运费合计" width="100">
|
||||
<template #default="{ row }">{{ formatOptionalNumber(row.freightTotal) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="actualStartDate"
|
||||
label="实际发货时间"
|
||||
width="160"
|
||||
@@ -1107,7 +1114,7 @@ const loadDetails = async () => {
|
||||
current: detailPage.current,
|
||||
size: detailPage.size,
|
||||
});
|
||||
details.value = res.data?.data?.records || [];
|
||||
details.value = (res.data?.data?.records || []).map(normalizeDetailRow);
|
||||
detailPage.total = res.data?.data?.total || 0;
|
||||
};
|
||||
const openCreate = () => prepareCreateForm(true);
|
||||
@@ -1156,7 +1163,7 @@ const loadBatchRows = async batchId => {
|
||||
if (!batchId) return;
|
||||
const res = await api.getImportDetails({ batchId, current: 1, size: 9999 });
|
||||
rows.value = extractRecords(res).map(({ id, ...item }, index) => ({
|
||||
...item,
|
||||
...normalizeDetailRow(item),
|
||||
_key: `${id || 'row'}-${index}`,
|
||||
batchNo: item.batchNo || form.batchNo,
|
||||
}));
|
||||
@@ -1300,10 +1307,22 @@ const carrierChange = value => {
|
||||
};
|
||||
const firstNotEmpty = (...values) => values.find(value => String(value ?? '').trim()) ?? '';
|
||||
const OPTIONAL_NUMBER_EMPTY_SENTINELS = [-1];
|
||||
const OPTIONAL_NUMBER_PROPS = ['mileage', 'unitPrice', 'freight', 'otherFeeTotal', 'freightTotal'];
|
||||
const normalizeOptionalImportNumber = (value, emptySentinels = OPTIONAL_NUMBER_EMPTY_SENTINELS) => {
|
||||
if (!String(value ?? '').trim()) return null;
|
||||
return emptySentinels.some(sentinel => Number(value) === sentinel) ? null : value;
|
||||
};
|
||||
const formatOptionalNumber = value => {
|
||||
const normalized = normalizeOptionalImportNumber(value);
|
||||
return normalized === null || normalized === undefined ? '' : normalized;
|
||||
};
|
||||
const normalizeDetailRow = row => {
|
||||
const next = { ...(row || {}) };
|
||||
OPTIONAL_NUMBER_PROPS.forEach(prop => {
|
||||
next[prop] = formatOptionalNumber(next[prop]);
|
||||
});
|
||||
return next;
|
||||
};
|
||||
const normalizeImportRow = row => ({
|
||||
...row,
|
||||
mileage: normalizeOptionalImportNumber(
|
||||
|
||||
@@ -1083,7 +1083,7 @@
|
||||
@visible-change="visible => visible && loadTaskFeeUnitOptions()"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in taskFeeUnitOptions"
|
||||
v-for="item in taskFeeUnitSelectOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@@ -1416,7 +1416,7 @@
|
||||
@visible-change="visible => visible && loadTaskFeeUnitOptions()"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in taskFeeUnitOptions"
|
||||
v-for="item in taskFeeUnitSelectOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@@ -3642,6 +3642,12 @@ import { addressTypeOptions } from '@/option/base/common-address';
|
||||
import { packageOptions } from '@/option/business/common';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { getToken, isAdministrator } from '@/utils/auth';
|
||||
import {
|
||||
currencyUnit,
|
||||
mapFeeUnitOptions,
|
||||
remapPriceUnitCurrency,
|
||||
resolvePriceUnitByQuantityUnit,
|
||||
} from '@/utils/currency';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { wgs84ToGcj02 } from '@/utils/coordinate';
|
||||
import { openImportDialog } from '@/utils/import-excel';
|
||||
@@ -4185,6 +4191,8 @@ export default {
|
||||
},
|
||||
selectionList: [],
|
||||
attachmentUploadMode: false,
|
||||
/** 复制来源运单业务状态(表单字段 addDisplay:false,提交时需显式带回) */
|
||||
copySourceBusinessStatus: '',
|
||||
standaloneFormKey: '',
|
||||
// 实例所属路由的路径快照:用于判断当前 $route 是否还是「本实例自己的路由」。
|
||||
// 必须在 data 里初始化,不能放 created —— Vue 的 Options API 执行顺序是
|
||||
@@ -4581,6 +4589,12 @@ export default {
|
||||
if (!currency) return '';
|
||||
return this.currencyRemark(currency);
|
||||
},
|
||||
taskFeeUnitSelectOptions() {
|
||||
return mapFeeUnitOptions(this.taskFeeUnitOptions, this.taskFreightCurrency || 'RMB');
|
||||
},
|
||||
defaultPriceUnit() {
|
||||
return `${currencyUnit(this.taskFreightCurrency || 'RMB')}/吨`;
|
||||
},
|
||||
isAdmin() {
|
||||
return isAdministrator(this.userInfo);
|
||||
},
|
||||
@@ -5175,7 +5189,7 @@ export default {
|
||||
quantity: goods.quantity ?? goods.cargoQuantity ?? goods.goodsQuantity ?? '',
|
||||
quantityUnit: goods.quantityUnit || goods.goodsQuantityUnit || goods.unit || '吨',
|
||||
unitPrice: goods.unitPrice,
|
||||
priceUnit: goods.priceUnit || '元/吨',
|
||||
priceUnit: goods.priceUnit || this.defaultPriceUnit,
|
||||
});
|
||||
},
|
||||
canOperation(operation, row) {
|
||||
@@ -6477,6 +6491,18 @@ export default {
|
||||
if (isAddMode) {
|
||||
delete submitRow.id;
|
||||
delete submitRow.waybillNo;
|
||||
// 复制提交:状态列未进表单,Avue 可能不带回;显式保留原运单业务状态(含已完成)
|
||||
const copyId = this.$route.query.copyId || '';
|
||||
if (copyId && !saveAsDraft) {
|
||||
const copiedStatus =
|
||||
this.form?.businessStatus ||
|
||||
this.copySourceBusinessStatus ||
|
||||
submitRow.businessStatus ||
|
||||
'';
|
||||
if (copiedStatus) {
|
||||
submitRow.businessStatus = copiedStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
const skipValidation = saveAsDraft && this.config.skipDraftValidation === true;
|
||||
if (
|
||||
@@ -6596,7 +6622,29 @@ export default {
|
||||
selected?.currency ||
|
||||
this.form.settlementCurrency ||
|
||||
'RMB';
|
||||
this.taskFreightCurrency = this.normalizeFreightCurrency(value);
|
||||
const nextCurrency = this.normalizeFreightCurrency(value);
|
||||
const previousCurrency = this.taskFreightCurrency;
|
||||
this.taskFreightCurrency = nextCurrency;
|
||||
if (previousCurrency && previousCurrency !== nextCurrency) {
|
||||
this.remapWaybillPriceUnits(nextCurrency);
|
||||
}
|
||||
},
|
||||
remapWaybillPriceUnits(currency) {
|
||||
if (this.form.priceUnit) {
|
||||
this.form.priceUnit = remapPriceUnitCurrency(this.form.priceUnit, currency);
|
||||
}
|
||||
(this.transportCargoRows || []).forEach(cargo => {
|
||||
if (cargo.priceUnit) {
|
||||
cargo.priceUnit = remapPriceUnitCurrency(cargo.priceUnit, currency);
|
||||
}
|
||||
});
|
||||
(this.taskFreightGroups || []).forEach(group => {
|
||||
(group.rows || []).forEach(row => {
|
||||
if (row.priceUnit) {
|
||||
row.priceUnit = remapPriceUnitCurrency(row.priceUnit, currency);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
loadFreightCurrencyOptions() {
|
||||
if (this.freightCurrencyOptions.length || this.freightCurrencyLoading) {
|
||||
@@ -6880,6 +6928,8 @@ export default {
|
||||
if (type === 'add' && copyId) {
|
||||
this.api.getDetail(copyId).then(res => {
|
||||
const sourceData = res.data.data || {};
|
||||
// 原运单业务状态(如 completed)提交时需原样带回并生成应收应付
|
||||
this.copySourceBusinessStatus = sourceData.businessStatus || '';
|
||||
// 清除不应该复制的字段(业务状态与原运单保持一致)
|
||||
delete sourceData.id;
|
||||
delete sourceData.code;
|
||||
@@ -6901,14 +6951,18 @@ export default {
|
||||
delete sourceData.updateUserName;
|
||||
|
||||
this.applyFormDetail(sourceData);
|
||||
// 标记为手工创建;业务状态沿用原运单
|
||||
// 标记为手工创建;业务状态沿用原运单(含已完成)
|
||||
this.form.dataSource = '手工创建';
|
||||
if (this.copySourceBusinessStatus) {
|
||||
this.form.businessStatus = this.copySourceBusinessStatus;
|
||||
}
|
||||
done();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'add') {
|
||||
this.copySourceBusinessStatus = '';
|
||||
this.form = {
|
||||
...(this.config.defaultForm || {}),
|
||||
};
|
||||
@@ -7382,7 +7436,7 @@ export default {
|
||||
if (this.isSentinelMinusOne(this.form[prop])) this.form[prop] = '';
|
||||
});
|
||||
this.form.priceUnit =
|
||||
this.form.priceUnit || taskInfo.priceUnit || goodsInfo.priceUnit || '元/吨';
|
||||
this.form.priceUnit || taskInfo.priceUnit || goodsInfo.priceUnit || this.defaultPriceUnit;
|
||||
this.form.otherFeeTotal = this.normalizeOptionalAmount(
|
||||
this.form.otherFeeTotal || taskInfo.otherFeeTotal || goodsInfo.otherFeeTotal || ''
|
||||
);
|
||||
@@ -8095,7 +8149,7 @@ export default {
|
||||
if (index === 0 && !cargo.unitPrice && this.form.unitPrice) {
|
||||
cargo.unitPrice = this.form.unitPrice;
|
||||
}
|
||||
cargo.priceUnit = cargo.priceUnit || this.form.priceUnit || '元/吨';
|
||||
cargo.priceUnit = cargo.priceUnit || this.form.priceUnit || this.defaultPriceUnit;
|
||||
if (this.isBillingFieldEmpty(cargo.freightAmount)) {
|
||||
cargo.freightAmount = this.normalizeOptionalAmount(
|
||||
freightItems[index]?.freightAmount ?? ''
|
||||
@@ -8477,7 +8531,7 @@ export default {
|
||||
},
|
||||
addTransportCargoRow(index = -1, row = {}) {
|
||||
const nextRow = this.normalizeTransportCargoRow({
|
||||
priceUnit: this.form.priceUnit || '元/吨',
|
||||
priceUnit: this.form.priceUnit || this.defaultPriceUnit,
|
||||
...row,
|
||||
});
|
||||
if (
|
||||
@@ -8524,12 +8578,9 @@ export default {
|
||||
this.syncTransportCargoJson();
|
||||
},
|
||||
resolvePriceUnitByQuantityUnit(quantityUnit) {
|
||||
return (
|
||||
{
|
||||
吨: '元/吨',
|
||||
方: '元/立方',
|
||||
件: '元/件',
|
||||
}[String(quantityUnit || '').trim()] || ''
|
||||
return resolvePriceUnitByQuantityUnit(
|
||||
quantityUnit,
|
||||
this.taskFreightCurrency || this.form.settlementCurrency || 'RMB'
|
||||
);
|
||||
},
|
||||
handleTransportCargoQuantityUnitChange(quantityUnit) {
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<el-form-item label="项目">
|
||||
<el-input v-model="form.projectName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="所属组织">
|
||||
<el-form-item label="合同负责部门">
|
||||
<el-input v-model="form.organizationName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="甲方">
|
||||
@@ -63,6 +63,15 @@
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请日期">
|
||||
<el-date-picker
|
||||
v-model="form.applyDate"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同期限">
|
||||
<div class="contract-basic-section__date-range">
|
||||
<el-date-picker
|
||||
@@ -91,7 +100,7 @@
|
||||
<template #suffix>天</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额">
|
||||
<el-form-item label="合同金额" prop="contractAmount">
|
||||
<el-input
|
||||
:model-value="contractAmountDisplay"
|
||||
placeholder="请输入"
|
||||
@@ -154,7 +163,7 @@
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要加盖法人章">
|
||||
<el-select v-model="form.legalSealFlag" placeholder="请选择">
|
||||
<el-select v-model="form.legalSealFlag" placeholder="请选择" clearable>
|
||||
<el-option label="否" :value="0" />
|
||||
<el-option label="是" :value="1" />
|
||||
</el-select>
|
||||
@@ -173,20 +182,30 @@
|
||||
<el-input v-model="form.handlerUserName" disabled />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="备注" class="contract-basic-section__remark">
|
||||
<el-form-item label="合同主要内容" class="contract-basic-section__remark">
|
||||
<el-input
|
||||
v-model="form.mainContent"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
maxlength="1000"
|
||||
show-word-limit
|
||||
placeholder="请输入合同主要内容"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他事项说明" class="contract-basic-section__remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
placeholder="请输入备注"
|
||||
placeholder="请输入其他事项说明"
|
||||
/>
|
||||
</el-form-item>
|
||||
</section>
|
||||
|
||||
<contract-attachment-section
|
||||
title="合同文件"
|
||||
title="用印材料"
|
||||
description
|
||||
attachment-type
|
||||
:attachment-location-options="changeAttachmentLocationOptions"
|
||||
@@ -251,13 +270,20 @@
|
||||
<el-button type="primary" plain @click="addPaymentRatioRow">添加</el-button>
|
||||
</section>
|
||||
|
||||
<billing-plan-editor v-model="planDialogVisible" :value="planEditor" :index="planEditorIndex" @save="savePlan" />
|
||||
<billing-plan-editor
|
||||
v-model="planDialogVisible"
|
||||
:value="planEditor"
|
||||
:index="planEditorIndex"
|
||||
:settlement-currency="form.settlementCurrency"
|
||||
@save="savePlan"
|
||||
/>
|
||||
|
||||
<contract-attachment-section
|
||||
title="其它附件"
|
||||
title="附件(佐证材料等)"
|
||||
description
|
||||
attachment-type
|
||||
attachment-location="其它附件"
|
||||
attachment-location="附件(佐证材料等)"
|
||||
attachment-type-dict-code="contract_supporting_attachment_type"
|
||||
:attachment-location-options="changeAttachmentLocationOptions"
|
||||
:rows="attachments"
|
||||
:preview="previewAttachment"
|
||||
@@ -308,6 +334,8 @@ import * as api from '@/api/business/contract-manage';
|
||||
import { submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
||||
import ContractAttachmentSection, {
|
||||
isContractSealMaterialLocation,
|
||||
isContractSupportingAttachmentLocation,
|
||||
normalizeContractFileRows,
|
||||
} from './components/contract-attachment-section.vue';
|
||||
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
||||
@@ -424,6 +452,21 @@ export default {
|
||||
],
|
||||
rules: {
|
||||
contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
||||
contractAmount: [
|
||||
{ required: true, message: '请输入合同金额', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return callback(new Error('请输入合同金额'));
|
||||
}
|
||||
if (Number(value) < 0) {
|
||||
return callback(new Error('合同金额不能小于0'));
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
changeReason: [{ max: 500, message: '变更原因不能超过500个字符', trigger: 'blur' }],
|
||||
},
|
||||
};
|
||||
@@ -433,7 +476,7 @@ export default {
|
||||
return this.$route.query.name || '合同变更';
|
||||
},
|
||||
changeAttachmentLocationOptions() {
|
||||
return ['合同文件', '其它附件', '变更材料'];
|
||||
return ['用印材料', '附件(佐证材料等)', '变更材料'];
|
||||
},
|
||||
contractAmountDisplay() {
|
||||
const value = this.form.contractAmount;
|
||||
@@ -601,7 +644,7 @@ export default {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
// 审核通过后上一次的变更材料归集到「其它附件」,按文件地址/文件名去重,避免重复展示
|
||||
// 审核通过后上一次的变更材料归集到「附件(佐证材料等)」,按文件地址/文件名去重,避免重复展示
|
||||
mergeChangeAttachments(attachments = [], changeAttachments = []) {
|
||||
const key = item => this.attachmentUrl(item) || this.attachmentName(item);
|
||||
const exists = new Set(attachments.map(key));
|
||||
@@ -655,11 +698,11 @@ export default {
|
||||
previewAttachment(row, rows = this.attachments) { const url = this.attachmentUrl(row); if (!url) { this.$message.warning('附件地址为空,无法预览'); return; } if (this.isAttachmentImage(row)) { this.imagePreviewUrls = (rows || []).filter(item => this.isAttachmentImage(item) && this.attachmentUrl(item)).map(item => this.attachmentUrl(item)); this.imagePreviewIndex = Math.max(this.imagePreviewUrls.indexOf(url), 0); this.imagePreviewVisible = true; return; } this.previewFile = { name: this.attachmentName(row), url, mimeType: row.mimeType || row.contentType || '' }; this.documentPreviewVisible = true; },
|
||||
handleAttachmentUploadToLocation({ location, rows = [] }) {
|
||||
if (!rows.length) return;
|
||||
if (location === '合同文件') {
|
||||
if (isContractSealMaterialLocation(location)) {
|
||||
this.contractFileRows = [...(this.contractFileRows || []), ...rows];
|
||||
return;
|
||||
}
|
||||
if (location === '其它附件') {
|
||||
if (isContractSupportingAttachmentLocation(location)) {
|
||||
this.attachments = [...(this.attachments || []), ...rows];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
<el-descriptions-item label="甲方">{{ detailValue('partyA') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="乙方">{{ detailValue('partyB') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同期限">{{ detailContractPeriod }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所属组织">{{
|
||||
<el-descriptions-item label="合同负责部门">{{
|
||||
detailValue('organizationName')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="经办人">{{
|
||||
@@ -140,6 +140,9 @@
|
||||
<el-descriptions-item label="签订日期">{{
|
||||
detailValue('signDate')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请日期">{{
|
||||
detailValue('applyDate')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同格式">{{
|
||||
detailValue('contractFormat')
|
||||
}}</el-descriptions-item>
|
||||
@@ -171,14 +174,17 @@
|
||||
<el-descriptions-item label="是否电子章">
|
||||
{{ detailElectronicSealText }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="3">{{
|
||||
<el-descriptions-item label="合同主要内容" :span="3">{{
|
||||
detailValue('mainContent')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="其他事项说明" :span="3">{{
|
||||
detailValue('remark')
|
||||
}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
|
||||
<contract-attachment-section
|
||||
title="合同文件"
|
||||
title="用印材料"
|
||||
description
|
||||
attachment-type
|
||||
readonly
|
||||
@@ -294,7 +300,7 @@
|
||||
</section>
|
||||
|
||||
<contract-attachment-section
|
||||
title="其它附件"
|
||||
title="附件(佐证材料等)"
|
||||
description
|
||||
readonly
|
||||
:rows="detailAttachmentRows"
|
||||
@@ -377,8 +383,14 @@
|
||||
<el-form-item label="合同编号">
|
||||
<el-input
|
||||
v-model="form.contractNo"
|
||||
:disabled="formMode === 'edit'"
|
||||
placeholder="不填写,则系统自动生成"
|
||||
disabled
|
||||
:placeholder="
|
||||
formMode === 'add'
|
||||
? form.organizationId
|
||||
? '系统按部门规则自动生成'
|
||||
: '请先选择合同负责部门'
|
||||
: ''
|
||||
"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同名称" prop="contractName">
|
||||
@@ -417,7 +429,7 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属组织" prop="organizationName">
|
||||
<el-form-item label="合同负责部门" prop="organizationName">
|
||||
<el-cascader
|
||||
v-model="organizationCascaderValue"
|
||||
:options="organizationOptions"
|
||||
@@ -471,6 +483,16 @@
|
||||
placeholder="请选择签订日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请日期">
|
||||
<el-date-picker
|
||||
v-model="form.applyDate"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="提交正式合同时自动填充"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同期限" prop="startDate">
|
||||
<div class="contract-manage-form__date-range">
|
||||
<el-date-picker
|
||||
@@ -497,7 +519,7 @@
|
||||
@input="value => integerInput('paymentDays', value)"
|
||||
><template #suffix>天</template></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额">
|
||||
<el-form-item label="合同金额" prop="contractAmount">
|
||||
<el-input
|
||||
:model-value="contractAmountDisplay"
|
||||
placeholder="请输入"
|
||||
@@ -557,7 +579,7 @@
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否需要加盖法人章" prop="legalSealFlag">
|
||||
<el-select v-model="form.legalSealFlag" placeholder="请选择">
|
||||
<el-select v-model="form.legalSealFlag" placeholder="请选择" clearable>
|
||||
<el-option label="否" :value="0" />
|
||||
<el-option label="是" :value="1" />
|
||||
</el-select>
|
||||
@@ -576,20 +598,30 @@
|
||||
<el-input v-model="form.handlerUserName" disabled />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="备注" prop="remark" class="contract-manage-form__remark">
|
||||
<el-form-item label="合同主要内容" prop="mainContent" class="contract-manage-form__remark">
|
||||
<el-input
|
||||
v-model="form.mainContent"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
maxlength="1000"
|
||||
show-word-limit
|
||||
placeholder="请输入合同主要内容"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他事项说明" prop="remark" class="contract-manage-form__remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
placeholder="请输入备注"
|
||||
placeholder="请输入其他事项说明"
|
||||
/>
|
||||
</el-form-item>
|
||||
</section>
|
||||
|
||||
<contract-attachment-section
|
||||
title="合同文件"
|
||||
title="用印材料"
|
||||
description
|
||||
attachment-type
|
||||
:attachment-location-options="contractAttachmentLocationOptions"
|
||||
@@ -809,10 +841,11 @@
|
||||
</section>
|
||||
|
||||
<contract-attachment-section
|
||||
title="其它附件"
|
||||
title="附件(佐证材料等)"
|
||||
description
|
||||
attachment-type
|
||||
attachment-location="其它附件"
|
||||
attachment-location="附件(佐证材料等)"
|
||||
attachment-type-dict-code="contract_supporting_attachment_type"
|
||||
:attachment-location-options="contractAttachmentLocationOptions"
|
||||
:readonly="isAttachmentUploadMode"
|
||||
:rows="attachmentRows"
|
||||
@@ -920,18 +953,19 @@
|
||||
v-model="billingPlanBox"
|
||||
:value="billingPlanForm"
|
||||
:index="billingPlanIndex"
|
||||
:settlement-currency="form.settlementCurrency"
|
||||
@save="saveBillingPlan"
|
||||
/>
|
||||
|
||||
<contract-attachment-section
|
||||
ref="listAttachmentUploader"
|
||||
dialog-only
|
||||
title="合同文件"
|
||||
title="用印材料"
|
||||
description
|
||||
attachment-type
|
||||
use-upload-dialog
|
||||
mark-approved-on-upload
|
||||
:attachment-location-options="['合同文件', '其它附件']"
|
||||
:attachment-location-options="['用印材料', '附件(佐证材料等)']"
|
||||
:rows="listUploadContractFileRows"
|
||||
@update:rows="listUploadContractFileRows = $event"
|
||||
@upload-to-location="handleListAttachmentUploadToLocation"
|
||||
@@ -988,6 +1022,7 @@
|
||||
v-model="detailBillingPlanBox"
|
||||
:value="detailBillingPlanForm"
|
||||
:index="detailBillingPlanIndex"
|
||||
:settlement-currency="detail.settlementCurrency || form.settlementCurrency"
|
||||
readonly
|
||||
/>
|
||||
|
||||
@@ -1026,6 +1061,8 @@ import ChangeRecordDetailDialog from '@/components/change-record-detail-dialog/m
|
||||
import ContractAttachmentSection, {
|
||||
attachmentName as sharedAttachmentName,
|
||||
attachmentUrl as sharedAttachmentUrl,
|
||||
isContractSealMaterialLocation,
|
||||
isContractSupportingAttachmentLocation,
|
||||
normalizeContractFileRows,
|
||||
} from './components/contract-attachment-section.vue';
|
||||
import PdfPreview from '@/components/pdf-preview/main.vue';
|
||||
@@ -1093,8 +1130,9 @@ const defaultForm = () => ({
|
||||
partyB: '',
|
||||
handlerUserName: '',
|
||||
signDate: '',
|
||||
applyDate: '',
|
||||
contractFormat: '',
|
||||
legalSealFlag: 0,
|
||||
legalSealFlag: null,
|
||||
copyCount: '',
|
||||
settlementCurrency: '',
|
||||
invoiceCycle: '',
|
||||
@@ -1110,6 +1148,7 @@ const defaultForm = () => ({
|
||||
effectiveType: '',
|
||||
feeGenerationMode: 'system',
|
||||
archiveStatus: '未归档',
|
||||
mainContent: '',
|
||||
remark: '',
|
||||
});
|
||||
// 复制新增:仅保留可编辑字段与明细,剔除主键、编号、审批与流程信息
|
||||
@@ -1121,6 +1160,7 @@ const createCopiedDetail = (detail = {}) => {
|
||||
return {
|
||||
...form,
|
||||
contractNo: '',
|
||||
applyDate: '',
|
||||
archiveStatus: '未归档',
|
||||
feeGenerationMode: detail.feeGenerationMode || '',
|
||||
billingEnabled: detail.billingEnabled,
|
||||
@@ -1215,13 +1255,12 @@ export default {
|
||||
signType: [{ required: true, message: '请选择签约类型', trigger: 'change' }],
|
||||
settlementCurrency: [{ required: true, message: '请选择结算币种', trigger: 'change' }],
|
||||
projectName: [{ required: true, message: '请选择所属项目', trigger: 'change' }],
|
||||
organizationName: [{ required: true, message: '请选择所属组织', trigger: 'change' }],
|
||||
organizationName: [{ required: true, message: '请选择合同负责部门', trigger: 'change' }],
|
||||
partyA: [{ required: true, message: '请选择甲方', trigger: 'change' }],
|
||||
partyB: [{ required: true, message: '请选择乙方', trigger: 'change' }],
|
||||
signDate: [{ required: true, message: '请选择签订日期', trigger: 'change' }],
|
||||
settlementMode: [{ required: true, message: '请选择结算方式', trigger: 'change' }],
|
||||
contractFormat: [{ required: true, message: '请选择合同格式', trigger: 'change' }],
|
||||
legalSealFlag: [{ required: true, message: '请选择是否需要加盖法人章', trigger: 'change' }],
|
||||
invoiceCycle: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
@@ -1236,6 +1275,22 @@ export default {
|
||||
],
|
||||
startDate: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
|
||||
endDate: [{ required: true, message: '请选择结束日期', trigger: 'change' }],
|
||||
contractAmount: [
|
||||
{ required: true, message: '请输入合同金额', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return callback(new Error('请输入合同金额'));
|
||||
}
|
||||
if (Number(value) < 0) {
|
||||
return callback(new Error('合同金额不能小于0'));
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
mainContent: [{ max: 1000, message: '合同主要内容不能超过1000个字符', trigger: 'blur' }],
|
||||
},
|
||||
submitAction: '',
|
||||
projectOptions: [],
|
||||
@@ -1345,8 +1400,8 @@ export default {
|
||||
return this.$route.query.attachmentUpload === '1';
|
||||
},
|
||||
contractAttachmentLocationOptions() {
|
||||
if (this.isAttachmentUploadMode) return ['合同文件'];
|
||||
return ['合同文件', '其它附件'];
|
||||
if (this.isAttachmentUploadMode) return ['用印材料'];
|
||||
return ['用印材料', '附件(佐证材料等)'];
|
||||
},
|
||||
contractAmountDisplay() {
|
||||
const value = this.form.contractAmount;
|
||||
@@ -1413,7 +1468,7 @@ export default {
|
||||
expandTrigger: 'click',
|
||||
};
|
||||
},
|
||||
// 所属组织级联:selectedOrganizationId 存部门 id,级联控件用根到节点的 id 路径,
|
||||
// 合同负责部门级联:selectedOrganizationId 存部门 id,级联控件用根到节点的 id 路径,
|
||||
// 两者在此双向转换;依赖 organizationOptions,树加载完成后回显自动刷新
|
||||
organizationCascaderValue: {
|
||||
get() {
|
||||
@@ -1775,6 +1830,7 @@ export default {
|
||||
this.applyDetail(createCopiedDetail(detail));
|
||||
this.form.handlerUserName =
|
||||
this.userInfo?.realName || this.userInfo?.userName || this.userInfo?.account || '';
|
||||
this.refreshPreviewContractNo();
|
||||
this.$nextTick(() => this.$refs.contractForm?.clearValidate());
|
||||
},
|
||||
closeForm() {
|
||||
@@ -1789,9 +1845,10 @@ export default {
|
||||
['contractName', '合同名称'],
|
||||
['contractCategory', '合同类型'],
|
||||
['projectName', '所属项目'],
|
||||
['organizationName', '所属组织'],
|
||||
['organizationName', '合同负责部门'],
|
||||
['partyA', '甲方'],
|
||||
['partyB', '乙方'],
|
||||
['contractAmount', '合同金额'],
|
||||
];
|
||||
const empty = required.find(([prop]) => {
|
||||
const value = this.form[prop];
|
||||
@@ -1799,10 +1856,16 @@ export default {
|
||||
});
|
||||
if (empty) {
|
||||
this.$message.warning(
|
||||
empty[0] === 'contractName' ? `请输入${empty[1]}` : `请选择${empty[1]}`
|
||||
['contractName', 'contractAmount'].includes(empty[0])
|
||||
? `请输入${empty[1]}`
|
||||
: `请选择${empty[1]}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (Number(this.form.contractAmount) < 0) {
|
||||
this.$message.warning('合同金额不能小于0');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!this.form.contractName?.trim()) {
|
||||
@@ -1825,7 +1888,7 @@ export default {
|
||||
if (action !== 'formal' && action !== 'edit') return true;
|
||||
const required = [
|
||||
['projectName', '所属项目'],
|
||||
['organizationName', '所属组织'],
|
||||
['organizationName', '合同负责部门'],
|
||||
['partyA', '甲方'],
|
||||
['partyB', '乙方'],
|
||||
['startDate', '合同开始日期'],
|
||||
@@ -1833,10 +1896,20 @@ export default {
|
||||
['signDate', '签订日期'],
|
||||
['settlementMode', '结算方式'],
|
||||
['contractFormat', '合同格式'],
|
||||
['contractAmount', '合同金额'],
|
||||
];
|
||||
const empty = required.find(([prop]) => !this.form[prop]);
|
||||
const empty = required.find(([prop]) => {
|
||||
const value = this.form[prop];
|
||||
return value === undefined || value === null || String(value).trim() === '';
|
||||
});
|
||||
if (empty) {
|
||||
this.$message.warning(`请选择或输入${empty[1]}`);
|
||||
this.$message.warning(
|
||||
empty[0] === 'contractAmount' ? `请输入${empty[1]}` : `请选择或输入${empty[1]}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (Number(this.form.contractAmount) < 0) {
|
||||
this.$message.warning('合同金额不能小于0');
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
@@ -2026,11 +2099,11 @@ export default {
|
||||
},
|
||||
handleListAttachmentUploadToLocation({ location, rows = [] }) {
|
||||
if (!rows.length) return;
|
||||
if (location === '合同文件') {
|
||||
if (isContractSealMaterialLocation(location)) {
|
||||
this.listUploadContractFileRows = [...(this.listUploadContractFileRows || []), ...rows];
|
||||
return;
|
||||
}
|
||||
if (location === '其它附件') {
|
||||
if (isContractSupportingAttachmentLocation(location)) {
|
||||
this.listUploadAttachmentRows = [...(this.listUploadAttachmentRows || []), ...rows];
|
||||
}
|
||||
},
|
||||
@@ -2150,6 +2223,9 @@ export default {
|
||||
column.renderSearch = scope => this.renderOrganizationSearch(scope);
|
||||
}
|
||||
this.syncCurrentOrganizationOption();
|
||||
if (this.isFormPage && this.formMode === 'add' && this.form.organizationId) {
|
||||
this.refreshPreviewContractNo();
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.organizationLoading = false;
|
||||
@@ -2212,6 +2288,29 @@ export default {
|
||||
}
|
||||
: { organizationId: '', organizationName: '' }
|
||||
);
|
||||
if (this.formMode === 'add') {
|
||||
this.refreshPreviewContractNo();
|
||||
}
|
||||
},
|
||||
refreshPreviewContractNo() {
|
||||
if (this.formMode !== 'add') return;
|
||||
const organizationId = this.form.organizationId;
|
||||
if (!organizationId) {
|
||||
this.form.contractNo = '';
|
||||
return;
|
||||
}
|
||||
const requestId = (this.contractNoPreviewRequestId =
|
||||
(this.contractNoPreviewRequestId || 0) + 1);
|
||||
api
|
||||
.nextContractNo(organizationId)
|
||||
.then(res => {
|
||||
if (requestId !== this.contractNoPreviewRequestId) return;
|
||||
this.form.contractNo = res.data?.data || '';
|
||||
})
|
||||
.catch(() => {
|
||||
if (requestId !== this.contractNoPreviewRequestId) return;
|
||||
this.form.contractNo = '';
|
||||
});
|
||||
},
|
||||
syncCurrentOrganizationOption() {
|
||||
if (!this.form.organizationId || !this.form.organizationName) return;
|
||||
@@ -2225,7 +2324,7 @@ export default {
|
||||
this.organizationFlatOptions.unshift(item);
|
||||
},
|
||||
renderOrganizationSearch(scope) {
|
||||
// 搜索区所属组织:单选级联(与新增/编辑表单一致)
|
||||
// 搜索区合同负责部门:单选级联(与新增/编辑表单一致)
|
||||
// 级联返回 id 路径数组,提交时由 normalizeSearch 取末级 id 转组织名称
|
||||
return h(ElCascader, {
|
||||
modelValue: Array.isArray(scope.row?.organizationName) ? scope.row.organizationName : [],
|
||||
@@ -2244,7 +2343,7 @@ export default {
|
||||
filterable: true,
|
||||
clearable: true,
|
||||
style: 'width: 100%',
|
||||
placeholder: '请选择 所属组织',
|
||||
placeholder: '请选择 合同负责部门',
|
||||
});
|
||||
},
|
||||
integerInput(prop, value) {
|
||||
@@ -2289,11 +2388,11 @@ export default {
|
||||
},
|
||||
handleAttachmentUploadToLocation({ location, rows = [] }) {
|
||||
if (!rows.length) return;
|
||||
if (location === '合同文件') {
|
||||
if (isContractSealMaterialLocation(location)) {
|
||||
this.contractFileRows = [...(this.contractFileRows || []), ...rows];
|
||||
return;
|
||||
}
|
||||
if (location === '其它附件') {
|
||||
if (isContractSupportingAttachmentLocation(location)) {
|
||||
this.attachmentRows = [...(this.attachmentRows || []), ...rows];
|
||||
}
|
||||
},
|
||||
@@ -2654,15 +2753,16 @@ export default {
|
||||
templateFlag: '是否范本',
|
||||
originalContractNo: '原件合同编号',
|
||||
electronicSealFlag: '是否电子章',
|
||||
remark: '备注',
|
||||
mainContent: '合同主要内容',
|
||||
remark: '其他事项说明',
|
||||
feeGenerationMode: '费用生成模式',
|
||||
billingPlanJson: '计费方案',
|
||||
settlementRuleJson: '结算单规则',
|
||||
preSettlementConfigJson: '预结算配置',
|
||||
formalSettlementConfigJson: '正式结算配置',
|
||||
paymentRatioJson: '付款比例设置',
|
||||
contractFileJson: '合同文件',
|
||||
attachmentsJson: '其它附件',
|
||||
contractFileJson: '用印材料',
|
||||
attachmentsJson: '附件(佐证材料等)',
|
||||
changeAttachmentsJson: '变更材料',
|
||||
};
|
||||
return labels[field] || field;
|
||||
|
||||
Reference in New Issue
Block a user