修复订单货柜预约与排车维护界面
This commit is contained in:
@@ -15,7 +15,9 @@ import type { DispatchRoute, DispatchRouteCommand, DispatchRouteStop } from '../
|
||||
import { DispatchInputError, requireVersion } from '../dispatchContracts'
|
||||
import { dispatchExceptionLabels, dispatchReturnDirectionLabels, canDispatchAction, dispatchActionLabels, dispatchRejectionReason, dispatchReviewAttachmentFields, dispatchReviewEvidence } from '../dispatchPresentation'
|
||||
import { isDefiniteDispatchRejection, useDispatchCommandRecovery, type PendingDispatchCommand } from '../dispatchCommandRecovery'
|
||||
import DispatchResourceFields from './DispatchResourceFields.vue'
|
||||
import DispatchVehicleMaintenanceForm from './DispatchVehicleMaintenanceForm.vue'
|
||||
import DispatchVehicleMaintenanceFees from './DispatchVehicleMaintenanceFees.vue'
|
||||
import { blankVehicleMaintenance, vehicleMaintenancePayload } from '../dispatchVehicleMaintenance'
|
||||
import DispatchEvidenceFiles from './DispatchEvidenceFiles.vue'
|
||||
|
||||
const open = defineModel<boolean>({ default: false })
|
||||
@@ -42,7 +44,7 @@ const isReview = computed(() => ['DISPATCH_REVIEW', 'LOADING_REVIEW'].includes(c
|
||||
const approvalBlock = computed(() => isReview.value && detail.value?.actions[currentAction.value]?.blockCode === 'APPROVAL_BLOCKED' ? detail.value.actions[currentAction.value]?.blockReason : null)
|
||||
const reviewTime = (value: string | null | undefined) => value ? new Intl.DateTimeFormat('zh-CN', { timeZone: 'Asia/Shanghai', dateStyle: 'short', timeStyle: 'short', hour12: false }).format(new Date(value)) : '未填写'
|
||||
const exception = reactive({ exceptionType: '' as DispatchExceptionType | '', returnDirection: '' as DispatchReturnDirection | '', description: '', imageFileIds: [] as string[] })
|
||||
const form = reactive({ publishLooseboardDemand: true, plannedDepartureAt: '', estimatedArrivalAt: '', remark: '', decision: 'APPROVED' as 'APPROVED' | 'REJECTED', reason: '' })
|
||||
const form = reactive({ publishLooseboardDemand: true, plannedDepartureAt: '', estimatedArrivalAt: '', maintenance: blankVehicleMaintenance(), remark: '', decision: 'APPROVED' as 'APPROVED' | 'REJECTED', reason: '' })
|
||||
let generation = 0
|
||||
let editorRequestKey = ''
|
||||
const cargoAction = computed(() => ['ADD_CARGO', 'REMOVE_CARGO'].includes(currentAction.value))
|
||||
@@ -67,6 +69,7 @@ async function load() {
|
||||
if (sequence !== generation) return
|
||||
if (value.dispatchNo !== no) throw new DispatchInputError('排车业务号不一致,请重新打开')
|
||||
detail.value = value
|
||||
form.maintenance = value.vehicleInfo.maintenance ? { ...value.vehicleInfo.maintenance } : blankVehicleMaintenance()
|
||||
Object.assign(exception, { exceptionType: '', returnDirection: '', description: '', imageFileIds: [] })
|
||||
const oldVehicle = value.vehicleInfo.vehicle
|
||||
vehicle.value = oldVehicle ? { mode: oldVehicle.mode, vehicleId: oldVehicle.vehicleId, plate: oldVehicle.plate, carrierName: oldVehicle.carrierName, capacity: oldVehicle.capacity ? { ...oldVehicle.capacity } : null, evidenceFileIds: [...oldVehicle.evidenceFileIds] } : blankVehicle()
|
||||
@@ -107,7 +110,7 @@ function payload(): object {
|
||||
case 'MARK_EXCEPTION':
|
||||
if (!exception.exceptionType) throw new DispatchInputError('请选择异常类型')
|
||||
return { ...common, exceptionType: exception.exceptionType, returnDirection: exception.returnDirection || null, description: exception.description.trim() || null, imageFileIds: [...exception.imageFileIds] } satisfies MarkDispatchException
|
||||
case 'EDIT': return { ...common, publishLooseboardDemand: form.publishLooseboardDemand, vehicle: vehicle.value, driver: driver.value, plannedDepartureAt: form.plannedDepartureAt || null, estimatedArrivalAt: form.estimatedArrivalAt || null, remark: form.remark || null } satisfies UpdateDispatch
|
||||
case 'EDIT': return { ...common, publishLooseboardDemand: form.publishLooseboardDemand, vehicle: vehicle.value, driver: driver.value, maintenance: vehicleMaintenancePayload(form.maintenance), plannedDepartureAt: form.plannedDepartureAt || null, estimatedArrivalAt: form.estimatedArrivalAt || null, remark: form.remark || null } satisfies UpdateDispatch
|
||||
case 'DISPATCH_REVIEW': case 'LOADING_REVIEW':
|
||||
if (form.decision === 'APPROVED' && approvalBlock.value) throw new DispatchInputError(approvalBlock.value)
|
||||
if (form.decision === 'REJECTED' && !form.reason.trim()) throw new DispatchInputError('驳回时必须填写原因')
|
||||
@@ -231,9 +234,16 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
<DispatchEvidenceFiles v-model="exception.imageFileIds" :dispatch-no="currentNo" kind="EXCEPTION" label="异常图片" save-hint="上传后点击保存,图片与本次异常一起登记。" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.EXCEPTION = $event" />
|
||||
</template>
|
||||
<template v-else-if="vehicleEditor">
|
||||
<section class="density-dialog-section" data-tone="work" aria-label="本车资源登记"><h3 class="density-dialog-section__title">车辆与司机</h3><DispatchResourceFields continuous v-model:vehicle="vehicle" v-model:driver="driver" :disabled="frozen || loading || uploadingEvidence || !allowed" /></section>
|
||||
<el-form-item v-if="detail?.taskType === 'DELIVERY'" label="散板需求"><el-checkbox v-model="form.publishLooseboardDemand" :disabled="frozen || loading || uploadingEvidence || !allowed">发布公共散板需求</el-checkbox></el-form-item>
|
||||
<section class="density-dialog-section" data-tone="work" aria-label="本车时间登记"><h3 class="density-dialog-section__title">排车时间</h3><table class="density-table density-table--editable workflow-editor-table"><tbody><tr><td><el-form-item label="计划发车时间"><el-date-picker v-model="form.plannedDepartureAt" :disabled="frozen || loading || uploadingEvidence || !allowed" type="datetime" value-format="YYYY-MM-DDTHH:mm:ssZ" placeholder="请选择计划发车时间" /></el-form-item></td><td><el-form-item label="预计到达时间"><el-date-picker v-model="form.estimatedArrivalAt" :disabled="frozen || loading || uploadingEvidence || !allowed" type="datetime" value-format="YYYY-MM-DDTHH:mm:ssZ" placeholder="请选择预计到达时间" /></el-form-item></td></tr></tbody></table></section>
|
||||
<DispatchVehicleMaintenanceForm :key="currentNo" :detail="detail" v-model:vehicle="vehicle" v-model:driver="driver" v-model:maintenance="form.maintenance" v-model:planned-departure-at="form.plannedDepartureAt" v-model:estimated-arrival-at="form.estimatedArrivalAt" v-model:publish-looseboard-demand="form.publishLooseboardDemand" :disabled="frozen || loading || uploadingEvidence || !allowed">
|
||||
<template #fees><DispatchVehicleMaintenanceFees :dispatch-no="currentNo" :deliveries="detail.documents.deliveries" /></template>
|
||||
<template #attachments>
|
||||
<div class="workflow-photo-grid density-dialog-sections" aria-label="车辆司机照片">
|
||||
<DispatchEvidenceFiles photo-card v-model="vehicle.evidenceFileIds" :dispatch-no="currentNo" kind="VEHICLE" label="车辆图片" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.VEHICLE = $event" />
|
||||
<DispatchEvidenceFiles photo-card v-model="driverPhotos" :dispatch-no="currentNo" kind="DRIVER_PHOTO" label="司机照片" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.DRIVER_PHOTO = $event" />
|
||||
<DispatchEvidenceFiles photo-card v-if="driver.evidence" v-model="driver.evidence.fileIds" :dispatch-no="currentNo" kind="DRIVER" label="驾驶证照片" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.DRIVER = $event" />
|
||||
</div>
|
||||
</template>
|
||||
</DispatchVehicleMaintenanceForm>
|
||||
</template>
|
||||
<template v-else-if="currentAction === 'DISPATCH_REVIEW' || currentAction === 'LOADING_REVIEW'">
|
||||
<section class="density-dialog-section" data-tone="source" aria-label="本车审核依据"><table class="density-table"><tbody><tr><th scope="row">车牌</th><td>{{ detail.vehicleInfo.vehicle?.plate || '—' }}</td><th scope="row">司机</th><td>{{ detail.vehicleInfo.driver?.name || '—' }}</td></tr><tr><th scope="row">托盘数</th><td>{{ detail.counts.palletCount }} 托</td><th scope="row">箱数</th><td>{{ detail.counts.packageCount }} 箱</td></tr></tbody></table>
|
||||
@@ -248,12 +258,7 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
</template>
|
||||
<el-alert v-else-if="currentAction === 'RETURN_TO_REVIEW'" title="仅零真实扫码允许退回装车前,保留原排车号,修改后两级审核重新提交。" type="warning" :closable="false" show-icon />
|
||||
<el-alert v-else-if="currentAction === 'CANCEL'" title="确认取消本排车单;服务端将核对真实作业和来源占用,不自动回库。" type="warning" :closable="false" show-icon />
|
||||
<div v-if="vehicleEditor" class="workflow-photo-grid density-dialog-sections" aria-label="车辆司机照片">
|
||||
<DispatchEvidenceFiles photo-card v-model="vehicle.evidenceFileIds" :dispatch-no="currentNo" kind="VEHICLE" label="车辆图片" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.VEHICLE = $event" />
|
||||
<DispatchEvidenceFiles photo-card v-model="driverPhotos" :dispatch-no="currentNo" kind="DRIVER_PHOTO" label="司机照片" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.DRIVER_PHOTO = $event" />
|
||||
<DispatchEvidenceFiles photo-card v-if="driver.evidence" v-model="driver.evidence.fileIds" :dispatch-no="currentNo" kind="DRIVER" label="驾驶证照片" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.DRIVER = $event" />
|
||||
</div>
|
||||
<div v-else-if="isReview" class="workflow-photo-grid density-dialog-sections" aria-label="车辆司机照片">
|
||||
<div v-if="isReview" class="workflow-photo-grid density-dialog-sections" aria-label="车辆司机照片">
|
||||
<DispatchEvidenceFiles v-for="field in dispatchReviewAttachmentFields" :key="field.key" photo-card readonly :model-value="reviewEvidence[field.key]" :dispatch-no="currentNo" :kind="field.kind" :label="field.label" />
|
||||
</div>
|
||||
<section v-if="currentOperation === 'ROUTE' || ['CANCEL', 'RETURN_TO_REVIEW', 'DISPATCH_REVIEW', 'LOADING_REVIEW'].includes(currentAction)" class="density-dialog-section" data-tone="work" aria-label="操作原因与意见"><h3 class="density-dialog-section__title">操作说明</h3><table class="density-table density-table--editable"><tbody><tr><td><el-form-item :label="isReview && form.decision === 'REJECTED' ? '驳回原因(必填)' : currentOperation === 'ROUTE' || ['CANCEL', 'RETURN_TO_REVIEW'].includes(currentAction) ? '原因(必填)' : '审核意见(选填)'" :error="isReview && form.decision === 'REJECTED' && !form.reason.trim() ? '请填写驳回原因' : ''"><el-input v-model="form.reason" :disabled="frozen || loading || uploadingEvidence || !allowed" type="textarea" :rows="3" :placeholder="isReview ? '驳回时必须填写原因,审核通过时选填' : ''" /></el-form-item></td></tr></tbody></table></section>
|
||||
@@ -274,8 +279,6 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
</AppDialog>
|
||||
</template>
|
||||
<style scoped>
|
||||
.workflow-editor-table { table-layout: fixed; }
|
||||
.workflow-editor-table td { width: 50%; }
|
||||
.workflow-order-actions { width: 160px; white-space: nowrap; }
|
||||
.workflow-photo-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--admin-space-4); }
|
||||
.workflow-review-actions { display: flex; justify-content: flex-end; gap: var(--admin-space-3); }
|
||||
|
||||
Reference in New Issue
Block a user