1、修复基础配置
2、修复业务模块 3、拆分页面代码
This commit is contained in:
@@ -2265,7 +2265,7 @@
|
||||
</div>
|
||||
<div class="business-crud-page__transport-plan-detail-field">
|
||||
<span>合同编号</span>
|
||||
<strong>{{ detailRow.contractNo || detailRow.contractName || '-' }}</strong>
|
||||
<strong>{{ detailRow.contractNo || '-' }}</strong>
|
||||
</div>
|
||||
<div class="business-crud-page__transport-plan-detail-field">
|
||||
<span>货物信息</span>
|
||||
@@ -3339,7 +3339,7 @@
|
||||
<div class="business-crud-page__dispatch-summary-item">
|
||||
<div class="business-crud-page__dispatch-summary-label">合同编号</div>
|
||||
<div class="business-crud-page__dispatch-summary-value">
|
||||
{{ dispatchRow.contractName || dispatchRow.contractNo || '-' }}
|
||||
{{ dispatchRow.contractNo || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="business-crud-page__dispatch-summary-item">
|
||||
@@ -3389,7 +3389,11 @@
|
||||
{{ parseDispatchRoutePoint(dispatchRow, 'start').name || '-' }}
|
||||
</div>
|
||||
<div class="business-crud-page__dispatch-route-address">
|
||||
{{ parseDispatchRoutePoint(dispatchRow, 'start').address || '-' }}
|
||||
{{
|
||||
formatTransportPlanProvinceCityDistrict(
|
||||
parseDispatchRoutePoint(dispatchRow, 'start').address
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
<div class="business-crud-page__dispatch-route-contact">
|
||||
{{ parseDispatchRoutePoint(dispatchRow, 'start').contact || '-' }}
|
||||
@@ -3406,7 +3410,11 @@
|
||||
{{ parseDispatchRoutePoint(dispatchRow, 'end').name || '-' }}
|
||||
</div>
|
||||
<div class="business-crud-page__dispatch-route-address">
|
||||
{{ parseDispatchRoutePoint(dispatchRow, 'end').address || '-' }}
|
||||
{{
|
||||
formatTransportPlanProvinceCityDistrict(
|
||||
parseDispatchRoutePoint(dispatchRow, 'end').address
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
<div class="business-crud-page__dispatch-route-contact">
|
||||
{{ parseDispatchRoutePoint(dispatchRow, 'end').contact || '-' }}
|
||||
@@ -3867,7 +3875,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dispatchCarrierRequired" :label="dispatchCarrierLabel" required>
|
||||
<el-select
|
||||
v-model="dispatchItemForm.carrierName"
|
||||
v-model="dispatchCarrierSelection"
|
||||
:placeholder="`请选择${dispatchCarrierLabel}`"
|
||||
filterable
|
||||
clearable
|
||||
@@ -3880,8 +3888,8 @@
|
||||
:key="
|
||||
item.id || item.customerName || item.carrierName || item.fullName || item.name
|
||||
"
|
||||
:label="item.customerName || item.carrierName || item.fullName || item.name"
|
||||
:value="item.customerName || item.carrierName || item.fullName || item.name"
|
||||
:label="item.label || item.customerName || item.carrierName || item.fullName || item.name"
|
||||
:value="dispatchIsCarrierMode ? item.carrierContractId : item.value || item.customerName || item.carrierName || item.fullName || item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -4086,7 +4094,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dispatchCarrierRequired" :label="dispatchCarrierLabel" required>
|
||||
<el-select
|
||||
v-model="dispatchItemForm.carrierName"
|
||||
v-model="dispatchCarrierSelection"
|
||||
:placeholder="`请选择${dispatchCarrierLabel}`"
|
||||
filterable
|
||||
clearable
|
||||
@@ -4099,8 +4107,8 @@
|
||||
:key="
|
||||
item.id || item.customerName || item.carrierName || item.fullName || item.name
|
||||
"
|
||||
:label="item.customerName || item.carrierName || item.fullName || item.name"
|
||||
:value="item.customerName || item.carrierName || item.fullName || item.name"
|
||||
:label="item.label || item.customerName || item.carrierName || item.fullName || item.name"
|
||||
:value="dispatchIsCarrierMode ? item.carrierContractId : item.value || item.customerName || item.carrierName || item.fullName || item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -5446,6 +5454,7 @@ const defaultDispatchRow = () => ({
|
||||
transportType: '',
|
||||
carrierType: '承运商',
|
||||
carrierId: '',
|
||||
carrierContractId: '',
|
||||
carrierName: '',
|
||||
driverId: '',
|
||||
driverName: '',
|
||||
@@ -6255,6 +6264,16 @@ export default {
|
||||
dispatchCarrierLabel() {
|
||||
return this.dispatchItemForm.carrierType === '网货平台' ? '承运方' : '承运商';
|
||||
},
|
||||
dispatchCarrierSelection: {
|
||||
get() {
|
||||
return this.dispatchIsCarrierMode
|
||||
? this.dispatchItemForm.carrierContractId || ''
|
||||
: this.dispatchItemForm.carrierName || '';
|
||||
},
|
||||
set(value) {
|
||||
this.handleDispatchCarrierChange(value);
|
||||
},
|
||||
},
|
||||
dispatchStationMode() {
|
||||
return ['water', 'rail', 'air'].includes(this.dispatchTransportMode);
|
||||
},
|
||||
@@ -12226,6 +12245,8 @@ export default {
|
||||
taskEntryMode: item.taskEntryMode || 'simple',
|
||||
transportType: item.transportType || plan.transportType || '',
|
||||
carrierType: item.carrierType || plan.carrierType || '承运商',
|
||||
carrierId: item.carrierId || plan.carrierId || '',
|
||||
carrierContractId: item.carrierContractId || plan.carrierContractId || '',
|
||||
carrierName: item.carrierName || plan.carrierName || '',
|
||||
driverName: item.driverName || plan.driverName || '',
|
||||
driverPhone: item.driverPhone || plan.driverPhone || '',
|
||||
@@ -12643,11 +12664,15 @@ export default {
|
||||
this.dispatchItemForm.trailerVehicleNo = '';
|
||||
this.dispatchItemForm.escortName = '';
|
||||
this.dispatchItemForm.escortPhone = '';
|
||||
} else if (!this.isDispatchCarrierRequired(nextValue)) {
|
||||
this.dispatchItemForm.carrierId = '';
|
||||
this.dispatchItemForm.carrierName = '';
|
||||
} else {
|
||||
this.dispatchItemForm.carrierContractId = '';
|
||||
if (!this.isDispatchCarrierRequired(nextValue)) {
|
||||
this.dispatchItemForm.carrierId = '';
|
||||
this.dispatchItemForm.carrierName = '';
|
||||
}
|
||||
}
|
||||
this.dispatchItemForm.carrierType = nextValue;
|
||||
this.loadDispatchCarrierOptions(this.dispatchRow);
|
||||
},
|
||||
isDispatchCarrierRequired(carrierType) {
|
||||
return ['承运商', '网货平台'].includes(String(carrierType || '').trim());
|
||||
@@ -12708,22 +12733,61 @@ export default {
|
||||
if (this.dispatchCarrierLoading) return Promise.resolve(this.dispatchCarrierOptions);
|
||||
const projectId = plan?.projectId;
|
||||
const requestId = ++this.dispatchCarrierRequestId;
|
||||
const carrierTypeAtRequest = this.dispatchItemForm.carrierType || '承运商';
|
||||
const project = this.projectOptions.find(item => String(item.id) === String(projectId));
|
||||
this.dispatchCarrierOptions = this.getProjectCarrierOptions({ ...project, ...plan });
|
||||
if (!projectId) return Promise.resolve(this.dispatchCarrierOptions);
|
||||
this.dispatchCarrierLoading = true;
|
||||
return getProjectDetail(projectId)
|
||||
.then(res => {
|
||||
if (requestId !== this.dispatchCarrierRequestId) return this.dispatchCarrierOptions;
|
||||
const detail = res?.data?.data || {};
|
||||
this.dispatchCarrierOptions = this.getProjectCarrierOptions({
|
||||
...project,
|
||||
...plan,
|
||||
...detail,
|
||||
const carrierContractPromise = getContractList(1, 9999, {
|
||||
projectId,
|
||||
projectName: plan?.projectName || project?.projectName,
|
||||
contractCategory: '承运商合同',
|
||||
}).then(res => this.getWaybillCarrierContractOptions(extractRecords(res)));
|
||||
if (carrierTypeAtRequest === '承运商') {
|
||||
return carrierContractPromise
|
||||
.then(options => {
|
||||
if (requestId !== this.dispatchCarrierRequestId) return this.dispatchCarrierOptions;
|
||||
this.dispatchCarrierOptions = options || [];
|
||||
const current = this.dispatchCarrierOptions.find(
|
||||
item =>
|
||||
String(item.carrierContractId) ===
|
||||
String(this.dispatchItemForm.carrierContractId || '')
|
||||
);
|
||||
if (current) {
|
||||
this.dispatchItemForm.carrierName = current.carrierName;
|
||||
} else if (!this.dispatchItemForm.carrierContractId) {
|
||||
const matches = this.dispatchCarrierOptions.filter(
|
||||
item => String(item.carrierName) === String(this.dispatchItemForm.carrierName || '')
|
||||
);
|
||||
if (matches.length === 1) {
|
||||
this.dispatchItemForm.carrierContractId = matches[0].carrierContractId;
|
||||
}
|
||||
}
|
||||
return this.dispatchCarrierOptions;
|
||||
})
|
||||
.catch(() => this.dispatchCarrierOptions)
|
||||
.finally(() => {
|
||||
if (requestId === this.dispatchCarrierRequestId) {
|
||||
this.dispatchCarrierLoading = false;
|
||||
}
|
||||
});
|
||||
return this.dispatchCarrierOptions;
|
||||
})
|
||||
.catch(() => this.dispatchCarrierOptions)
|
||||
}
|
||||
return Promise.all([
|
||||
getProjectDetail(projectId)
|
||||
.then(res => {
|
||||
if (requestId !== this.dispatchCarrierRequestId) return this.dispatchCarrierOptions;
|
||||
const detail = res?.data?.data || {};
|
||||
this.dispatchCarrierOptions = this.getProjectCarrierOptions({
|
||||
...project,
|
||||
...plan,
|
||||
...detail,
|
||||
});
|
||||
return this.dispatchCarrierOptions;
|
||||
})
|
||||
.catch(() => this.dispatchCarrierOptions),
|
||||
carrierContractPromise.catch(() => []),
|
||||
])
|
||||
.then(([options]) => options)
|
||||
.finally(() => {
|
||||
if (requestId === this.dispatchCarrierRequestId) {
|
||||
this.dispatchCarrierLoading = false;
|
||||
@@ -12731,9 +12795,19 @@ export default {
|
||||
});
|
||||
},
|
||||
handleDispatchCarrierChange(value) {
|
||||
const carrier = this.dispatchCarrierOptions.find(item => item.value === String(value || ''));
|
||||
const carrier = this.dispatchCarrierOptions.find(item => {
|
||||
const optionValue = this.dispatchIsCarrierMode ? item.carrierContractId : item.value;
|
||||
return String(optionValue || '') === String(value || '');
|
||||
});
|
||||
if (this.dispatchIsCarrierMode) {
|
||||
this.dispatchItemForm.carrierContractId = carrier?.carrierContractId || '';
|
||||
this.dispatchItemForm.carrierId = '';
|
||||
this.dispatchItemForm.carrierName = carrier?.carrierName || '';
|
||||
return;
|
||||
}
|
||||
this.dispatchItemForm.carrierContractId = '';
|
||||
this.dispatchItemForm.carrierId = carrier?.id || '';
|
||||
this.dispatchItemForm.carrierName = value || '';
|
||||
this.dispatchItemForm.carrierName = carrier?.carrierName || value || '';
|
||||
},
|
||||
loadDispatchDriverOptions() {
|
||||
if (this.taskDriverLoading) return Promise.resolve([]);
|
||||
@@ -12837,7 +12911,54 @@ export default {
|
||||
},
|
||||
dispatchItemRemainingQuantity(row = {}) {
|
||||
const unit = this.getDispatchQuantityUnit(row);
|
||||
let remaining = this.getDispatchRemainingQuantity(unit);
|
||||
const hasCargoIdentity = Boolean(
|
||||
String(row.cargoName || row.goodsName || row.name || '').trim() ||
|
||||
String(
|
||||
row.cargoType || row.secondCargoTypeName || row.goodsType || row.type || ''
|
||||
).trim()
|
||||
);
|
||||
const planGoodsRows = this.dispatchPlanGoodsRows;
|
||||
const cargoKey = this.getDispatchCargoIdentity(row);
|
||||
|
||||
// 完整录入时按货物身份计算,不能把同单位的其他货物数量合并到当前行。
|
||||
if (planGoodsRows.length && hasCargoIdentity) {
|
||||
const matchedPlanRows = planGoodsRows.filter(
|
||||
goods => this.getDispatchCargoIdentity(goods) === cargoKey
|
||||
);
|
||||
if (!matchedPlanRows.length) return 0;
|
||||
const total = matchedPlanRows.reduce(
|
||||
(sum, goods) =>
|
||||
sum +
|
||||
this.parseDispatchQuantity(
|
||||
goods.quantity || goods.cargoQuantity || goods.goodsQuantity
|
||||
),
|
||||
0
|
||||
);
|
||||
const assigned = this.dispatchRows.reduce((sum, dispatchRow, index) => {
|
||||
if (
|
||||
index === this.dispatchItemIndex ||
|
||||
!this.hasDispatchVehicleIdentifier(dispatchRow)
|
||||
) {
|
||||
return sum;
|
||||
}
|
||||
return (
|
||||
sum +
|
||||
this.getDispatchGoodsSourceRows(dispatchRow).reduce((goodsSum, goods) => {
|
||||
if (this.getDispatchCargoIdentity(goods) !== cargoKey) return goodsSum;
|
||||
return (
|
||||
goodsSum +
|
||||
this.parseDispatchQuantity(
|
||||
goods.quantity || goods.cargoQuantity || goods.goodsQuantity
|
||||
)
|
||||
);
|
||||
}, 0)
|
||||
);
|
||||
}, 0);
|
||||
return Math.max(total - assigned, 0);
|
||||
}
|
||||
|
||||
// 兼容没有货物明细的旧数据,以及尚未选择货物的空白行。
|
||||
const remaining = this.getDispatchRemainingQuantity(unit);
|
||||
const editingRow = this.dispatchRows[this.dispatchItemIndex];
|
||||
if (!editingRow || !this.hasDispatchVehicleIdentifier(editingRow)) return remaining;
|
||||
const editingGoodsRows = this.dispatchGoodsRows(editingRow.goodsJson);
|
||||
@@ -12943,6 +13064,9 @@ export default {
|
||||
if (this.isDispatchCarrierRequired(row.carrierType)) {
|
||||
requiredFields.push(['carrierName', row.carrierType === '网货平台' ? '承运方' : '承运商']);
|
||||
}
|
||||
if (row.carrierType === '承运商') {
|
||||
requiredFields.push(['carrierContractId', '承运商合同']);
|
||||
}
|
||||
const fullEntry = row.taskEntryMode === 'full';
|
||||
const roadTransport = this.resolveTransportMode(row.transportType) === 'road';
|
||||
if (fullEntry) {
|
||||
@@ -13056,16 +13180,25 @@ export default {
|
||||
? this.dispatchItemCargoRows
|
||||
: [this.dispatchItemForm];
|
||||
if (!this.validateDispatchItemData(this.dispatchItemForm, goodsRows)) return false;
|
||||
const quantitiesByUnit = new Map();
|
||||
const quantityGroups = new Map();
|
||||
goodsRows.forEach(goods => {
|
||||
const unit = this.getDispatchQuantityUnit(goods);
|
||||
quantitiesByUnit.set(
|
||||
unit,
|
||||
(quantitiesByUnit.get(unit) || 0) + this.parseDispatchQuantity(goods.quantity)
|
||||
const hasCargoIdentity = Boolean(
|
||||
String(goods.cargoName || goods.goodsName || goods.name || '').trim() ||
|
||||
String(
|
||||
goods.cargoType || goods.secondCargoTypeName || goods.goodsType || goods.type || ''
|
||||
).trim()
|
||||
);
|
||||
const key = hasCargoIdentity
|
||||
? `cargo:${this.getDispatchCargoIdentity(goods)}`
|
||||
: `unit:${unit}`;
|
||||
const group = quantityGroups.get(key) || { row: goods, quantity: 0 };
|
||||
group.quantity += this.parseDispatchQuantity(goods.quantity);
|
||||
quantityGroups.set(key, group);
|
||||
});
|
||||
for (const [unit, quantity] of quantitiesByUnit.entries()) {
|
||||
const remaining = this.dispatchItemRemainingQuantity({ quantityUnit: unit });
|
||||
for (const { row: goods, quantity } of quantityGroups.values()) {
|
||||
const unit = this.getDispatchQuantityUnit(goods);
|
||||
const remaining = this.dispatchItemRemainingQuantity(goods);
|
||||
if (quantity - remaining > 1e-8) {
|
||||
this.$message.warning(
|
||||
`本次调度${unit}合计不能超过剩余数量${this.formatDispatchQuantity(remaining)}${unit}`
|
||||
|
||||
@@ -134,7 +134,6 @@
|
||||
<el-row v-if="route.freightItems.length" :gutter="16">
|
||||
<el-col :span="6"><el-form-item label="运费合计"><el-input :model-value="formatAmount(freightTotal(route))" readonly><template #suffix>{{ currencyLabel(route.currency) }}</template></el-input></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="其他费用合计"><el-input :model-value="route.otherFeeTotal" inputmode="decimal" placeholder="请输入" @input="value => handleOtherFeeTotalInput(route, value)" /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="币种"><el-select v-model="route.currency"><el-option label="人民币" value="CNY" /><el-option label="美元" value="USD" /><el-option label="欧元" value="EUR" /></el-select></el-form-item></el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
@@ -143,16 +142,16 @@
|
||||
<el-form :model="route" label-position="right" label-width="auto" class="dispatch-form carrier-form">
|
||||
<el-row :gutter="16">
|
||||
<template v-if="isRoad(route)">
|
||||
<el-col v-if="route.carrierType === '承运商'" :span="6"><el-form-item label="承运商" required><el-select v-model="route.carrierContractId" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="item.contractId" :label="carrierOptionLabel(item)" :value="item.contractId" /></el-select></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="承运商" :required="route.carrierType === '承运商'"><el-select :model-value="route.carrierType === '承运商' ? route.carrierContractId : route.carrierName" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="carrierOptionValue(item)" :label="carrierOptionLabel(item)" :value="route.carrierType === '承运商' ? carrierOptionValue(item) : item.carrierName" /></el-select></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="司机" :required="route.carrierType !== '承运商'"><el-autocomplete :ref="element => setDriverInput(route.segmentNo, element)" v-model="route.driverName" :debounce="300" :fetch-suggestions="fetchDriverSuggestions" clearable placeholder="请输入司机" :loading="driverLoading" @select="item => handleDriverSuggestionSelect(route, item)" /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item :label="route.carrierType === '承运商' ? '手机号' : '司机手机号'" :required="route.carrierType !== '承运商'"><el-input v-model="route.driverPhone" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="车牌号" required><el-input v-model="route.vehicleNo" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col v-if="route.carrierType !== '承运商'" :span="6"><el-form-item label="挂车车牌号" required><el-input v-model="route.trailerVehicleNo" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col v-if="route.carrierType !== '承运商'" :span="6"><el-form-item label="押运人" required><el-input v-model="route.escortName" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col v-if="route.carrierType !== '承运商'" :span="6"><el-form-item label="押运人手机号" required><el-input v-model="route.escortPhone" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col v-if="route.carrierType !== '承运商'" :span="6"><el-form-item label="挂车车牌号"><el-input v-model="route.trailerVehicleNo" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col v-if="route.carrierType !== '承运商'" :span="6"><el-form-item label="押运人"><el-autocomplete v-model="route.escortName" :debounce="300" :fetch-suggestions="fetchEscortSuggestions" clearable placeholder="请输入" :loading="escortLoading" @select="item => handleEscortSuggestionSelect(route, item)" /></el-form-item></el-col>
|
||||
<el-col v-if="route.carrierType !== '承运商'" :span="6"><el-form-item label="押运人手机号"><el-input v-model="route.escortPhone" placeholder="请输入" /></el-form-item></el-col>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-col v-if="route.carrierType === '承运商'" :span="6"><el-form-item label="承运商" required><el-select v-model="route.carrierContractId" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="item.contractId" :label="carrierOptionLabel(item)" :value="item.contractId" /></el-select></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="承运商" :required="route.carrierType === '承运商'"><el-select :model-value="route.carrierType === '承运商' ? route.carrierContractId : route.carrierName" filterable clearable placeholder="请选择" :loading="carrierLoading" @change="value => handleCarrierContractChange(route, value)"><el-option v-for="item in carrierOptions" :key="carrierOptionValue(item)" :label="carrierOptionLabel(item)" :value="route.carrierType === '承运商' ? carrierOptionValue(item) : item.carrierName" /></el-select></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="船/航/班列号" required><el-input v-model="route.vehicleNo" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="船长"><el-input v-model="route.captainName" placeholder="请输入" /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="联系电话" required><el-input v-model="route.driverPhone" placeholder="请输入" /></el-form-item></el-col>
|
||||
@@ -208,7 +207,7 @@ export default {
|
||||
props: { id: [String, Number] },
|
||||
emits: ['back'],
|
||||
data() {
|
||||
return { loading: false, submitting: false, master: null, routes: [], pending: [], pendingExpanded: false, editingId: null, driverInputs: {}, carrierOptions: [], driverOptions: [], carrierLoading: false, driverLoading: false, cargoTypeOptions: [], cargoTypeCascaderProps: { label: 'cargoName', value: 'id', children: 'children', emitPath: true }, quantityUnitOptions: ['吨', '千克', '立方米', '件', '车', '箱', '托盘'] };
|
||||
return { loading: false, submitting: false, master: null, routes: [], pending: [], pendingExpanded: false, editingId: null, driverInputs: {}, carrierOptions: [], driverOptions: [], carrierLoading: false, driverLoading: false, escortLoading: false, cargoTypeOptions: [], cargoTypeCascaderProps: { label: 'cargoName', value: 'id', children: 'children', emitPath: true }, quantityUnitOptions: ['吨', '千克', '立方米', '件', '车', '箱', '托盘'] };
|
||||
},
|
||||
computed: {
|
||||
totalQuantity() { return (this.master?.goods || []).reduce((sum, item) => sum + Number(item.quantity || 0), 0); },
|
||||
@@ -231,6 +230,7 @@ export default {
|
||||
},
|
||||
async mounted() {
|
||||
await Promise.all([this.load(), this.loadCarrierOptions(), this.loadDriverOptions()]);
|
||||
this.applySelfOperatedCarrierDefaults();
|
||||
},
|
||||
methods: {
|
||||
async load() {
|
||||
@@ -238,10 +238,36 @@ export default {
|
||||
try {
|
||||
const res = await api.getDetail(this.id);
|
||||
this.master = res.data?.data || res.data || res;
|
||||
await this.loadContractCurrency();
|
||||
this.cargoTypeOptions = this.buildMasterCargoTypeOptions(this.master.goods || []);
|
||||
this.routes = this.dispatchRouteNodes().map((node, index) => this.createRoute(node, index));
|
||||
} finally { this.loading = false; }
|
||||
},
|
||||
normalizeCurrencyValue(value) {
|
||||
const raw = typeof value === 'object'
|
||||
? value.dictKey || value.value || value.code || value.dictValue || ''
|
||||
: value;
|
||||
const normalized = String(raw || 'RMB').trim().toUpperCase();
|
||||
return normalized.includes(' - ') ? normalized.split(' - ')[0].trim() : normalized;
|
||||
},
|
||||
async loadContractCurrency() {
|
||||
const directCurrency = this.master?.settlementCurrency || this.master?.settlementCurrencyCode || this.master?.currency;
|
||||
if (!this.master?.projectId || !this.master?.contractId) {
|
||||
this.master.settlementCurrency = this.normalizeCurrencyValue(directCurrency || 'RMB');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await api.getProjectContracts(this.master.projectId);
|
||||
const contract = unwrapRecords(response).find(item => String(item.id) === String(this.master.contractId));
|
||||
this.master.customerContractPartyB = contract?.partyB || this.master.customerContractPartyB || '';
|
||||
this.master.settlementCurrency = this.normalizeCurrencyValue(
|
||||
directCurrency || contract?.settlementCurrency || contract?.settlementCurrencyCode || contract?.currency || 'RMB'
|
||||
);
|
||||
} catch {
|
||||
this.master.customerContractPartyB = '';
|
||||
this.master.settlementCurrency = 'RMB';
|
||||
}
|
||||
},
|
||||
dispatchRouteNodes() {
|
||||
const routes = Array.isArray(this.master?.routes) ? this.master.routes : [];
|
||||
if (routes.length) return routes;
|
||||
@@ -261,9 +287,9 @@ export default {
|
||||
...node,
|
||||
selected: false,
|
||||
documentType: '运单',
|
||||
carrierType: '承运商',
|
||||
carrierType: node.carrierType || this.master?.carrierType || '承运商',
|
||||
carrierContractId: '',
|
||||
currency: 'CNY',
|
||||
currency: this.normalizeCurrencyValue(this.master?.settlementCurrency || 'RMB'),
|
||||
otherFeeTotal: '',
|
||||
freightItems: [],
|
||||
departureName: previous.departureName || '', departureAddress: previous.departureAddress || '', departureContact: previous.departureContact || '', departurePhone: previous.departurePhone || '',
|
||||
@@ -343,7 +369,7 @@ export default {
|
||||
},
|
||||
buildFreightJson(route) {
|
||||
return JSON.stringify({
|
||||
currency: route.currency || 'CNY',
|
||||
currency: route.currency || 'RMB',
|
||||
totalFreightAmount: this.freightTotal(route),
|
||||
otherFreightAmount: route.otherFeeTotal || '',
|
||||
freightItems: (route.freightItems || []).map(item => ({
|
||||
@@ -352,7 +378,7 @@ export default {
|
||||
})),
|
||||
});
|
||||
},
|
||||
currencyLabel(value) { return ({ CNY: '人民币', USD: '美元', EUR: '欧元' })[value] || value || '人民币'; },
|
||||
currencyLabel(value) { return ({ CNY: '人民币', RMB: '人民币', USD: '美元', EUR: '欧元' })[value] || value || '人民币'; },
|
||||
quantityNumber(value) { return Number(value || 0); },
|
||||
goodsKey(goods = {}, includeUnit = true) {
|
||||
return [
|
||||
@@ -533,16 +559,23 @@ export default {
|
||||
}
|
||||
if (value !== '承运商') {
|
||||
route.carrierContractId = '';
|
||||
route.carrierName = '';
|
||||
if (value === '网货平台') route.carrierName = '';
|
||||
if (value === '自运') this.applySelfOperatedCarrierDefaults(route);
|
||||
}
|
||||
},
|
||||
handleCarrierContractChange(route, contractId) {
|
||||
const contract = this.carrierOptions.find(
|
||||
item => String(item.contractId) === String(contractId)
|
||||
item =>
|
||||
[item.contractId, item.carrierName, item.id].some(
|
||||
value => String(value || '') === String(contractId || '')
|
||||
)
|
||||
);
|
||||
route.carrierContractId = contract?.contractId || '';
|
||||
route.carrierContractId = route.carrierType === '承运商' ? contract?.contractId || '' : '';
|
||||
route.carrierName = contract?.carrierName || '';
|
||||
},
|
||||
carrierOptionValue(item = {}) {
|
||||
return item.contractId || item.id || item.value || item.carrierName || '';
|
||||
},
|
||||
carrierOptionLabel(item) {
|
||||
const duplicateCount = this.carrierOptions.filter(option => option.carrierName === item.carrierName).length;
|
||||
return duplicateCount > 1
|
||||
@@ -568,10 +601,35 @@ export default {
|
||||
this.carrierLoading = false;
|
||||
}
|
||||
},
|
||||
applySelfOperatedCarrierDefaults(targetRoute) {
|
||||
const routes = targetRoute ? [targetRoute] : this.routes;
|
||||
if (!this.carrierOptions.length) {
|
||||
const carrierName = String(this.master?.customerContractPartyB || '').trim();
|
||||
if (carrierName) {
|
||||
this.carrierOptions = [{
|
||||
id: `customer-contract-${carrierName}`,
|
||||
contractId: `customer-contract-${carrierName}`,
|
||||
carrierName,
|
||||
}];
|
||||
}
|
||||
}
|
||||
routes.forEach(route => {
|
||||
if (route.carrierType !== '自运') return;
|
||||
if (this.carrierOptions.length) {
|
||||
const current = this.carrierOptions.find(
|
||||
item => String(item.carrierName || '') === String(route.carrierName || '')
|
||||
);
|
||||
route.carrierName = current?.carrierName || this.carrierOptions[0].carrierName || '';
|
||||
}
|
||||
route.carrierContractId = '';
|
||||
});
|
||||
},
|
||||
async loadDriverOptions(keyword = '') {
|
||||
this.driverLoading = true;
|
||||
try {
|
||||
this.driverOptions = unwrapRecords(await getDriverList(1, 20, { driverName: keyword }));
|
||||
this.driverOptions = unwrapRecords(
|
||||
await getDriverList(1, 20, { driverName: keyword, posts: '司机' })
|
||||
);
|
||||
} finally {
|
||||
this.driverLoading = false;
|
||||
}
|
||||
@@ -595,6 +653,28 @@ export default {
|
||||
const drivingVehicle = String(item.drivingVehicle || '').trim();
|
||||
if (drivingVehicle) route.vehicleNo = drivingVehicle;
|
||||
},
|
||||
fetchEscortSuggestions(queryString, callback) {
|
||||
const keyword = String(queryString || '').trim();
|
||||
this.escortLoading = true;
|
||||
getDriverList(1, 20, { ...(keyword ? { driverName: keyword } : {}), posts: '押运员' })
|
||||
.then(res => {
|
||||
callback(
|
||||
unwrapRecords(res).map(item => ({
|
||||
...item,
|
||||
value: this.driverOptionLabel(item),
|
||||
}))
|
||||
);
|
||||
})
|
||||
.catch(() => callback([]))
|
||||
.finally(() => {
|
||||
this.escortLoading = false;
|
||||
});
|
||||
},
|
||||
handleEscortSuggestionSelect(route, item = {}) {
|
||||
route.escortName = this.driverOptionLabel(item);
|
||||
const phone = item.mobile || item.driverPhone || item.phone || '';
|
||||
if (phone) route.escortPhone = phone;
|
||||
},
|
||||
setDriverInput(segmentNo, element) {
|
||||
if (element) this.driverInputs[segmentNo] = element;
|
||||
else delete this.driverInputs[segmentNo];
|
||||
@@ -622,7 +702,7 @@ export default {
|
||||
if (route.documentType === '运单') {
|
||||
if (this.isRoad(route)) {
|
||||
if (route.carrierType === '承运商' && (!route.carrierContractId || !route.carrierName || !route.vehicleNo)) return this.$message.warning('请选择承运商并填写车牌号');
|
||||
if (route.carrierType !== '承运商' && (!route.driverName || !route.driverPhone || !route.vehicleNo || !route.trailerVehicleNo || !route.escortName || !route.escortPhone)) return this.$message.warning('请补全自运或网货平台的车辆与人员信息');
|
||||
if (route.carrierType !== '承运商' && (!route.driverName || !route.driverPhone || !route.vehicleNo)) return this.$message.warning('请补全自运或网货平台的车辆与人员信息');
|
||||
} else if (!route.vehicleNo || !route.driverPhone || (route.carrierType === '承运商' && (!route.carrierContractId || !route.carrierName))) {
|
||||
return this.$message.warning('请补全非公路运输的承运信息');
|
||||
}
|
||||
@@ -632,7 +712,7 @@ export default {
|
||||
id: `${route.segmentNo}-${item.cargoName}-${Date.now()}-${Math.random()}`,
|
||||
batchNo,
|
||||
segmentNo: route.segmentNo, relationNo: route.segmentNo, documentType: route.documentType, transportType: route.transportType, carrierType: route.carrierType,
|
||||
carrierContractId: route.carrierContractId, carrierName: route.carrierName, driverName: route.driverName, driverPhone: route.driverPhone, vehicleNo: route.vehicleNo, captainName: route.captainName, cabinNo: route.cabinNo, containerNo: route.containerNo, trailerVehicleNo: route.trailerVehicleNo, escortName: route.escortName, escortPhone: route.escortPhone, mileage: this.normalizeMileage(route.mileage), unitPrice: this.freightItemsForGoods(route, item).unitPrice || '', priceUnit: this.freightItemsForGoods(route, item).priceUnit || '', currency: route.currency || 'CNY', freightAmount: this.freightAmount(this.freightItemsForGoods(route, item)), freightTotal: this.freightTotal(route), otherFeeTotal: route.otherFeeTotal || '', freightJson: this.buildFreightJson(route), remark: route.remark,
|
||||
carrierContractId: route.carrierContractId, carrierName: route.carrierName, driverName: route.driverName, driverPhone: route.driverPhone, vehicleNo: route.vehicleNo, captainName: route.captainName, cabinNo: route.cabinNo, containerNo: route.containerNo, trailerVehicleNo: route.trailerVehicleNo, escortName: route.escortName, escortPhone: route.escortPhone, mileage: this.normalizeMileage(route.mileage), unitPrice: this.freightItemsForGoods(route, item).unitPrice || '', priceUnit: this.freightItemsForGoods(route, item).priceUnit || '', currency: route.currency || 'RMB', freightAmount: this.freightAmount(this.freightItemsForGoods(route, item)), freightTotal: this.freightTotal(route), otherFeeTotal: route.otherFeeTotal || '', freightJson: this.buildFreightJson(route), remark: route.remark,
|
||||
departureName: route.departureName, departureAddress: route.departureAddress, departureContact: route.departureContact, departurePhone: route.departurePhone,
|
||||
arrivalName: route.arrivalName, arrivalAddress: route.arrivalAddress, arrivalContact: route.arrivalContact, arrivalPhone: route.arrivalPhone,
|
||||
estimatedStartTime: route.estimatedStartTime, estimatedEndTime: route.estimatedEndTime,
|
||||
@@ -661,6 +741,9 @@ export default {
|
||||
}
|
||||
if (goods) goods.dispatchQuantity = item.quantity;
|
||||
Object.assign(route, item);
|
||||
route.currency = this.normalizeCurrencyValue(
|
||||
this.master?.settlementCurrency || route.currency || 'RMB'
|
||||
);
|
||||
this.syncFreightItems(route);
|
||||
const freightItem = this.freightItemsForGoods(route, goods);
|
||||
if (freightItem) { freightItem.unitPrice = item.unitPrice || ''; freightItem.priceUnit = item.priceUnit || freightItem.priceUnit; }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user