✨ 运单详情页新增异常上报卡片
在运费信息之后展示该运单关联的异常处置记录,表格沿用异常处置页的操作与权限, 列只保留上报人、异常类型、上报说明、承运商、最新跟进说明、状态。 跟进/编辑/详情弹窗在本页内完成,操作后局部刷新该卡片,不跳转列表页。
This commit is contained in:
@@ -2057,6 +2057,100 @@
|
||||
</div>
|
||||
</div>
|
||||
</section-card>
|
||||
<section-card title="异常上报">
|
||||
<el-table v-loading="waybillExceptionLoading" :data="waybillExceptionRows" border>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="reporterName" label="上报人" min-width="120" align="center" />
|
||||
<el-table-column
|
||||
prop="exceptionTypeName"
|
||||
label="异常类型"
|
||||
min-width="160"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="reportDescription"
|
||||
label="上报说明"
|
||||
min-width="180"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="carrierName"
|
||||
label="承运商"
|
||||
min-width="160"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="latestFollowContent"
|
||||
label="最新跟进说明"
|
||||
min-width="200"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="状态" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-link
|
||||
:type="row.disposalStatus === 'completed' ? 'info' : 'primary'"
|
||||
@click="
|
||||
openWaybillException(
|
||||
row,
|
||||
row.disposalStatus === 'completed' ? 'detail' : 'follow'
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ row.disposalStatusName || '-' }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<div class="waybill-manage-page__exception-actions">
|
||||
<template v-if="row.disposalStatus !== 'completed'">
|
||||
<el-link
|
||||
v-if="permission.exception_disposal_follow"
|
||||
type="primary"
|
||||
@click="openWaybillException(row, 'follow')"
|
||||
>
|
||||
跟进
|
||||
</el-link>
|
||||
<el-link
|
||||
v-if="permission.exception_disposal_edit"
|
||||
type="primary"
|
||||
@click="openWaybillException(row, 'edit')"
|
||||
>
|
||||
编辑
|
||||
</el-link>
|
||||
<el-link
|
||||
v-if="permission.exception_disposal_complete"
|
||||
type="primary"
|
||||
@click="completeWaybillExceptionRow(row)"
|
||||
>
|
||||
完成
|
||||
</el-link>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-link
|
||||
v-if="permission.exception_disposal_view"
|
||||
type="primary"
|
||||
@click="openWaybillException(row, 'detail')"
|
||||
>
|
||||
详情
|
||||
</el-link>
|
||||
<el-link
|
||||
v-if="permission.exception_disposal_edit"
|
||||
type="primary"
|
||||
@click="openWaybillException(row, 'edit')"
|
||||
>
|
||||
编辑
|
||||
</el-link>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section-card>
|
||||
<div class="waybill-manage-page__waybill-detail-bottom">
|
||||
<section-card title="执行详情">
|
||||
<el-tabs v-model="waybillProcessDetailTab" type="border-card">
|
||||
@@ -2356,6 +2450,284 @@
|
||||
</template>
|
||||
</component>
|
||||
|
||||
<el-dialog
|
||||
v-model="waybillExceptionDialog.visible"
|
||||
:title="waybillExceptionDialogTitle"
|
||||
:width="waybillExceptionDialog.mode === 'edit' ? '1080px' : '960px'"
|
||||
top="6vh"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<div
|
||||
v-loading="waybillExceptionDialog.loading"
|
||||
class="waybill-manage-page__exception-dialog"
|
||||
>
|
||||
<el-form
|
||||
v-if="waybillExceptionDialog.mode === 'edit'"
|
||||
ref="waybillExceptionEditFormRef"
|
||||
:model="waybillExceptionEditForm"
|
||||
:rules="waybillExceptionEditRules"
|
||||
label-position="right"
|
||||
label-width="96px"
|
||||
>
|
||||
<section-card title="运单信息">
|
||||
<el-descriptions :column="3" border size="small">
|
||||
<el-descriptions-item
|
||||
v-for="field in waybillExceptionWaybillFields"
|
||||
:key="field.prop"
|
||||
:label="field.label"
|
||||
>
|
||||
{{ waybillExceptionValue(field.prop) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section-card>
|
||||
|
||||
<section-card title="异常信息">
|
||||
<el-row :gutter="18">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="上报人">
|
||||
<span class="waybill-manage-page__exception-readonly">{{
|
||||
waybillExceptionValue('reporterName')
|
||||
}}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="上报时间">
|
||||
<span class="waybill-manage-page__exception-readonly">{{
|
||||
waybillExceptionValue('reportTime')
|
||||
}}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="异常类型" prop="exceptionType">
|
||||
<el-select
|
||||
v-model="waybillExceptionEditForm.exceptionType"
|
||||
placeholder="请选择"
|
||||
@change="handleWaybillExceptionTypeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in waybillExceptionTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="异常原因" prop="exceptionReason">
|
||||
<el-select
|
||||
v-model="waybillExceptionEditForm.exceptionReason"
|
||||
clearable
|
||||
placeholder="请选择"
|
||||
:disabled="!waybillExceptionEditForm.exceptionType"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in waybillExceptionReasonOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="上报说明" prop="reportDescription">
|
||||
<el-input
|
||||
v-model="waybillExceptionEditForm.reportDescription"
|
||||
type="textarea"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
:rows="3"
|
||||
placeholder="请输入"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="现场照片">
|
||||
<div class="waybill-manage-page__exception-edit-photos">
|
||||
<div
|
||||
v-for="(url, index) in waybillExceptionEditForm.scenePhotoList"
|
||||
:key="url"
|
||||
class="waybill-manage-page__exception-edit-photo"
|
||||
>
|
||||
<el-image
|
||||
:src="url"
|
||||
:preview-src-list="waybillExceptionEditForm.scenePhotoList"
|
||||
:initial-index="index"
|
||||
fit="cover"
|
||||
/>
|
||||
<el-link
|
||||
type="danger"
|
||||
:underline="false"
|
||||
@click="removeWaybillExceptionPhoto(index)"
|
||||
>删除</el-link
|
||||
>
|
||||
</div>
|
||||
<el-upload
|
||||
action="/api/blade-resource/oss/endpoint/put-file"
|
||||
name="file"
|
||||
:headers="waybillExceptionUploadHeaders"
|
||||
:show-file-list="false"
|
||||
:before-upload="beforeWaybillExceptionPhotoUpload"
|
||||
:on-success="handleWaybillExceptionPhotoSuccess"
|
||||
:on-error="handleWaybillExceptionPhotoError"
|
||||
>
|
||||
<div class="waybill-manage-page__exception-edit-photo-add">+ 添加</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</section-card>
|
||||
</el-form>
|
||||
|
||||
<template v-else>
|
||||
<section-card title="运单信息">
|
||||
<el-descriptions :column="3" border size="small">
|
||||
<el-descriptions-item
|
||||
v-for="field in waybillExceptionWaybillFields"
|
||||
:key="field.prop"
|
||||
:label="field.label"
|
||||
>
|
||||
{{ waybillExceptionValue(field.prop) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section-card>
|
||||
|
||||
<section-card title="异常信息">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item
|
||||
v-for="field in waybillExceptionDetailFields"
|
||||
:key="field.prop"
|
||||
:label="field.label"
|
||||
:span="field.span === 2 ? 2 : 1"
|
||||
>
|
||||
{{ waybillExceptionValue(field.prop) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section-card>
|
||||
|
||||
<section-card title="现场照片">
|
||||
<div class="waybill-manage-page__exception-photos">
|
||||
<el-image
|
||||
v-for="(url, index) in waybillExceptionPhotoUrls"
|
||||
:key="url"
|
||||
:src="url"
|
||||
:preview-src-list="waybillExceptionPhotoUrls"
|
||||
:initial-index="index"
|
||||
fit="cover"
|
||||
/>
|
||||
<el-empty
|
||||
v-if="!waybillExceptionPhotoUrls.length"
|
||||
description="暂无现场照片"
|
||||
:image-size="56"
|
||||
/>
|
||||
</div>
|
||||
</section-card>
|
||||
|
||||
<section-card v-if="waybillExceptionDialog.mode === 'follow'" title="跟进">
|
||||
<el-form
|
||||
ref="waybillExceptionFollowFormRef"
|
||||
:model="waybillExceptionFollowForm"
|
||||
:rules="waybillExceptionFollowRules"
|
||||
label-position="right"
|
||||
label-width="96px"
|
||||
>
|
||||
<el-row :gutter="18">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="跟进说明" prop="followContent">
|
||||
<el-input
|
||||
v-model="waybillExceptionFollowForm.followContent"
|
||||
type="textarea"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
:rows="3"
|
||||
placeholder="请输入"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="跟进附件">
|
||||
<vehicle-attachment-upload
|
||||
v-model="waybillExceptionFollowForm.attachments"
|
||||
:limit="20"
|
||||
:max-size="500"
|
||||
button-text="上传附件"
|
||||
:show-tip="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</section-card>
|
||||
|
||||
<section-card title="历史跟进">
|
||||
<el-table :data="waybillExceptionDetail.followRecords || []" border>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column
|
||||
v-for="column in waybillExceptionFollowColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:min-width="column.minWidth"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="附件" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<template v-if="parseWaybillExceptionAttachments(row.attachmentsJson).length">
|
||||
<el-link
|
||||
v-for="(file, index) in parseWaybillExceptionAttachments(
|
||||
row.attachmentsJson
|
||||
)"
|
||||
:key="index"
|
||||
type="primary"
|
||||
class="waybill-manage-page__exception-attachment-link"
|
||||
:href="file.url"
|
||||
target="_blank"
|
||||
>
|
||||
{{ file.name || '附件' + (index + 1) }}
|
||||
</el-link>
|
||||
</template>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section-card>
|
||||
</template>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button
|
||||
v-if="waybillExceptionDialog.mode === 'edit' && permission.exception_disposal_edit"
|
||||
type="primary"
|
||||
:loading="waybillExceptionDialog.submitting"
|
||||
@click="submitWaybillExceptionEdit"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="waybillExceptionDialog.mode === 'follow' && permission.exception_disposal_follow"
|
||||
type="primary"
|
||||
:loading="waybillExceptionDialog.submitting"
|
||||
@click="submitWaybillExceptionFollow"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="
|
||||
waybillExceptionDialog.mode === 'follow' && permission.exception_disposal_complete
|
||||
"
|
||||
type="primary"
|
||||
plain
|
||||
@click="completeWaybillExceptionFromDialog"
|
||||
>
|
||||
完成
|
||||
</el-button>
|
||||
<el-button @click="waybillExceptionDialog.visible = false">取消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="attachmentDocumentPreviewVisible"
|
||||
:title="attachmentPreviewFile.name || '附件预览'"
|
||||
@@ -3120,6 +3492,12 @@ import { h, resolveComponent } from 'vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
import {
|
||||
disposalStatusOptions,
|
||||
exceptionCategoryOptions,
|
||||
} from '@/option/transit/exception-disposal';
|
||||
import { getUploadHeaders } from '@/utils/upload';
|
||||
import * as exceptionDisposalApi from '@/api/transit/exception-disposal';
|
||||
|
||||
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
||||
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||
@@ -3349,6 +3727,32 @@ export default {
|
||||
waybillVoucherFolderView: false,
|
||||
waybillVoucherImagesLoading: false,
|
||||
waybillVoucherImagesLoaded: false,
|
||||
waybillExceptionRows: [],
|
||||
waybillExceptionLoading: false,
|
||||
waybillExceptionDialog: {
|
||||
visible: false,
|
||||
mode: 'follow',
|
||||
loading: false,
|
||||
submitting: false,
|
||||
},
|
||||
waybillExceptionDetail: {},
|
||||
waybillExceptionFollowForm: { followContent: '', attachments: [] },
|
||||
waybillExceptionFollowRules: {
|
||||
followContent: [{ max: 500, message: '跟进说明不能超过500个字符', trigger: 'blur' }],
|
||||
},
|
||||
waybillExceptionEditForm: {
|
||||
exceptionType: '',
|
||||
exceptionReason: '',
|
||||
reportDescription: '',
|
||||
scenePhotoList: [],
|
||||
},
|
||||
waybillExceptionEditRules: {
|
||||
exceptionType: [{ required: true, message: '请选择异常类型', trigger: 'change' }],
|
||||
reportDescription: [
|
||||
{ required: true, message: '请输入上报说明', trigger: 'blur' },
|
||||
{ max: 500, message: '上报说明不能超过500个字符', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
waybillRouteChangeBox: false,
|
||||
waybillRouteChangeTab: 'change',
|
||||
waybillRouteChangeRows: [],
|
||||
@@ -3648,6 +4052,54 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['permission', 'userInfo']),
|
||||
waybillExceptionDialogTitle() {
|
||||
return (
|
||||
{ detail: '异常详情', follow: '异常跟进', edit: '编辑异常' }[
|
||||
this.waybillExceptionDialog.mode
|
||||
] || '异常详情'
|
||||
);
|
||||
},
|
||||
waybillExceptionWaybillFields() {
|
||||
return [
|
||||
{ label: '运单号', prop: 'waybillNo' },
|
||||
{ label: '配载单号/总单号', prop: 'loadingOrMasterNo' },
|
||||
{ label: '车牌号', prop: 'vehicleNo' },
|
||||
{ label: '项目', prop: 'projectName' },
|
||||
{ label: '承运商', prop: 'carrierName' },
|
||||
];
|
||||
},
|
||||
waybillExceptionDetailFields() {
|
||||
return [
|
||||
{ label: '上报人', prop: 'reporterName' },
|
||||
{ label: '上报时间', prop: 'reportTime' },
|
||||
{ label: '异常类型', prop: 'exceptionTypeName' },
|
||||
{ label: '异常原因', prop: 'exceptionReason' },
|
||||
{ label: '上报说明', prop: 'reportDescription', span: 2 },
|
||||
];
|
||||
},
|
||||
waybillExceptionFollowColumns() {
|
||||
return [
|
||||
{ label: '跟进说明', prop: 'followContent', minWidth: 260 },
|
||||
{ label: '跟进人', prop: 'followUserName', minWidth: 130 },
|
||||
{ label: '跟进时间', prop: 'followTime', minWidth: 170 },
|
||||
];
|
||||
},
|
||||
waybillExceptionTypeOptions() {
|
||||
return exceptionCategoryOptions.map(item => ({ label: item.label, value: item.value }));
|
||||
},
|
||||
waybillExceptionReasonOptions() {
|
||||
return (
|
||||
exceptionCategoryOptions.find(
|
||||
item => item.value === this.waybillExceptionEditForm.exceptionType
|
||||
)?.children || []
|
||||
);
|
||||
},
|
||||
waybillExceptionPhotoUrls() {
|
||||
return this.parseWaybillExceptionPhotos(this.waybillExceptionDetail.scenePhotos);
|
||||
},
|
||||
waybillExceptionUploadHeaders() {
|
||||
return getUploadHeaders();
|
||||
},
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.canCreate,
|
||||
@@ -4629,6 +5081,7 @@ export default {
|
||||
this.waybillVoucherFolder = null;
|
||||
this.waybillVoucherFolderView = false;
|
||||
this.waybillVoucherImagesLoaded = false;
|
||||
this.waybillExceptionRows = [];
|
||||
const request =
|
||||
typeof this.api.getDetail === 'function'
|
||||
? this.api.getDetail(row.id)
|
||||
@@ -4639,6 +5092,7 @@ export default {
|
||||
this.detailRow = detail;
|
||||
this.loadWaybillPunchRecords();
|
||||
this.loadWaybillVoucherImages();
|
||||
this.loadWaybillExceptions(detail);
|
||||
if (detail.contractId) {
|
||||
return getContractDetail(detail.contractId)
|
||||
.then(contractRes => {
|
||||
@@ -4668,6 +5122,206 @@ export default {
|
||||
this.detailLoading = false;
|
||||
});
|
||||
},
|
||||
// 异常处置列表接口不支持按 waybillId 精确过滤,只有 waybillNo 模糊匹配,
|
||||
// 而运单号存在前缀包含(YD001 会命中 YD0011),故取回后必须再按 waybillId 精确筛一次。
|
||||
// 多取一页降低「同前缀运单占满首页」导致漏数据的概率。
|
||||
// 注意 String() 比较只是避免类型不一致,挡不住 int64 精度:运单 id 超出 JS 安全整数范围,
|
||||
// 两个相差很小的 id 在响应 JSON 解析时就已被解析成同一个浮点值,此处无从分辨。
|
||||
async loadWaybillExceptions(detail) {
|
||||
const waybillId = detail?.id;
|
||||
const waybillNo = detail?.waybillNo;
|
||||
if (!waybillId || !waybillNo) {
|
||||
this.waybillExceptionRows = [];
|
||||
return;
|
||||
}
|
||||
this.waybillExceptionLoading = true;
|
||||
try {
|
||||
const res = await exceptionDisposalApi.getList(1, 100, { waybillNo });
|
||||
const data = res?.data?.data || res?.data || res || {};
|
||||
this.waybillExceptionRows = (data.records || [])
|
||||
.filter(item => String(item.waybillId) === String(waybillId))
|
||||
.map(this.decorateWaybillExceptionRow);
|
||||
} catch (error) {
|
||||
this.waybillExceptionRows = [];
|
||||
} finally {
|
||||
this.waybillExceptionLoading = false;
|
||||
}
|
||||
},
|
||||
decorateWaybillExceptionRow(row) {
|
||||
return {
|
||||
...row,
|
||||
exceptionTypeName: this.waybillExceptionName(row.exceptionType),
|
||||
disposalStatusName:
|
||||
disposalStatusOptions.find(item => item.value === row.disposalStatus)?.label ||
|
||||
row.disposalStatus ||
|
||||
'-',
|
||||
};
|
||||
},
|
||||
waybillExceptionName(value) {
|
||||
if (!value) return '-';
|
||||
// 一级存中文大类名(如「交通异常」),二级存子类名(如「货损」),两级都查
|
||||
const group = exceptionCategoryOptions.find(item => item.value === value);
|
||||
if (group) return group.label;
|
||||
for (const item of exceptionCategoryOptions) {
|
||||
const match = item.children.find(child => child.value === value);
|
||||
if (match) return match.label;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
async openWaybillException(row, mode) {
|
||||
this.waybillExceptionDialog = {
|
||||
visible: true,
|
||||
mode,
|
||||
loading: true,
|
||||
submitting: false,
|
||||
};
|
||||
this.waybillExceptionFollowForm = { followContent: '', attachments: [] };
|
||||
try {
|
||||
const res = await exceptionDisposalApi.getDetail(row.id);
|
||||
const detail = res?.data?.data || res?.data || res || {};
|
||||
this.waybillExceptionDetail = this.decorateWaybillExceptionRow(detail);
|
||||
if (mode === 'edit') {
|
||||
this.waybillExceptionEditForm = {
|
||||
exceptionType: this.waybillExceptionDetail.exceptionType || '',
|
||||
exceptionReason: this.waybillExceptionDetail.exceptionReason || '',
|
||||
reportDescription: this.waybillExceptionDetail.reportDescription || '',
|
||||
scenePhotoList: this.parseWaybillExceptionPhotos(
|
||||
this.waybillExceptionDetail.scenePhotos
|
||||
),
|
||||
};
|
||||
}
|
||||
} finally {
|
||||
this.waybillExceptionDialog.loading = false;
|
||||
}
|
||||
},
|
||||
waybillExceptionValue(prop) {
|
||||
const value = this.waybillExceptionDetail[prop];
|
||||
return value === null || value === undefined || value === '' ? '-' : value;
|
||||
},
|
||||
handleWaybillExceptionTypeChange() {
|
||||
// 一级类型变了,旧二级可能不属于新类型
|
||||
const stillValid = this.waybillExceptionReasonOptions.some(
|
||||
item => item.value === this.waybillExceptionEditForm.exceptionReason
|
||||
);
|
||||
if (!stillValid) {
|
||||
this.waybillExceptionEditForm.exceptionReason = '';
|
||||
}
|
||||
},
|
||||
beforeWaybillExceptionPhotoUpload(file) {
|
||||
const validType = ['image/jpeg', 'image/png', 'image/jpg', 'image/bmp'].includes(file.type);
|
||||
if (!validType) {
|
||||
this.$message.error('仅支持 JPG、PNG、BMP 图片');
|
||||
return false;
|
||||
}
|
||||
if (file.size / 1024 / 1024 >= 5) {
|
||||
this.$message.error('图片大小不能超过 5MB');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
handleWaybillExceptionPhotoSuccess(res) {
|
||||
if (res.code === 200 && res.data) {
|
||||
const url = res.data.link || res.data.url || res.data.domain || '';
|
||||
if (url) {
|
||||
this.waybillExceptionEditForm.scenePhotoList = [
|
||||
...this.waybillExceptionEditForm.scenePhotoList,
|
||||
url,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
this.$message.error(res.msg || '上传失败');
|
||||
}
|
||||
},
|
||||
handleWaybillExceptionPhotoError() {
|
||||
this.$message.error('上传失败');
|
||||
},
|
||||
removeWaybillExceptionPhoto(index) {
|
||||
const list = [...this.waybillExceptionEditForm.scenePhotoList];
|
||||
list.splice(index, 1);
|
||||
this.waybillExceptionEditForm.scenePhotoList = list;
|
||||
},
|
||||
parseWaybillExceptionPhotos(value) {
|
||||
if (!value) return [];
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
if (Array.isArray(parsed)) return parsed.filter(Boolean);
|
||||
} catch (error) {
|
||||
return String(value)
|
||||
.split(',')
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
parseWaybillExceptionAttachments(value) {
|
||||
if (!value) return [];
|
||||
if (Array.isArray(value)) return value;
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
return Array.isArray(parsed) ? parsed.filter(item => item && item.url) : [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
async submitWaybillExceptionEdit() {
|
||||
await this.$refs.waybillExceptionEditFormRef.validate();
|
||||
this.waybillExceptionDialog.submitting = true;
|
||||
try {
|
||||
await exceptionDisposalApi.update({
|
||||
id: this.waybillExceptionDetail.id,
|
||||
exceptionType: this.waybillExceptionEditForm.exceptionType,
|
||||
exceptionReason: this.waybillExceptionEditForm.exceptionReason,
|
||||
reportDescription: this.waybillExceptionEditForm.reportDescription,
|
||||
scenePhotos: this.waybillExceptionEditForm.scenePhotoList.join(','),
|
||||
});
|
||||
this.$message.success('编辑成功');
|
||||
this.waybillExceptionDialog.visible = false;
|
||||
this.refreshWaybillExceptions();
|
||||
} finally {
|
||||
this.waybillExceptionDialog.submitting = false;
|
||||
}
|
||||
},
|
||||
async submitWaybillExceptionFollow() {
|
||||
await this.$refs.waybillExceptionFollowFormRef.validate();
|
||||
const followContent = (this.waybillExceptionFollowForm.followContent || '').trim();
|
||||
const attachmentsJson = this.waybillExceptionFollowForm.attachments.length
|
||||
? JSON.stringify(this.waybillExceptionFollowForm.attachments)
|
||||
: '';
|
||||
// 后端要求二者至少有其一
|
||||
if (!followContent && !attachmentsJson) {
|
||||
this.$message.warning('请填写跟进说明或上传附件');
|
||||
return;
|
||||
}
|
||||
this.waybillExceptionDialog.submitting = true;
|
||||
try {
|
||||
await exceptionDisposalApi.follow({
|
||||
id: this.waybillExceptionDetail.id,
|
||||
followContent,
|
||||
attachmentsJson,
|
||||
});
|
||||
this.$message.success('跟进成功');
|
||||
this.waybillExceptionDialog.visible = false;
|
||||
this.refreshWaybillExceptions();
|
||||
} finally {
|
||||
this.waybillExceptionDialog.submitting = false;
|
||||
}
|
||||
},
|
||||
async completeWaybillExceptionRow(row) {
|
||||
await this.$confirm('确认完成该异常处置?', '提示', { type: 'warning' });
|
||||
await exceptionDisposalApi.complete({ id: row.id });
|
||||
this.$message.success('完成成功');
|
||||
this.refreshWaybillExceptions();
|
||||
},
|
||||
async completeWaybillExceptionFromDialog() {
|
||||
await this.$confirm('确认完成该异常处置?', '提示', { type: 'warning' });
|
||||
await exceptionDisposalApi.complete({ id: this.waybillExceptionDetail.id });
|
||||
this.$message.success('完成成功');
|
||||
this.waybillExceptionDialog.visible = false;
|
||||
this.refreshWaybillExceptions();
|
||||
},
|
||||
refreshWaybillExceptions() {
|
||||
this.loadWaybillExceptions(this.detailRow);
|
||||
},
|
||||
closeDetail() {
|
||||
this.destroyWaybillLocateMap();
|
||||
this.destroyWaybillTrackMap();
|
||||
@@ -10046,6 +10700,81 @@ export default {
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
&__exception-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__exception-dialog {
|
||||
padding: 4px 0 0;
|
||||
|
||||
:deep(.section-card + .section-card) {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&__exception-readonly {
|
||||
color: #606266;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
&__exception-attachment-link {
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
&__exception-photos {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
min-height: 80px;
|
||||
|
||||
:deep(.el-image) {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
border: 1px solid #eff1f7;
|
||||
}
|
||||
}
|
||||
|
||||
&__exception-edit-photos {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__exception-edit-photo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
:deep(.el-image) {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
border: 1px solid #eff1f7;
|
||||
}
|
||||
}
|
||||
|
||||
&__exception-edit-photo-add {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
border: 1px dashed #dcdfe6;
|
||||
border-radius: 4px;
|
||||
color: #909399;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: #409eff;
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
&__waybill-detail-summary {
|
||||
:deep(.el-card__body) {
|
||||
padding: 18px 22px;
|
||||
|
||||
Reference in New Issue
Block a user