修复业务模块bug
This commit is contained in:
@@ -84,12 +84,12 @@
|
||||
</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><span class="route-title-path">{{ getRouteTitle(index).replace(`段${index + 1}:`, '') }}</span><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 #title><div class="route-step-title"><span class="route-segment-label">段{{ index + 1 }}</span><span class="route-title-path">{{ getRouteTitle(index).replace(`段${index + 1}:`, '') }}</span><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 class="route-node-form">
|
||||
<el-form-item label="途经地" required class="route-address-form-item"
|
||||
><div class="route-address-inputs"
|
||||
><el-input v-model="route.departureName" class="route-address-name" readonly :disabled="!route.transportType" placeholder="请先选择运输类型" @click="openAddressMap(`route-${index}`)" /><el-input v-model="route.departureAddress" class="route-address-detail" readonly :disabled="!route.transportType" placeholder="请先选择运输类型" @click="openAddressMap(`route-${index}`)" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="List" :disabled="!route.transportType" @click="openCommonAddress(`route-${index}`)" /></el-tooltip></div
|
||||
><el-input v-model="route.departureName" class="route-address-name" readonly :disabled="!route.transportType" placeholder="请先选择运输方式" @click="openAddressMap(`route-${index}`)" /><el-input v-model="route.departureAddress" class="route-address-detail" readonly :disabled="!route.transportType" placeholder="请先选择运输方式" @click="openAddressMap(`route-${index}`)" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="List" :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>
|
||||
@@ -98,12 +98,12 @@
|
||||
</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><span class="route-title-path">{{ getFinalRouteTitle().replace(`段${form.routes.length + 1}:`, '') }}</span><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 #title><div class="route-step-title"><span class="route-segment-label">段{{ form.routes.length + 1 }}</span><span class="route-title-path">{{ getFinalRouteTitle().replace(`段${form.routes.length + 1}:`, '') }}</span><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 class="route-address-inputs"
|
||||
><el-input v-model="form.arrivalName" class="route-address-name" readonly :disabled="!form.finalTransportType" placeholder="请先选择运输类型" @click="openAddressMap('arrival')" /><el-input v-model="form.arrivalAddress" class="route-address-detail" readonly :disabled="!form.finalTransportType" placeholder="请先选择运输类型" @click="openAddressMap('arrival')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="List" :disabled="!form.finalTransportType" @click="openCommonAddress('arrival')" /></el-tooltip></div
|
||||
><el-input v-model="form.arrivalName" class="route-address-name" readonly :disabled="!form.finalTransportType" placeholder="请先选择运输方式" @click="openAddressMap('arrival')" /><el-input v-model="form.arrivalAddress" class="route-address-detail" readonly :disabled="!form.finalTransportType" placeholder="请先选择运输方式" @click="openAddressMap('arrival')" /><el-tooltip content="选择常用地址" placement="top"><el-button class="address-picker-button" type="primary" link :icon="List" :disabled="!form.finalTransportType" @click="openCommonAddress('arrival')" /></el-tooltip></div
|
||||
></el-form-item>
|
||||
<el-form-item label="联系人"
|
||||
><el-input v-model="form.arrivalContact" placeholder="请输入" /></el-form-item>
|
||||
@@ -140,25 +140,33 @@
|
||||
><el-select
|
||||
v-model="row.cargoName"
|
||||
filterable
|
||||
remote
|
||||
allow-create
|
||||
default-first-option
|
||||
clearable
|
||||
placeholder="请输入并选择"
|
||||
:loading="cargoNameLoading"
|
||||
:remote-method="searchCargoOptions"
|
||||
@visible-change="loadCargoOptions"
|
||||
placeholder="请选择或输入"
|
||||
:loading="isCargoOptionsLoading(row.cargoTypePath)"
|
||||
@visible-change="visible => visible && loadCargoOptionsByType(row.cargoTypePath)"
|
||||
@change="selectCargoName(row, $event)"
|
||||
><el-option
|
||||
v-for="cargo in cargoOptions"
|
||||
v-for="cargo in getCargoOptionsByType(row.cargoTypePath)"
|
||||
:key="cargo.id"
|
||||
:label="cargo.cargoName"
|
||||
:value="cargo.cargoName" /></el-select
|
||||
></template></el-table-column
|
||||
><el-table-column label="货物类型" min-width="130"
|
||||
><template #default="{ row }"
|
||||
><el-input
|
||||
v-model="row.cargoType"
|
||||
placeholder="从货物类型获取" /></template></el-table-column
|
||||
><el-table-column label="数量" width="132" class-name="master-editor__quantity-cell"
|
||||
><el-cascader
|
||||
v-model="row.cargoTypePath"
|
||||
:options="cargoTypeOptions"
|
||||
:props="cargoTypeCascaderProps"
|
||||
:placeholder="row.cargoType || '请选择'"
|
||||
clearable
|
||||
filterable
|
||||
:loading="cargoTypeLoading"
|
||||
@visible-change="visible => visible && loadCargoTypeOptions()"
|
||||
@change="value => handleCargoTypeChange(row, value)"
|
||||
/></template></el-table-column
|
||||
><el-table-column label="数量" width="180" class-name="master-editor__quantity-cell"
|
||||
><template #default="{ row }"
|
||||
><el-input
|
||||
v-model="row.quantity"
|
||||
@@ -232,7 +240,11 @@
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column label="文件名" min-width="240" align="center" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.originalName || row.name }}</template>
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="previewAttachment(row)">
|
||||
{{ attachmentName(row) }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件大小" width="120" align="center">
|
||||
<template #default="{ row }">{{ formatFileSize(row.size) }}</template>
|
||||
@@ -248,6 +260,37 @@
|
||||
</el-table>
|
||||
</div>
|
||||
</section>
|
||||
<el-dialog
|
||||
v-model="attachmentDocumentPreviewVisible"
|
||||
:title="attachmentPreviewFile.name || '附件预览'"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
width="90%"
|
||||
top="4vh"
|
||||
class="master-editor__attachment-viewer-dialog"
|
||||
>
|
||||
<open-file-viewer
|
||||
v-if="attachmentDocumentPreviewVisible && attachmentPreviewFile.url"
|
||||
:file="attachmentPreviewFile.url"
|
||||
:file-name="attachmentPreviewFile.name"
|
||||
:mime-type="attachmentPreviewFile.mimeType"
|
||||
width="100%"
|
||||
height="72vh"
|
||||
fit="contain"
|
||||
theme="auto"
|
||||
locale="zh-CN"
|
||||
:toolbar="attachmentViewerToolbar"
|
||||
:plugins="attachmentViewerPlugins"
|
||||
@unsupported="handleAttachmentPreviewUnsupported"
|
||||
@error="handleAttachmentPreviewError"
|
||||
/>
|
||||
</el-dialog>
|
||||
<el-image-viewer
|
||||
v-if="attachmentImagePreviewVisible"
|
||||
:url-list="attachmentImagePreviewUrls"
|
||||
:initial-index="attachmentImagePreviewIndex"
|
||||
@close="attachmentImagePreviewVisible = false"
|
||||
/>
|
||||
<el-dialog
|
||||
v-model="addressDialogVisible"
|
||||
title="选择常用地址"
|
||||
@@ -440,20 +483,38 @@ import { getList as getCommonAddressList } from '@/api/base/common-address';
|
||||
import { getList as getAirportMasterList } from '@/api/base/airport-master';
|
||||
import { getList as getPortTerminalList } from '@/api/base/port-terminal';
|
||||
import { getList as getRailwayStationList } from '@/api/base/railway-station';
|
||||
import { getList as getCargoTypeList } from '@/api/base/cargo-type';
|
||||
import { getList as getCommonCargoList } from '@/api/business/common-cargo';
|
||||
import { exportBlob, importBlob } from '@/api/common';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
import { List, Search } from '@element-plus/icons-vue';
|
||||
import { ElImageViewer } from 'element-plus';
|
||||
import { OpenFileViewer } from '@open-file-viewer/vue';
|
||||
import { fallbackPlugin, imagePlugin, officePlugin, pdfPlugin, textPlugin } from '@open-file-viewer/core';
|
||||
import '@open-file-viewer/core/style.css';
|
||||
import pdfWorkerSrc from 'pdfjs-dist/build/pdf.worker.mjs?url';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
||||
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||
const quantityUnitOptions = ['吨', '件', '方'];
|
||||
const attachmentViewerPlugins = [
|
||||
imagePlugin(),
|
||||
pdfPlugin({ workerSrc: pdfWorkerSrc, useFetchData: true }),
|
||||
officePlugin({ pdf: { workerSrc: pdfWorkerSrc, useFetchData: true } }),
|
||||
textPlugin(),
|
||||
fallbackPlugin(),
|
||||
];
|
||||
let amapLoader;
|
||||
import { getList as getCommonRouteList } from '@/api/business/common-route';
|
||||
import * as api from '@/api/business/master-order';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { isMobile } from '@/utils/validate';
|
||||
export default {
|
||||
components: {
|
||||
ElImageViewer,
|
||||
OpenFileViewer,
|
||||
},
|
||||
props: { id: [String, Number] },
|
||||
emits: ['back', 'dispatch'],
|
||||
data() {
|
||||
@@ -491,12 +552,28 @@ export default {
|
||||
commonCargoLoading: false,
|
||||
commonCargoRows: [],
|
||||
commonCargoPage: { current: 1, size: 10, total: 0 },
|
||||
cargoNameLoading: false,
|
||||
cargoOptions: [],
|
||||
cargoTypeLoading: false,
|
||||
cargoTypeOptions: [],
|
||||
cargoTypeFlatOptions: [],
|
||||
cargoOptionsMap: {},
|
||||
cargoOptionsLoadingMap: {},
|
||||
cargoImportVisible: false,
|
||||
cargoImportLoading: false,
|
||||
attachmentRows: [],
|
||||
selectedAttachmentRows: [],
|
||||
attachmentImagePreviewVisible: false,
|
||||
attachmentImagePreviewUrls: [],
|
||||
attachmentImagePreviewIndex: 0,
|
||||
attachmentDocumentPreviewVisible: false,
|
||||
attachmentPreviewFile: {},
|
||||
attachmentViewerPlugins,
|
||||
attachmentViewerToolbar: {
|
||||
download: true,
|
||||
fullscreen: true,
|
||||
print: true,
|
||||
rotate: true,
|
||||
zoom: true,
|
||||
},
|
||||
attachmentFileTypes: [
|
||||
'pdf',
|
||||
'bmp',
|
||||
@@ -539,11 +616,19 @@ export default {
|
||||
air: '空港机场',
|
||||
}[this.addressTransportMode(this.addressTarget)] || '站点';
|
||||
},
|
||||
cargoTypeCascaderProps() {
|
||||
return {
|
||||
value: 'id',
|
||||
label: 'label',
|
||||
children: 'children',
|
||||
emitPath: true,
|
||||
};
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.loading = true;
|
||||
try {
|
||||
await this.loadProjects();
|
||||
async mounted() {
|
||||
this.loading = true;
|
||||
try {
|
||||
await Promise.all([this.loadProjects(), this.loadCargoTypeOptions()]);
|
||||
if (this.id) {
|
||||
await this.loadDetail(this.id);
|
||||
}
|
||||
@@ -574,6 +659,7 @@ export default {
|
||||
attachmentsJson: detail.attachmentsJson || '[]',
|
||||
transportOrganizationType: '多式联运',
|
||||
};
|
||||
this.restoreGoodsCargoTypePaths();
|
||||
this.attachmentRows = this.parseJsonArray(this.form.attachmentsJson);
|
||||
this.selectedAttachmentRows = [];
|
||||
if (this.form.projectId) await this.loadContracts(this.form.projectId, false);
|
||||
@@ -897,31 +983,117 @@ export default {
|
||||
this.commonCargoLoading = false;
|
||||
}
|
||||
},
|
||||
async loadCargoOptions(visible) {
|
||||
if (!visible || this.cargoOptions.length) return;
|
||||
await this.searchCargoOptions('');
|
||||
},
|
||||
async searchCargoOptions(keyword) {
|
||||
this.cargoNameLoading = true;
|
||||
async loadCargoTypeOptions() {
|
||||
if (this.cargoTypeOptions.length || this.cargoTypeLoading) return;
|
||||
this.cargoTypeLoading = true;
|
||||
try {
|
||||
const response = await getCommonCargoList(1, 50, {
|
||||
allDept: 0,
|
||||
cargoName: keyword || undefined,
|
||||
});
|
||||
const data = response?.data?.data || response?.data || response || {};
|
||||
this.cargoOptions = data.records || [];
|
||||
const response = await getCargoTypeList(1, 9999, { allDept: 0 });
|
||||
const rows = this.responseRecords(response);
|
||||
this.cargoTypeOptions = this.buildCargoTypeTree(rows);
|
||||
} finally {
|
||||
this.cargoNameLoading = false;
|
||||
this.cargoTypeLoading = false;
|
||||
}
|
||||
},
|
||||
buildCargoTypeTree(rows = []) {
|
||||
const nodes = new Map();
|
||||
rows.forEach(row => {
|
||||
const id = String(row.id);
|
||||
nodes.set(id, {
|
||||
...row,
|
||||
id,
|
||||
label: row.cargoName || row.cargoTypeName || row.name || row.cargoCode || '',
|
||||
children: [],
|
||||
});
|
||||
});
|
||||
const roots = [];
|
||||
nodes.forEach(node => {
|
||||
const parentId = node.parentId == null ? '' : String(node.parentId);
|
||||
if (parentId && parentId !== '0' && nodes.has(parentId)) {
|
||||
nodes.get(parentId).children.push(node);
|
||||
} else {
|
||||
roots.push(node);
|
||||
}
|
||||
});
|
||||
this.cargoTypeFlatOptions = [];
|
||||
const normalize = (node, path = []) => {
|
||||
const nextPath = [...path, node.id];
|
||||
const children = node.children.map(child => normalize(child, nextPath));
|
||||
const normalized = { ...node, children };
|
||||
this.cargoTypeFlatOptions.push({ ...normalized, path: nextPath });
|
||||
return normalized;
|
||||
};
|
||||
return roots.map(node => normalize(node));
|
||||
},
|
||||
getCargoTypeByPath(path = []) {
|
||||
const normalizedPath = Array.isArray(path) ? path.map(value => String(value)) : [];
|
||||
const id = normalizedPath.at(-1);
|
||||
return this.cargoTypeFlatOptions.find(item => item.id === id) || null;
|
||||
},
|
||||
getCargoOptionsKey(path = []) {
|
||||
const cargoType = this.getCargoTypeByPath(path);
|
||||
return String(cargoType?.cargoCode || cargoType?.code || cargoType?.id || '');
|
||||
},
|
||||
getCargoOptionsByType(path = []) {
|
||||
const key = this.getCargoOptionsKey(path);
|
||||
return key ? this.cargoOptionsMap[key] || [] : [];
|
||||
},
|
||||
isCargoOptionsLoading(path = []) {
|
||||
const key = this.getCargoOptionsKey(path);
|
||||
return key ? Boolean(this.cargoOptionsLoadingMap[key]) : false;
|
||||
},
|
||||
async loadCargoOptionsByType(path = []) {
|
||||
const cargoType = this.getCargoTypeByPath(path);
|
||||
const key = this.getCargoOptionsKey(path);
|
||||
if (!key || !cargoType) return [];
|
||||
if (this.cargoOptionsMap[key] || this.cargoOptionsLoadingMap[key]) {
|
||||
return this.cargoOptionsMap[key] || [];
|
||||
}
|
||||
this.cargoOptionsLoadingMap = { ...this.cargoOptionsLoadingMap, [key]: true };
|
||||
try {
|
||||
const response = await getCommonCargoList(1, 500, {
|
||||
allDept: 0,
|
||||
secondCargoTypeName: cargoType.label,
|
||||
secondCargoTypeCode: cargoType.cargoCode || cargoType.code || '',
|
||||
});
|
||||
const options = this.responseRecords(response);
|
||||
this.cargoOptionsMap = { ...this.cargoOptionsMap, [key]: options };
|
||||
return options;
|
||||
} finally {
|
||||
this.cargoOptionsLoadingMap = { ...this.cargoOptionsLoadingMap, [key]: false };
|
||||
}
|
||||
},
|
||||
selectCargoName(goods, cargoName) {
|
||||
if (!cargoName) return;
|
||||
const cargo = this.cargoOptions.find(item => item.cargoName === cargoName);
|
||||
const cargo = this.getCargoOptionsByType(goods.cargoTypePath).find(
|
||||
item => item.cargoName === cargoName
|
||||
);
|
||||
if (!cargo) return;
|
||||
Object.assign(goods, this.normalizeCargoRow(cargo));
|
||||
Object.assign(goods, this.normalizeCargoRow(cargo, goods.cargoTypePath));
|
||||
},
|
||||
handleCargoTypeChange(goods, value) {
|
||||
const path = Array.isArray(value) ? value.map(item => String(item)) : [];
|
||||
const cargoType = this.getCargoTypeByPath(path);
|
||||
goods.cargoTypePath = path;
|
||||
goods.cargoType = cargoType?.label || '';
|
||||
goods.cargoTypeCode = cargoType?.cargoCode || cargoType?.code || cargoType?.id || '';
|
||||
goods.cargoName = '';
|
||||
goods.specification = '';
|
||||
goods.model = '';
|
||||
this.loadCargoOptionsByType(path);
|
||||
},
|
||||
restoreGoodsCargoTypePaths() {
|
||||
this.form.goods.forEach(goods => {
|
||||
if (Array.isArray(goods.cargoTypePath) && goods.cargoTypePath.length) return;
|
||||
const cargoType = this.cargoTypeFlatOptions.find(
|
||||
item =>
|
||||
String(item.cargoCode || item.code || '') === String(goods.cargoTypeCode || '') ||
|
||||
item.label === goods.cargoType
|
||||
);
|
||||
if (cargoType) goods.cargoTypePath = cargoType.path;
|
||||
});
|
||||
},
|
||||
selectCommonCargo(row) {
|
||||
const cargo = this.normalizeCargoRow(row);
|
||||
const cargo = this.normalizeCargoRow(row, this.resolveCargoTypePath(row));
|
||||
const firstGoods = this.form.goods[0];
|
||||
const isFirstGoodsEmpty =
|
||||
firstGoods &&
|
||||
@@ -943,12 +1115,35 @@ export default {
|
||||
}
|
||||
this.commonCargoVisible = false;
|
||||
},
|
||||
normalizeCargoRow(row = {}) {
|
||||
resolveCargoTypePath(row = {}) {
|
||||
return (
|
||||
this.cargoTypeFlatOptions.find(
|
||||
item =>
|
||||
String(item.cargoCode || item.code || '') ===
|
||||
String(row.secondCargoTypeCode || row.cargoTypeCode || '') ||
|
||||
item.label === (row.secondCargoTypeName || row.cargoType || row.goodsType)
|
||||
)?.path || []
|
||||
);
|
||||
},
|
||||
normalizeCargoRow(row = {}, cargoTypePath = this.resolveCargoTypePath(row)) {
|
||||
const cargoType = this.getCargoTypeByPath(cargoTypePath);
|
||||
return {
|
||||
...row,
|
||||
cargoName: row.cargoName || row.goodsName || '',
|
||||
cargoType:
|
||||
row.cargoType || row.goodsType || row.secondCargoTypeName || row.firstCargoTypeName || '',
|
||||
cargoType?.label ||
|
||||
row.cargoType ||
|
||||
row.goodsType ||
|
||||
row.secondCargoTypeName ||
|
||||
row.firstCargoTypeName ||
|
||||
'',
|
||||
cargoTypeCode:
|
||||
cargoType?.cargoCode ||
|
||||
cargoType?.code ||
|
||||
row.cargoTypeCode ||
|
||||
row.secondCargoTypeCode ||
|
||||
'',
|
||||
cargoTypePath,
|
||||
quantity: row.quantity || '',
|
||||
quantityUnit: row.quantityUnit || quantityUnitOptions[0],
|
||||
packageType: row.packageType || row.package || '',
|
||||
@@ -1096,13 +1291,54 @@ export default {
|
||||
if (number < 1024 * 1024) return `${(number / 1024).toFixed(1)}KB`;
|
||||
return `${(number / 1024 / 1024).toFixed(1)}MB`;
|
||||
},
|
||||
attachmentUrl(row = {}) {
|
||||
return row.url || row.link || row.fileUrl || row.domain || '';
|
||||
},
|
||||
attachmentName(row = {}) {
|
||||
return row.originalName || row.name || row.fileName || '附件';
|
||||
},
|
||||
attachmentExtension(row = {}) {
|
||||
const source = String(this.attachmentName(row) || this.attachmentUrl(row)).split('?')[0];
|
||||
const index = source.lastIndexOf('.');
|
||||
return index > -1 ? source.slice(index + 1).toLowerCase() : '';
|
||||
},
|
||||
isAttachmentImage(row) {
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(this.attachmentExtension(row));
|
||||
},
|
||||
previewAttachment(row) {
|
||||
const url = this.attachmentUrl(row);
|
||||
if (!url) {
|
||||
this.$message.warning('附件地址为空,无法预览');
|
||||
return;
|
||||
}
|
||||
if (this.isAttachmentImage(row)) {
|
||||
this.attachmentImagePreviewUrls = this.attachmentRows
|
||||
.filter(item => this.isAttachmentImage(item) && this.attachmentUrl(item))
|
||||
.map(item => this.attachmentUrl(item));
|
||||
this.attachmentImagePreviewIndex = Math.max(this.attachmentImagePreviewUrls.indexOf(url), 0);
|
||||
this.attachmentImagePreviewVisible = true;
|
||||
return;
|
||||
}
|
||||
this.attachmentPreviewFile = {
|
||||
name: this.attachmentName(row),
|
||||
url,
|
||||
mimeType: row.mimeType || row.contentType || '',
|
||||
};
|
||||
this.attachmentDocumentPreviewVisible = true;
|
||||
},
|
||||
handleAttachmentPreviewUnsupported() {
|
||||
this.$message.warning('当前文件暂不支持在线预览');
|
||||
},
|
||||
handleAttachmentPreviewError() {
|
||||
this.$message.error('附件预览失败');
|
||||
},
|
||||
downloadAttachment(row) {
|
||||
const url = row.url || row.link;
|
||||
const url = this.attachmentUrl(row);
|
||||
if (!url) {
|
||||
this.$message.warning('附件地址为空');
|
||||
return;
|
||||
}
|
||||
downloadFileByUrl(url, row.originalName || row.name || '附件');
|
||||
downloadFileByUrl(url, this.attachmentName(row));
|
||||
},
|
||||
handleAttachmentBatchDownload() {
|
||||
const rows = this.selectedAttachmentRows.length
|
||||
@@ -1111,6 +1347,21 @@ export default {
|
||||
rows.forEach(row => this.downloadAttachment(row));
|
||||
},
|
||||
async save(draft = false) {
|
||||
const phoneFields = [
|
||||
[this.form.departurePhone, '发货联系方式'],
|
||||
...this.form.routes.map((route, index) => [
|
||||
route.departurePhone,
|
||||
`第${index + 1}个途经地联系方式`,
|
||||
]),
|
||||
[this.form.arrivalPhone, '收货联系方式'],
|
||||
];
|
||||
const invalidPhone = phoneFields.find(
|
||||
([value]) => String(value || '').trim() && !isMobile(value)
|
||||
);
|
||||
if (invalidPhone) {
|
||||
this.$message.warning(`${invalidPhone[1]}格式不正确`);
|
||||
return false;
|
||||
}
|
||||
if (!draft) {
|
||||
await this.$refs.form.validate();
|
||||
if (!this.form.departureAddress || !this.form.arrivalAddress)
|
||||
@@ -1121,7 +1372,7 @@ export default {
|
||||
this.form.routes.some(item => !item.departureName || !item.transportType) ||
|
||||
!this.form.finalTransportType
|
||||
)
|
||||
return this.$message.warning('请完整填写途经地及运输类型');
|
||||
return this.$message.warning('请完整填写途经地及运输方式');
|
||||
}
|
||||
const payload = {
|
||||
...this.form,
|
||||
@@ -1145,15 +1396,18 @@ export default {
|
||||
return res?.data?.data || res?.data || res;
|
||||
},
|
||||
async saveDraft() {
|
||||
await this.save(true);
|
||||
const result = await this.save(true);
|
||||
if (result === false) return;
|
||||
this.$emit('back');
|
||||
},
|
||||
async confirmCreate() {
|
||||
await this.save();
|
||||
const result = await this.save();
|
||||
if (result === false) return;
|
||||
this.$emit('back');
|
||||
},
|
||||
async createAndDispatch() {
|
||||
const data = await this.save();
|
||||
if (data === false) return;
|
||||
const id = data?.id || data?.masterOrderId || data?.masterId;
|
||||
if (!id) {
|
||||
this.$message.error('保存成功但未获取到总单ID,无法进入调度');
|
||||
@@ -1223,7 +1477,7 @@ export default {
|
||||
}
|
||||
}
|
||||
:deep(.master-editor__quantity-cell .el-input) {
|
||||
width: 108px;
|
||||
width: 156px;
|
||||
}
|
||||
.section-head {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user