修复业务模块bug
This commit is contained in:
@@ -797,6 +797,7 @@
|
||||
placeholder="请输入"
|
||||
clearable
|
||||
maxlength="10"
|
||||
inputmode="numeric"
|
||||
:disabled="dialogReadonly"
|
||||
@input="handleTaskMileageInput"
|
||||
/>
|
||||
@@ -927,6 +928,7 @@
|
||||
placeholder="请输入"
|
||||
clearable
|
||||
maxlength="10"
|
||||
inputmode="numeric"
|
||||
:disabled="dialogReadonly"
|
||||
@input="handleTaskMileageInput"
|
||||
/>
|
||||
@@ -1347,6 +1349,7 @@
|
||||
placeholder="请输入里程"
|
||||
clearable
|
||||
maxlength="10"
|
||||
inputmode="numeric"
|
||||
:disabled="dialogReadonly"
|
||||
@input="handleTaskMileageInput"
|
||||
/>
|
||||
@@ -2334,6 +2337,7 @@
|
||||
v-model="detailBox"
|
||||
:title="`${config.title}详情`"
|
||||
append-to-body
|
||||
top="10px"
|
||||
width="96%"
|
||||
class="business-crud-page__detail-dialog"
|
||||
>
|
||||
@@ -2386,6 +2390,7 @@
|
||||
v-for="file in attachmentRows"
|
||||
:key="file.url || file.name || file.originalName"
|
||||
type="primary"
|
||||
@click="previewAttachment(file)"
|
||||
>
|
||||
{{ file.originalName || file.name || '-' }}
|
||||
</el-link>
|
||||
@@ -2502,15 +2507,44 @@
|
||||
</section-card>
|
||||
<div class="business-crud-page__waybill-detail-bottom">
|
||||
<section-card title="执行详情">
|
||||
<el-timeline v-if="waybillDetailProcessNodes.length">
|
||||
<el-timeline-item
|
||||
v-for="(node, index) in waybillDetailProcessNodes"
|
||||
:key="node.key || index"
|
||||
:timestamp="node.time || ''"
|
||||
>{{ node.name || node.nodeName || node.label }}</el-timeline-item
|
||||
<el-tabs v-model="waybillProcessDetailTab" type="border-card">
|
||||
<el-tab-pane label="打卡详情" name="punch">
|
||||
<el-timeline v-if="waybillDetailProcessNodes.length">
|
||||
<el-timeline-item
|
||||
v-for="(node, index) in waybillDetailProcessNodes"
|
||||
:key="node.key || index"
|
||||
:timestamp="node.time || ''"
|
||||
>{{ node.name || node.nodeName || node.label }}</el-timeline-item
|
||||
>
|
||||
</el-timeline>
|
||||
<el-empty v-else description="暂无打卡详情" :image-size="50" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="waybillHasRelatedVoucher"
|
||||
label="批量补录"
|
||||
name="batchSupplement"
|
||||
>
|
||||
</el-timeline>
|
||||
<el-empty v-else description="暂无执行详情" :image-size="50" />
|
||||
<div v-loading="waybillVoucherImagesLoading" class="business-crud-page__voucher-image-grid">
|
||||
<div
|
||||
v-for="(image, index) in waybillVoucherImages"
|
||||
:key="image.id || image.objectKey || index"
|
||||
class="business-crud-page__voucher-image-item"
|
||||
:title="image.imageName"
|
||||
@click="previewWaybillVoucherImage(index)"
|
||||
>
|
||||
<el-image :src="image.url" fit="cover" lazy />
|
||||
</div>
|
||||
<el-empty
|
||||
v-if="!waybillVoucherImagesLoading && !waybillVoucherImages.length"
|
||||
description="暂无凭证图片"
|
||||
:image-size="50"
|
||||
/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane label="司机上传" name="driverUpload">
|
||||
<el-empty description="暂无司机上传数据" :image-size="50" />
|
||||
</el-tab-pane> -->
|
||||
</el-tabs>
|
||||
</section-card>
|
||||
<section-card title="物流轨迹">
|
||||
<template #extra>
|
||||
@@ -2565,7 +2599,11 @@
|
||||
<el-table :data="attachmentRows" empty-text="暂无附件">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column label="文件名" min-width="260">
|
||||
<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 prop="description" label="附件描述" min-width="220" />
|
||||
<el-table-column label="文件大小" width="110">
|
||||
@@ -2587,6 +2625,38 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="attachmentDocumentPreviewVisible"
|
||||
:title="attachmentPreviewFile.name || '附件预览'"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
width="90%"
|
||||
top="4vh"
|
||||
>
|
||||
<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="waybillRouteChangeBox"
|
||||
title="变更运输路线"
|
||||
@@ -4674,6 +4744,7 @@ import {
|
||||
import {
|
||||
getDetail as getProcessConfigDetail,
|
||||
getList as getProcessConfigList,
|
||||
getVoucherImages as getProcessConfigVoucherImages,
|
||||
} from '@/api/business/process-config';
|
||||
import { getList as getCarrierCustomerList } from '@/api/vehicle/customer-archive';
|
||||
import { getList as getDriverList } from '@/api/transportCapacity/driver';
|
||||
@@ -4689,6 +4760,11 @@ import { applyTableMenuWidth } from '@/utils/table-menu';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
import { isMobile } from '@/utils/validate';
|
||||
import { List, Location, Rank, 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';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
@@ -4698,6 +4774,14 @@ const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
||||
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||
let amapLoader;
|
||||
|
||||
const attachmentViewerPlugins = [
|
||||
imagePlugin(),
|
||||
pdfPlugin({ workerSrc: pdfWorkerSrc, useFetchData: true }),
|
||||
officePlugin({ pdf: { workerSrc: pdfWorkerSrc, useFetchData: true } }),
|
||||
textPlugin(),
|
||||
fallbackPlugin(),
|
||||
];
|
||||
|
||||
const estimateMenuButtonCount = config => {
|
||||
const rowActions = (config.actions || []).filter(action => action !== 'batchComplete');
|
||||
return 3 + rowActions.length + (config.operations || []).length;
|
||||
@@ -4859,7 +4943,7 @@ const defaultDispatchRow = () => ({
|
||||
const taskCarrierTypes = ['承运商', '自运', '网货平台'];
|
||||
|
||||
export default {
|
||||
components: { WaybillImportDialog, Rank },
|
||||
components: { WaybillImportDialog, Rank, ElImageViewer, OpenFileViewer },
|
||||
name: 'BusinessCrudPage',
|
||||
props: {
|
||||
api: {
|
||||
@@ -4904,6 +4988,11 @@ export default {
|
||||
detailLoading: false,
|
||||
detailRow: {},
|
||||
waybillDetailProcessNodes: [],
|
||||
waybillProcessDetailTab: 'punch',
|
||||
waybillHasRelatedVoucher: false,
|
||||
waybillVoucherImages: [],
|
||||
waybillVoucherImagesLoading: false,
|
||||
waybillVoucherImagesLoaded: false,
|
||||
waybillRouteChangeBox: false,
|
||||
waybillRouteChangeTab: 'change',
|
||||
waybillRouteChangeRows: [],
|
||||
@@ -4989,6 +5078,19 @@ export default {
|
||||
selectedAttachmentRows: [],
|
||||
contractFileRows: [],
|
||||
selectedContractFileRows: [],
|
||||
attachmentImagePreviewVisible: false,
|
||||
attachmentImagePreviewUrls: [],
|
||||
attachmentImagePreviewIndex: 0,
|
||||
attachmentDocumentPreviewVisible: false,
|
||||
attachmentPreviewFile: {},
|
||||
attachmentViewerPlugins,
|
||||
attachmentViewerToolbar: {
|
||||
download: true,
|
||||
fullscreen: true,
|
||||
print: true,
|
||||
rotate: true,
|
||||
zoom: true,
|
||||
},
|
||||
transportCargoRows: [],
|
||||
taskFreightCurrency: 'CNY',
|
||||
shippingTemplateFreight: defaultShippingTemplateFreight(),
|
||||
@@ -5643,6 +5745,9 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
waybillProcessDetailTab(tab) {
|
||||
if (tab === 'batchSupplement') this.loadWaybillVoucherImages();
|
||||
},
|
||||
'form.transportType'(value, oldValue) {
|
||||
if (!this.shippingInfoFormEnabled || this.suppressTransportTypeClear) return;
|
||||
if (String(value ?? '') === String(oldValue ?? '')) return;
|
||||
@@ -5990,6 +6095,10 @@ export default {
|
||||
this.detailBox = true;
|
||||
this.detailLoading = true;
|
||||
this.detailRow = { ...row };
|
||||
this.waybillProcessDetailTab = 'punch';
|
||||
this.waybillHasRelatedVoucher = false;
|
||||
this.waybillVoucherImages = [];
|
||||
this.waybillVoucherImagesLoaded = false;
|
||||
const request =
|
||||
typeof this.api.getDetail === 'function'
|
||||
? this.api.getDetail(row.id)
|
||||
@@ -6039,8 +6148,9 @@ export default {
|
||||
return projectIds.includes(String(projectId));
|
||||
});
|
||||
if (!config?.id) return [];
|
||||
return getProcessConfigDetail(config.id).then(detailRes => {
|
||||
return getProcessConfigDetail(config.id, this.detailRow.id).then(detailRes => {
|
||||
const detail = detailRes?.data?.data || detailRes?.data || config;
|
||||
this.waybillHasRelatedVoucher = Boolean(detail.hasRelatedVoucher);
|
||||
return this.getProcessConfigEnabledNodes(detail);
|
||||
});
|
||||
})
|
||||
@@ -6052,6 +6162,25 @@ export default {
|
||||
})
|
||||
.catch(() => []);
|
||||
},
|
||||
loadWaybillVoucherImages() {
|
||||
if (!this.detailRow.id || this.waybillVoucherImagesLoading || this.waybillVoucherImagesLoaded) {
|
||||
return;
|
||||
}
|
||||
this.waybillVoucherImagesLoading = true;
|
||||
getProcessConfigVoucherImages(this.detailRow.id)
|
||||
.then(res => {
|
||||
this.waybillVoucherImages = extractRecords(res);
|
||||
this.waybillVoucherImagesLoaded = true;
|
||||
})
|
||||
.finally(() => {
|
||||
this.waybillVoucherImagesLoading = false;
|
||||
});
|
||||
},
|
||||
previewWaybillVoucherImage(index) {
|
||||
this.attachmentImagePreviewUrls = this.waybillVoucherImages.map(image => image.url).filter(Boolean);
|
||||
this.attachmentImagePreviewIndex = index;
|
||||
this.attachmentImagePreviewVisible = this.attachmentImagePreviewUrls.length > 0;
|
||||
},
|
||||
buildWaybillRouteNodes(rows = []) {
|
||||
const nodes = [];
|
||||
rows.forEach((row, rowIndex) => {
|
||||
@@ -7021,6 +7150,7 @@ export default {
|
||||
['quantity', 'mileage', 'unitPrice'].forEach(prop => {
|
||||
if (Number(this.form[prop]) === -1) this.form[prop] = '';
|
||||
});
|
||||
this.form.mileage = this.normalizeMileageValue(this.form.mileage);
|
||||
this.$nextTick(() => {
|
||||
this.suppressTransportTypeClear = false;
|
||||
});
|
||||
@@ -7291,6 +7421,7 @@ export default {
|
||||
});
|
||||
},
|
||||
applyShippingPlan(plan = {}) {
|
||||
this.suppressTransportTypeClear = true;
|
||||
this.form.planId = plan.id || '';
|
||||
this.form.planName = plan.planName || '';
|
||||
[
|
||||
@@ -7301,6 +7432,7 @@ export default {
|
||||
'transportMode',
|
||||
'transportTypeName',
|
||||
'transportModeName',
|
||||
'departureAddressId',
|
||||
'departureName',
|
||||
'departureAddress',
|
||||
'departureContact',
|
||||
@@ -7308,6 +7440,7 @@ export default {
|
||||
'departureProvince',
|
||||
'departureCity',
|
||||
'departureDistrict',
|
||||
'arrivalAddressId',
|
||||
'arrivalName',
|
||||
'arrivalAddress',
|
||||
'arrivalContact',
|
||||
@@ -7337,11 +7470,24 @@ export default {
|
||||
].forEach(prop => {
|
||||
if (firstGoods[prop] !== undefined) this.form[prop] = firstGoods[prop];
|
||||
});
|
||||
this.form.cargoTypePath = this.normalizeBillingCargoTypePath(firstGoods.cargoTypePath);
|
||||
this.initTaskInfoForm();
|
||||
this.ensureBillingCargoTypeOptions().then(() => {
|
||||
if (this.form.cargoTypePath.length) return;
|
||||
const cargoType = this.findBillingCargoTypeByCodeOrName({
|
||||
cargoTypeCode: this.form.cargoTypeCode,
|
||||
cargoType: this.form.cargoType,
|
||||
});
|
||||
if (cargoType?.path) this.form.cargoTypePath = cargoType.path;
|
||||
});
|
||||
if (this.isTaskFullMode) {
|
||||
this.initTaskFullCargoRows(goodsRows);
|
||||
}
|
||||
if (this.contractSelectEnabled) this.syncCurrentContractOption();
|
||||
this.$refs.crud?.validateField?.('planName');
|
||||
this.$nextTick(() => {
|
||||
this.suppressTransportTypeClear = false;
|
||||
});
|
||||
},
|
||||
clearShippingPlan() {
|
||||
this.form.planId = '';
|
||||
@@ -7417,7 +7563,7 @@ export default {
|
||||
this.form.quantityUnit =
|
||||
this.form.quantityUnit || taskInfo.quantityUnit || goodsInfo.quantityUnit || '吨';
|
||||
const mileage = this.form.mileage || taskInfo.mileage || goodsInfo.mileage || '';
|
||||
this.form.mileage = Number(mileage) === -1 ? '' : mileage;
|
||||
this.form.mileage = this.normalizeMileageValue(mileage);
|
||||
this.form.unitPrice = this.form.unitPrice || taskInfo.unitPrice || goodsInfo.unitPrice || '';
|
||||
['quantity', 'mileage', 'unitPrice'].forEach(prop => {
|
||||
if (Number(this.form[prop]) === -1) this.form[prop] = '';
|
||||
@@ -7702,6 +7848,11 @@ export default {
|
||||
.replace(/\D/g, '')
|
||||
.slice(0, 10);
|
||||
},
|
||||
normalizeMileageValue(value) {
|
||||
if (value === undefined || value === null || value === '' || Number(value) === -1) return '';
|
||||
const mileage = Number(value);
|
||||
return Number.isFinite(mileage) && mileage >= 0 ? String(Math.trunc(mileage)) : '';
|
||||
},
|
||||
handleDispatchMileageInput(value) {
|
||||
this.dispatchItemForm.mileage = String(value || '')
|
||||
.replace(/\D/g, '')
|
||||
@@ -9015,13 +9166,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.downloadUrl || 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));
|
||||
},
|
||||
handleBatchDownload() {
|
||||
const rows = this.selectedAttachmentRows.length
|
||||
@@ -12413,6 +12605,32 @@ export default {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__waybill-process-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__voucher-image-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
&__voucher-image-item {
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border: 1px solid #eff1f7;
|
||||
border-radius: 4px;
|
||||
|
||||
.el-image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__route-change-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
padding-top: 12px;
|
||||
|
||||
Reference in New Issue
Block a user