This commit is contained in:
2026-10-23 12:06:42 +08:00
parent 75bb0bf78e
commit 4f766a76bd
11 changed files with 23 additions and 27 deletions
@@ -53,7 +53,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: '', maintenance: blankVehicleMaintenance(), remark: '', decision: 'APPROVED' as 'APPROVED' | 'REJECTED', reason: '' })
const form = reactive({ plannedDepartureAt: '', estimatedArrivalAt: '', maintenance: blankVehicleMaintenance(), remark: '', decision: 'APPROVED' as 'APPROVED' | 'REJECTED', reason: '' })
/** 并发加货后补入新目的仓,保留客服已填写的同仓编号。 */
function fillDestinationAppointments(value: DispatchDetail, keepInput = false) {
const entered = new Map(keepInput ? form.maintenance.destinationAppointments.map(row => [row.destinationKey, row.appointmentNo]) : [])
@@ -90,7 +90,7 @@ async function load() {
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()
driver.value = value.vehicleInfo.driver ? structuredClone(value.vehicleInfo.driver) : blankDriver()
if (!driver.value.evidence) driver.value.evidence = blankDriver().evidence
Object.assign(form, { publishLooseboardDemand: value.publishLooseboardDemand, plannedDepartureAt: value.dispatchInfo.plannedDepartureAt || '', estimatedArrivalAt: value.dispatchInfo.estimatedArrivalAt || '', remark: value.documents.remark || '', reason: '', decision: 'APPROVED' })
Object.assign(form, { plannedDepartureAt: value.dispatchInfo.plannedDepartureAt || '', estimatedArrivalAt: value.dispatchInfo.estimatedArrivalAt || '', remark: value.documents.remark || '', reason: '', decision: 'APPROVED' })
if (currentOperation.value === 'ROUTE') {
const data = await api.getDispatchRoute(no)
if (sequence !== generation) return
@@ -125,7 +125,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.mode === 'MASTER' && !vehicle.value.vehicleId ? null : vehicle.value, driver: driver.value.mode === 'MASTER' && !driver.value.driverId ? null : driver.value, maintenance: vehicleMaintenancePayload(form.maintenance), plannedDepartureAt: form.plannedDepartureAt || null, estimatedArrivalAt: form.estimatedArrivalAt || null, remark: form.remark || null } satisfies UpdateDispatch
case 'EDIT': return { ...common, vehicle: vehicle.value.mode === 'MASTER' && !vehicle.value.vehicleId ? null : vehicle.value, driver: driver.value.mode === 'MASTER' && !driver.value.driverId ? null : 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('驳回时必须填写原因')
@@ -246,7 +246,7 @@ 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">
<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">
<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" :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="车辆司机照片">
@@ -268,7 +268,7 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
<section class="density-dialog-section" data-tone="source" aria-label="排车与预约">
<h3 class="density-dialog-section__title">排车与预约</h3>
<table class="density-table"><tbody><tr><th scope="row">计划来车/发车(北京时间)</th><td>{{ reviewTime(detail.dispatchInfo.plannedDepartureAt) }}</td><th scope="row">预计送达(北京时间)</th><td>{{ reviewTime(detail.dispatchInfo.estimatedArrivalAt) }}</td></tr></tbody></table>
<DispatchAppointments :appointments="detail.dispatchInfo.fbaAppointments" />
<DispatchAppointments :appointments="detail.dispatchInfo.fbaAppointments" :show-shipment-numbers="currentAction !== 'DISPATCH_REVIEW'" />
<el-alert v-if="approvalBlock" :title="approvalBlock" type="warning" :closable="false" show-icon />
</section>
</template>
@@ -284,7 +284,7 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
<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>
<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">{{ isReview ? '审核意见' : '操作说明' }}</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>
<section v-if="currentOperation === 'ROUTE' || ['CANCEL', 'RETURN_TO_REVIEW', 'DISPATCH_REVIEW', 'LOADING_REVIEW'].includes(currentAction)" class="density-dialog-section" :data-tone="currentAction === 'DISPATCH_REVIEW' ? undefined : 'work'" aria-label="操作原因与意见"><h3 class="density-dialog-section__title">{{ isReview ? '审核意见' : '操作说明' }}</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>
<section v-else-if="!['MARK_EXCEPTION', 'EDIT', 'SUBMIT_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="备注"><el-input v-model="form.remark" aria-label="本次操作备注" :disabled="frozen || loading || uploadingEvidence || !allowed" type="textarea" :rows="3" /></el-form-item></td></tr></tbody></table></section>
</el-form>
</div>