调整业务模块
This commit is contained in:
@@ -34,7 +34,7 @@
|
||||
:model-value="form.masterNo || '系统自动生成'"
|
||||
readonly /></el-form-item></el-col
|
||||
><el-col :span="6"
|
||||
><el-form-item label="运输组织类型" required
|
||||
><el-form-item label="运输类型" required
|
||||
><el-select v-model="form.transportOrganizationType" disabled
|
||||
><el-option label="多式联运" value="多式联运" /></el-select></el-form-item></el-col
|
||||
><el-col :span="24"
|
||||
@@ -54,75 +54,77 @@
|
||||
<el-link type="primary" @click="openRouteDialog">选择线路</el-link>
|
||||
</div>
|
||||
</div>
|
||||
<el-form :model="form" label-position="right" label-width="auto"
|
||||
><div class="route-steps">
|
||||
<el-steps direction="vertical" :active="form.routes.length + 1">
|
||||
<el-step>
|
||||
<template #icon><span class="route-step-icon route-step-icon--start">起</span></template>
|
||||
<template #description>
|
||||
<div class="route-node-form">
|
||||
<el-form-item label="发货地址" required class="route-address-form-item"
|
||||
<el-form class="route-info-form" :model="form" label-position="right" label-width="96px"
|
||||
><div class="route-flow">
|
||||
<div class="route-flow-row">
|
||||
<span class="route-flow-marker route-flow-marker--start">起</span>
|
||||
<div class="route-flow-body">
|
||||
<div class="route-node-form">
|
||||
<el-form-item label="发货地" required class="route-address-form-item"
|
||||
><div class="route-address-inputs"
|
||||
><el-cascader v-model="addressRegionPaths.departure" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange('departure', value)" /><el-input v-model="form.departureAddress" class="route-address-detail" readonly placeholder="请输入详细地址" @click="openAddressMap('departure')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" @click="openCommonAddress('departure')" /></el-tooltip></div
|
||||
><el-input v-if="isNonRoadAddress('departure')" v-model="form.departureName" class="route-address-name" readonly placeholder="请选择站点" /><el-cascader v-else v-model="addressRegionPaths.departure" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange('departure', value)" /><el-input v-model="form.departureAddress" class="route-address-detail" readonly placeholder="请输入详细地址" @click="handleAddressDetailClick('departure')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" @click="openCommonAddress('departure')" /></el-tooltip></div
|
||||
></el-form-item>
|
||||
<el-form-item label="联系人"
|
||||
<el-form-item label="联系人" class="route-contact-form-item"
|
||||
><el-input v-model="form.departureContact" placeholder="请输入"
|
||||
/></el-form-item>
|
||||
<el-form-item label="联系方式"
|
||||
<el-form-item label="联系方式" class="route-phone-form-item"
|
||||
><el-input v-model="form.departurePhone" placeholder="请输入"
|
||||
/></el-form-item>
|
||||
<el-form-item label="计划开始日期"
|
||||
<el-form-item label="计划开始" class="route-date-form-item"
|
||||
><el-date-picker
|
||||
v-model="form.planStartTime"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择"
|
||||
style="width: 200px"
|
||||
/></el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step v-for="(route, index) in form.routes" :key="index">
|
||||
<template #icon><span class="route-step-icon route-step-icon--middle">经</span></template>
|
||||
<template #title><div class="route-step-title"><span class="route-segment-label">段{{ index + 1 }}</span><el-tooltip :content="getRouteTitle(index).replace(`段${index + 1}:`, '')" placement="top"><span class="route-title-path">{{ formatRouteTitle(getRouteTitle(index), index + 1) }}</span></el-tooltip><div class="route-transport-control"><span>运输方式</span><el-select v-model="route.transportType" placeholder="请选择"><el-option v-for="type in transports" :key="type" :label="type" :value="type" /></el-select></div></div></template>
|
||||
<template #description>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template v-for="(route, index) in form.routes" :key="index">
|
||||
<div class="route-flow-segment">
|
||||
<div class="route-step-title"><span class="route-segment-label">{{ circledSegmentNumber(index + 1) }} 段{{ index + 1 }}</span><el-tooltip :content="getRouteTitle(index).replace(`段${index + 1}:`, '')" placement="top"><span class="route-title-path">{{ formatRouteTitle(getRouteTitle(index), index + 1) }}</span></el-tooltip><div class="route-transport-control"><span>运输方式<span class="required-asterisk">*</span></span><el-select v-model="route.transportType" placeholder="请选择"><el-option v-for="type in transports" :key="type" :label="type" :value="type" /></el-select></div></div>
|
||||
</div>
|
||||
<div class="route-flow-row">
|
||||
<span class="route-flow-marker route-flow-marker--middle">经</span>
|
||||
<div class="route-flow-body">
|
||||
<div class="route-node-form">
|
||||
<el-form-item label="途经地" required class="route-address-form-item"
|
||||
><div class="route-address-inputs"
|
||||
><el-cascader v-model="addressRegionPaths[`route-${index}`]" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="!route.transportType" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange(`route-${index}`, value)" /><el-input v-model="route.departureAddress" class="route-address-detail" readonly :disabled="!route.transportType || !isRoadTransportType(route.transportType)" placeholder="请先选择运输方式" @click="openAddressMap(`route-${index}`)" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="!route.transportType" @click="openCommonAddress(`route-${index}`)" /></el-tooltip></div
|
||||
><el-input v-if="isNonRoadAddress(`route-${index}`)" v-model="route.departureName" class="route-address-name" readonly :disabled="!route.transportType" placeholder="请先选择运输方式" /><el-cascader v-else v-model="addressRegionPaths[`route-${index}`]" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="!route.transportType" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange(`route-${index}`, value)" /><el-input v-model="route.departureAddress" class="route-address-detail" readonly :disabled="!route.transportType" placeholder="请先选择运输方式" @click="handleAddressDetailClick(`route-${index}`)" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="!route.transportType" @click="openCommonAddress(`route-${index}`)" /></el-tooltip></div
|
||||
></el-form-item>
|
||||
<el-form-item label="联系人"><el-input v-model="route.departureContact" placeholder="请输入" /></el-form-item>
|
||||
<el-form-item label="联系方式"><div class="route-contact-actions"><el-input v-model="route.departurePhone" placeholder="请输入" /><el-tooltip v-if="index === form.routes.length - 1" content="新增途经点" placement="top"><el-button class="route-action-button" type="primary" link @click="addRoute"><el-icon><CirclePlus /></el-icon></el-button></el-tooltip><el-tooltip content="删除途经点" placement="top"><el-button class="route-action-button" type="danger" link @click="removeRoute(index)"><el-icon><Remove /></el-icon></el-button></el-tooltip></div></el-form-item>
|
||||
<el-form-item label="联系人" class="route-contact-form-item"><el-input v-model="route.departureContact" placeholder="请输入" /></el-form-item>
|
||||
<el-form-item label="联系方式" class="route-phone-form-item"><div class="route-contact-actions"><el-input v-model="route.departurePhone" placeholder="请输入" /><el-tooltip v-if="index === form.routes.length - 1" content="新增途经点" placement="top"><el-button class="route-action-button" type="primary" link @click="addRoute"><el-icon><CirclePlus /></el-icon></el-button></el-tooltip><el-tooltip content="删除途经点" placement="top"><el-button class="route-action-button" type="danger" link @click="removeRoute(index)"><el-icon><Remove /></el-icon></el-button></el-tooltip></div></el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step>
|
||||
<template #icon><span class="route-step-icon route-step-icon--end">终</span></template>
|
||||
<template #title><div class="route-step-title"><span class="route-segment-label">段{{ form.routes.length + 1 }}</span><el-tooltip :content="getFinalRouteTitle().replace(`段${form.routes.length + 1}:`, '')" placement="top"><span class="route-title-path">{{ formatRouteTitle(getFinalRouteTitle(), form.routes.length + 1) }}</span></el-tooltip><div class="route-transport-control"><span>运输方式</span><el-select v-model="form.finalTransportType" placeholder="请选择"><el-option v-for="type in transports" :key="type" :label="type" :value="type" /></el-select></div></div></template>
|
||||
<template #description>
|
||||
<div class="route-node-form">
|
||||
<el-form-item label="收货地址" required class="route-address-form-item"
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="route-flow-segment">
|
||||
<div class="route-step-title"><span class="route-segment-label">{{ circledSegmentNumber(form.routes.length + 1) }} 段{{ form.routes.length + 1 }}</span><el-tooltip :content="getFinalRouteTitle().replace(`段${form.routes.length + 1}:`, '')" placement="top"><span class="route-title-path">{{ formatRouteTitle(getFinalRouteTitle(), form.routes.length + 1) }}</span></el-tooltip><div class="route-transport-control"><span>运输方式<span class="required-asterisk">*</span></span><el-select v-model="form.finalTransportType" placeholder="请选择"><el-option v-for="type in transports" :key="type" :label="type" :value="type" /></el-select></div></div>
|
||||
</div>
|
||||
<div class="route-flow-row">
|
||||
<span class="route-flow-marker route-flow-marker--end">终</span>
|
||||
<div class="route-flow-body">
|
||||
<div class="route-node-form">
|
||||
<el-form-item label="收货地" required class="route-address-form-item"
|
||||
><div class="route-address-inputs"
|
||||
><el-cascader v-model="addressRegionPaths.arrival" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="!form.finalTransportType" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange('arrival', value)" /><el-input v-model="form.arrivalAddress" class="route-address-detail" readonly :disabled="!form.finalTransportType || !isRoadTransportType(form.finalTransportType)" placeholder="请选择省市区" @click="openAddressMap('arrival')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="!form.finalTransportType" @click="openCommonAddress('arrival')" /></el-tooltip></div
|
||||
><el-input v-if="isNonRoadAddress('arrival')" v-model="form.arrivalName" class="route-address-name" readonly :disabled="!form.finalTransportType" placeholder="请先选择运输方式" /><el-cascader v-else v-model="addressRegionPaths.arrival" class="route-address-name" :options="regionOptions" :props="regionCascaderProps" :loading="regionLoading" :disabled="!form.finalTransportType" placeholder="请选择省市区" clearable filterable @visible-change="visible => visible && loadRegionOptions()" @change="value => handleAddressRegionChange('arrival', value)" /><el-input v-model="form.arrivalAddress" class="route-address-detail" readonly :disabled="!form.finalTransportType" placeholder="请先选择运输方式" @click="handleAddressDetailClick('arrival')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="OfficeBuilding" :disabled="!form.finalTransportType" @click="openCommonAddress('arrival')" /></el-tooltip></div
|
||||
></el-form-item>
|
||||
<el-form-item label="联系人"
|
||||
<el-form-item label="联系人" class="route-contact-form-item"
|
||||
><el-input v-model="form.arrivalContact" placeholder="请输入" /></el-form-item>
|
||||
<el-form-item label="联系方式"
|
||||
<el-form-item label="联系方式" class="route-phone-form-item"
|
||||
><el-input v-model="form.arrivalPhone" placeholder="请输入" /></el-form-item>
|
||||
<el-form-item label="计划结束日期"
|
||||
<el-form-item label="计划结束" class="route-date-form-item"
|
||||
><el-date-picker
|
||||
v-model="form.planEndTime"
|
||||
type="date"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择"
|
||||
style="width: 200px"
|
||||
/></el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
</el-steps>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></el-form
|
||||
>
|
||||
</section>
|
||||
@@ -157,7 +159,8 @@
|
||||
</template></el-autocomplete
|
||||
></template></el-table-column
|
||||
><el-table-column label="货物类型" min-width="130"
|
||||
><template #default="{ row }"
|
||||
><template #header><span>货物类型<span class="required-asterisk">*</span></span></template>
|
||||
<template #default="{ row }"
|
||||
><el-cascader
|
||||
v-model="row.cargoTypePath"
|
||||
:options="cargoTypeOptions"
|
||||
@@ -170,14 +173,16 @@
|
||||
@change="value => handleCargoTypeChange(row, value)"
|
||||
/></template></el-table-column
|
||||
><el-table-column label="数量" width="180" class-name="master-editor__quantity-cell"
|
||||
><template #default="{ row }"
|
||||
><template #header><span>数量<span class="required-asterisk">*</span></span></template>
|
||||
<template #default="{ row }"
|
||||
><el-input
|
||||
v-model="row.quantity"
|
||||
inputmode="decimal"
|
||||
placeholder="请输入"
|
||||
@input="value => handleQuantityInput(row, value)" /></template></el-table-column
|
||||
><el-table-column label="数量单位" width="120"
|
||||
><template #default="{ row }"
|
||||
><template #header><span>数量单位<span class="required-asterisk">*</span></span></template>
|
||||
<template #default="{ row }"
|
||||
><el-select v-model="row.quantityUnit"
|
||||
><el-option v-for="unit in quantityUnitOptions" :key="unit" :label="unit" :value="unit" /></el-select></template></el-table-column
|
||||
><el-table-column label="包装" width="130"
|
||||
@@ -194,6 +199,15 @@
|
||||
><el-table-column label="型号" min-width="120"
|
||||
><template #default="{ row }"
|
||||
><el-input v-model="row.model" placeholder="请输入" /></template></el-table-column
|
||||
><el-table-column label="物料编码" min-width="140"
|
||||
><template #default="{ row }"
|
||||
><el-input v-model="row.materialCode" placeholder="请输入" /></template></el-table-column
|
||||
><el-table-column label="设备编码" min-width="140"
|
||||
><template #default="{ row }"
|
||||
><el-input v-model="row.deviceCode" placeholder="请输入" /></template></el-table-column
|
||||
><el-table-column label="备注" min-width="180"
|
||||
><template #default="{ row }"
|
||||
><el-input v-model="row.remark" maxlength="200" show-word-limit placeholder="请输入" /></template></el-table-column
|
||||
><el-table-column label="操作" width="140"
|
||||
><template #default="{ $index }"
|
||||
><div class="goods-actions"
|
||||
@@ -717,6 +731,11 @@ export default {
|
||||
responseData(response) {
|
||||
return response?.data?.data || response?.data || response || {};
|
||||
},
|
||||
circledSegmentNumber(number) {
|
||||
const value = Number(number);
|
||||
const circledNumbers = '①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳';
|
||||
return circledNumbers[value - 1] || String(value);
|
||||
},
|
||||
async loadRegionOptions() {
|
||||
if (this.regionOptions.length) return this.regionOptions;
|
||||
if (this.regionRequest) return this.regionRequest;
|
||||
@@ -767,9 +786,19 @@ export default {
|
||||
},
|
||||
extractChinaRegionOptions(regions = []) {
|
||||
const china = regions.find(item => ['中国', '中华人民共和国'].includes(item.title));
|
||||
if (china?.children?.length) return china.children;
|
||||
if (regions.length === 1 && regions[0].children?.length) return regions[0].children;
|
||||
return regions;
|
||||
const chinaChildren = china?.children || [];
|
||||
// 部分行政区划数据的省级节点 parentId 为 0,另一部分挂在“中国(+86)”下,需合并两类根节点。
|
||||
const rootRegions = regions.filter(
|
||||
item => item !== china && ['0', '', 'null', 'undefined'].includes(String(item.parentId ?? ''))
|
||||
);
|
||||
const merged = [...chinaChildren, ...rootRegions];
|
||||
const seen = new Set();
|
||||
return merged.filter(item => {
|
||||
const key = String(item.id ?? item.value ?? item.title ?? '');
|
||||
if (seen.has(key)) return false;
|
||||
seen.add(key);
|
||||
return true;
|
||||
});
|
||||
},
|
||||
findRegionPathByName(options = [], regionName = '', parents = []) {
|
||||
const target = String(regionName || '').replace(/\s+/g, '');
|
||||
@@ -805,6 +834,32 @@ export default {
|
||||
});
|
||||
return labels;
|
||||
},
|
||||
setAddressRegionNames(field, labels = []) {
|
||||
if (!field) return;
|
||||
const normalized = labels.map(label => String(label || '').trim()).filter(Boolean);
|
||||
const province = normalized.find(label => /省|自治区|特别行政区/.test(label)) || normalized[0] || '';
|
||||
const city = normalized.filter(label => /市|州|盟/.test(label)).at(-1) || '';
|
||||
const district = normalized.filter(label => /区|县|旗/.test(label)).at(-1) || '';
|
||||
if (field.provinceName) field.model[field.provinceName] = province;
|
||||
if (field.cityName) field.model[field.cityName] = city;
|
||||
if (field.districtName) field.model[field.districtName] = district;
|
||||
},
|
||||
setAddressRegionNamesFromRow(field, row = {}) {
|
||||
const labels = [row.provinceName, row.cityName, row.districtName].filter(Boolean);
|
||||
if (labels.length) {
|
||||
this.setAddressRegionNames(field, labels);
|
||||
return;
|
||||
}
|
||||
const text = String(row.regionName || '').replace(/\s+/g, '');
|
||||
if (!text) return;
|
||||
const provinceMatch = text.match(/^.*?(?:省|自治区|特别行政区)/);
|
||||
const rest = provinceMatch ? text.slice(provinceMatch[0].length) : text;
|
||||
const cityMatch = rest.match(/.+?(?:市|州|盟)/);
|
||||
const districtMatch = cityMatch
|
||||
? rest.slice(cityMatch[0].length).match(/^[^市州盟]*?(?:区|县|旗)/)
|
||||
: rest.match(/.+?(?:区|县|旗)/);
|
||||
this.setAddressRegionNames(field, [provinceMatch?.[0], cityMatch?.[0], districtMatch?.[0]]);
|
||||
},
|
||||
handleAddressRegionChange(target, value) {
|
||||
const field = this.addressModel(target);
|
||||
const path = Array.isArray(value) ? value.map(item => String(item)) : [];
|
||||
@@ -813,6 +868,8 @@ export default {
|
||||
const labels = this.regionLabels(path);
|
||||
field.model[field.name] = labels.join('');
|
||||
field.model[field.regionCode] = path.at(-1) || '';
|
||||
field.model[field.siteCode] = '';
|
||||
this.setAddressRegionNames(field, labels);
|
||||
},
|
||||
syncAddressRegionPath(target) {
|
||||
const field = this.addressModel(target);
|
||||
@@ -822,6 +879,7 @@ export default {
|
||||
? codePath
|
||||
: this.findRegionPathByName(this.regionOptions, field.model[field.name]);
|
||||
this.addressRegionPaths = { ...this.addressRegionPaths, [target]: path };
|
||||
if (path.length) this.setAddressRegionNames(field, this.regionLabels(path));
|
||||
},
|
||||
syncAddressRegionPaths() {
|
||||
if (!this.regionOptions.length) return;
|
||||
@@ -880,19 +938,27 @@ export default {
|
||||
const date = this.normalizeDateValue(value);
|
||||
return date ? `${date} ${endOfDay ? '23:59:59' : '00:00:00'}` : '';
|
||||
},
|
||||
getRegionDisplay(target, fallback) {
|
||||
getRoadRegionDisplay(target, fallback) {
|
||||
const labels = this.regionLabels(this.addressRegionPaths[target] || []);
|
||||
return labels.length ? labels.join('/') : fallback;
|
||||
return labels.at(-1) || fallback;
|
||||
},
|
||||
getAddressDisplay(target, fallback) {
|
||||
const field = this.addressModel(target);
|
||||
const name = field?.model?.[field.name] || fallback;
|
||||
return this.isNonRoadAddress(target) ? name : this.getRoadRegionDisplay(target, name);
|
||||
},
|
||||
getRouteTitle(index) {
|
||||
const departureName =
|
||||
index === 0
|
||||
? this.getRegionDisplay('departure', this.form.departureName || '发货地址')
|
||||
: this.getRegionDisplay(
|
||||
? this.getAddressDisplay(
|
||||
'departure',
|
||||
this.form.departureName || '发货地址'
|
||||
)
|
||||
: this.getAddressDisplay(
|
||||
`route-${index - 1}`,
|
||||
this.form.routes[index - 1].departureName || '途经地'
|
||||
);
|
||||
const arrivalName = this.getRegionDisplay(
|
||||
const arrivalName = this.getAddressDisplay(
|
||||
`route-${index}`,
|
||||
this.form.routes[index].departureName || '途经地'
|
||||
);
|
||||
@@ -912,11 +978,14 @@ export default {
|
||||
return `${this.truncateRouteAddress(departure)}${separator}${this.truncateRouteAddress(arrival)}`;
|
||||
},
|
||||
getFinalRouteTitle() {
|
||||
const departureName = this.getRegionDisplay(
|
||||
const departureName = this.getAddressDisplay(
|
||||
`route-${this.form.routes.length - 1}`,
|
||||
this.lastRouteName
|
||||
);
|
||||
const arrivalName = this.getRegionDisplay('arrival', this.form.arrivalName || '收货地址');
|
||||
const arrivalName = this.getAddressDisplay(
|
||||
'arrival',
|
||||
this.form.arrivalName || '收货地址'
|
||||
);
|
||||
return `段${this.form.routes.length + 1}:${departureName} → ${arrivalName}`;
|
||||
},
|
||||
responseRecords(response) {
|
||||
@@ -965,6 +1034,9 @@ export default {
|
||||
latitude: 'departureLatitude',
|
||||
regionCode: 'departureRegionCode',
|
||||
siteCode: 'departureSiteCode',
|
||||
provinceName: 'departureProvinceName',
|
||||
cityName: 'departureCityName',
|
||||
districtName: 'departureDistrictName',
|
||||
}
|
||||
: null;
|
||||
}
|
||||
@@ -979,13 +1051,16 @@ export default {
|
||||
latitude: `${prefix}Latitude`,
|
||||
regionCode: `${prefix}RegionCode`,
|
||||
siteCode: `${prefix}SiteCode`,
|
||||
provinceName: `${prefix}ProvinceName`,
|
||||
cityName: `${prefix}CityName`,
|
||||
districtName: `${prefix}DistrictName`,
|
||||
};
|
||||
},
|
||||
addressTransportType(target) {
|
||||
if (target.startsWith('route-')) {
|
||||
return this.form.routes[Number(target.slice(6))]?.transportType || '';
|
||||
}
|
||||
return target === 'arrival' ? this.form.finalTransportType : '';
|
||||
return target === 'arrival' ? this.form.finalTransportType : this.form.routes[0]?.transportType || '';
|
||||
},
|
||||
addressTransportMode(target) {
|
||||
const type = this.addressTransportType(target);
|
||||
@@ -998,6 +1073,17 @@ export default {
|
||||
const value = String(type || '').trim().toLowerCase();
|
||||
return value === 'road' || value.includes('公路');
|
||||
},
|
||||
isNonRoadAddress(target) {
|
||||
const field = this.addressModel(target);
|
||||
if (!field) return false;
|
||||
const siteCode = String(field.model[field.siteCode] || '').trim();
|
||||
// 地址展示模式由实际选择的数据决定:有站点编码表示非公路站点名称,
|
||||
// 没有站点编码则保留省市区级联,避免切换运输方式时改写已有地址。
|
||||
return Boolean(siteCode && siteCode !== '/');
|
||||
},
|
||||
resolveAddressRegionCode(row = {}) {
|
||||
return row.regionCode || row.districtCode || row.areaCode || row.adcode || '';
|
||||
},
|
||||
openCommonAddress(target) {
|
||||
this.addressTarget = target;
|
||||
if (this.addressTransportMode(target) !== 'road') {
|
||||
@@ -1054,14 +1140,15 @@ export default {
|
||||
const target = this.addressModel(this.addressTarget);
|
||||
if (!target) return;
|
||||
const station = this.normalizeStation(row);
|
||||
target.model[target.name] = station.regionName || station.stationName;
|
||||
target.model[target.name] = station.stationName || station.regionName;
|
||||
target.model[target.address] = station.detailAddress;
|
||||
target.model[target.longitude] = station.longitude || '';
|
||||
target.model[target.latitude] = station.latitude || '';
|
||||
target.model[target.regionCode] = station.regionCode || '';
|
||||
target.model[target.regionCode] = this.resolveAddressRegionCode(station);
|
||||
target.model[target.siteCode] = station.stationCode;
|
||||
this.setAddressRegionNamesFromRow(target, station);
|
||||
this.stationDialogVisible = false;
|
||||
this.syncAddressRegionPath(this.addressTarget);
|
||||
this.loadRegionOptions().then(() => this.syncAddressRegionPath(this.addressTarget));
|
||||
},
|
||||
async loadAddressList() {
|
||||
this.addressLoading = true;
|
||||
@@ -1096,12 +1183,21 @@ export default {
|
||||
target.model[target.phone] = row.contactPhone || target.model[target.phone] || '';
|
||||
target.model[target.longitude] = row.longitude || '';
|
||||
target.model[target.latitude] = row.latitude || '';
|
||||
target.model[target.regionCode] = row.regionCode || '';
|
||||
target.model[target.regionCode] = this.resolveAddressRegionCode(row);
|
||||
target.model[target.siteCode] = '';
|
||||
this.setAddressRegionNamesFromRow(target, row);
|
||||
this.addressDialogVisible = false;
|
||||
this.syncAddressRegionPath(this.addressTarget);
|
||||
this.loadRegionOptions().then(() => this.syncAddressRegionPath(this.addressTarget));
|
||||
},
|
||||
handleAddressDetailClick(target) {
|
||||
if (this.addressTransportMode(target) !== 'road') {
|
||||
this.openCommonAddress(target);
|
||||
return;
|
||||
}
|
||||
this.openAddressMap(target);
|
||||
},
|
||||
openAddressMap(target) {
|
||||
if ((target.startsWith('route-') || target === 'arrival') && !this.isRoadTransportType(this.addressTransportType(target))) {
|
||||
if (this.addressTransportMode(target) !== 'road') {
|
||||
this.$message.info('非公路运输地址不能使用地图选择');
|
||||
return;
|
||||
}
|
||||
@@ -1203,6 +1299,9 @@ export default {
|
||||
const component = result.regeocode?.addressComponent || {};
|
||||
this.mapSelected.detailAddress =
|
||||
result.regeocode?.formattedAddress || this.mapSelected.detailAddress;
|
||||
this.mapSelected.provinceName = component.province || '';
|
||||
this.mapSelected.cityName = component.city || '';
|
||||
this.mapSelected.districtName = component.district || '';
|
||||
this.mapSelected.regionName = [component.province, component.city, component.district]
|
||||
.filter(Boolean)
|
||||
.join('');
|
||||
@@ -1228,6 +1327,8 @@ export default {
|
||||
target.model[target.longitude] = this.mapSelected.longitude;
|
||||
target.model[target.latitude] = this.mapSelected.latitude;
|
||||
target.model[target.regionCode] = this.mapSelected.regionCode || '';
|
||||
target.model[target.siteCode] = '';
|
||||
this.setAddressRegionNamesFromRow(target, this.mapSelected);
|
||||
this.mapDialogVisible = false;
|
||||
this.syncAddressRegionPath(this.mapTarget);
|
||||
},
|
||||
@@ -1445,6 +1546,8 @@ export default {
|
||||
'brand',
|
||||
'specification',
|
||||
'model',
|
||||
'materialCode',
|
||||
'deviceCode',
|
||||
'remark',
|
||||
].some(key => firstGoods[key]);
|
||||
|
||||
@@ -1489,6 +1592,8 @@ export default {
|
||||
brand: row.brand || '',
|
||||
specification: row.specification || row.spec || '',
|
||||
model: row.model || '',
|
||||
materialCode: row.materialCode || '',
|
||||
deviceCode: row.deviceCode || '',
|
||||
remark: row.remark || row.descriptionOne || '',
|
||||
};
|
||||
},
|
||||
@@ -1590,7 +1695,12 @@ export default {
|
||||
this.syncAddressRegionPaths();
|
||||
},
|
||||
addGoods(index) {
|
||||
this.form.goods.splice(index + 1, 0, { quantityUnit: quantityUnitOptions[0] });
|
||||
this.form.goods.splice(index + 1, 0, {
|
||||
quantityUnit: quantityUnitOptions[0],
|
||||
materialCode: '',
|
||||
deviceCode: '',
|
||||
remark: '',
|
||||
});
|
||||
},
|
||||
removeGoods(index) {
|
||||
if (this.form.goods.length > 1) this.form.goods.splice(index, 1);
|
||||
@@ -1707,13 +1817,20 @@ export default {
|
||||
await this.$refs.form.validate();
|
||||
if (!this.form.departureAddress || !this.form.arrivalAddress)
|
||||
return this.$message.warning('请填写收发货地址');
|
||||
if (!this.form.goods.some(item => item.cargoType && item.quantity > 0 && item.quantityUnit))
|
||||
return this.$message.warning('请至少填写一条有效货物');
|
||||
if (
|
||||
this.form.routes.some(item => !item.departureName || !item.transportType) ||
|
||||
!this.form.finalTransportType
|
||||
)
|
||||
return this.$message.warning('请完整填写途经地及运输方式');
|
||||
const invalidGoodsIndex = this.form.goods.findIndex(
|
||||
item =>
|
||||
!String(item.cargoType || '').trim() ||
|
||||
!(Number(item.quantity) > 0) ||
|
||||
!String(item.quantityUnit || '').trim()
|
||||
);
|
||||
if (invalidGoodsIndex >= 0)
|
||||
return this.$message.warning(`请完整填写第${invalidGoodsIndex + 1}条货物的类型、数量和数量单位`);
|
||||
const invalidRouteIndex = this.form.routes.findIndex(
|
||||
item => !item.departureName || !item.transportType
|
||||
);
|
||||
if (invalidRouteIndex >= 0)
|
||||
return this.$message.warning(`请完整填写第${invalidRouteIndex + 1}段途经地及运输方式`);
|
||||
if (!this.form.finalTransportType) return this.$message.warning('请填写最后一段运输方式');
|
||||
}
|
||||
const payload = {
|
||||
...this.form,
|
||||
@@ -1721,7 +1838,17 @@ export default {
|
||||
planEndTime: this.normalizeDateTimeValue(this.form.planEndTime, true),
|
||||
attachmentsJson: JSON.stringify(this.attachmentRows),
|
||||
routes: [
|
||||
...this.form.routes.map((route, index) => ({ ...route, segmentNo: `段${index + 1}` })),
|
||||
...this.form.routes.map((route, index) => ({
|
||||
...route,
|
||||
segmentNo: `段${index + 1}`,
|
||||
...(index === 0
|
||||
? {
|
||||
departureProvinceName: this.form.departureProvinceName,
|
||||
departureCityName: this.form.departureCityName,
|
||||
departureDistrictName: this.form.departureDistrictName,
|
||||
}
|
||||
: {}),
|
||||
})),
|
||||
{
|
||||
segmentNo: `段${this.form.routes.length + 1}`,
|
||||
departureName: this.form.arrivalName,
|
||||
@@ -1732,6 +1859,9 @@ export default {
|
||||
departureLatitude: this.form.arrivalLatitude,
|
||||
departureRegionCode: this.form.arrivalRegionCode,
|
||||
departureSiteCode: this.form.arrivalSiteCode,
|
||||
departureProvinceName: this.form.arrivalProvinceName,
|
||||
departureCityName: this.form.arrivalCityName,
|
||||
departureDistrictName: this.form.arrivalDistrictName,
|
||||
transportType: this.form.finalTransportType,
|
||||
},
|
||||
],
|
||||
@@ -1887,57 +2017,59 @@ export default {
|
||||
justify-content: flex-end;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.route-steps {
|
||||
.route-flow {
|
||||
position: relative;
|
||||
.el-steps {
|
||||
--el-text-color-placeholder: #a8abb2;
|
||||
padding: 4px 0;
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
bottom: 20px;
|
||||
left: 16px;
|
||||
width: 2px;
|
||||
background: #dcdfe6;
|
||||
content: '';
|
||||
}
|
||||
:deep(.el-step__main) {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.route-flow-row {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: 32px minmax(0, 1fr);
|
||||
column-gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
.route-flow-marker {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
background: #409eff;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
&--middle {
|
||||
background: #67c23a;
|
||||
}
|
||||
:deep(.el-step__title) {
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
:deep(.el-step__description) {
|
||||
padding: 12px 0 0;
|
||||
}
|
||||
:deep(.el-step__line) {
|
||||
background-color: #dcdfe6;
|
||||
}
|
||||
:deep(.el-step__icon) {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex-shrink: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
}
|
||||
.route-step-icon {
|
||||
display: inline-flex;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
background: #409eff;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
&--middle {
|
||||
background: #67c23a;
|
||||
}
|
||||
&--end {
|
||||
background: #e6a23c;
|
||||
}
|
||||
&--end {
|
||||
background: #e6a23c;
|
||||
}
|
||||
}
|
||||
.route-flow-body {
|
||||
min-width: 0;
|
||||
}
|
||||
.route-flow-segment {
|
||||
min-height: 48px;
|
||||
padding-left: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.route-node-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(420px, 1fr)) repeat(2, minmax(260px, 1fr));
|
||||
grid-template-columns: 300px 360px repeat(3, 300px);
|
||||
gap: 0 16px;
|
||||
align-items: start;
|
||||
:deep(.el-form-item) {
|
||||
@@ -1963,9 +2095,24 @@ export default {
|
||||
.route-address-name {
|
||||
flex: 0 0 220px;
|
||||
}
|
||||
.route-address-detail,
|
||||
.route-address-detail {
|
||||
flex: 0 0 300px;
|
||||
width: 300px;
|
||||
}
|
||||
.route-contact-actions :deep(.el-input) {
|
||||
flex: 1;
|
||||
flex: 0 0 200px;
|
||||
width: 200px;
|
||||
}
|
||||
:deep(.route-contact-form-item .el-input),
|
||||
:deep(.route-phone-form-item .el-input),
|
||||
:deep(.route-date-form-item .el-date-editor) {
|
||||
width: 200px;
|
||||
}
|
||||
:deep(.route-contact-actions) {
|
||||
width: auto;
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.address-picker-button {
|
||||
flex: 0 0 auto;
|
||||
@@ -1985,6 +2132,7 @@ export default {
|
||||
font-size: 16px;
|
||||
.route-segment-label {
|
||||
flex: 0 0 auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.route-title-path {
|
||||
display: inline-block;
|
||||
@@ -2010,6 +2158,10 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.required-asterisk {
|
||||
margin-left: 4px;
|
||||
color: #f56c6c;
|
||||
}
|
||||
.route-action-button {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user