Merge origin/release/test and combine transport photo workflows
This commit is contained in:
@@ -41,6 +41,8 @@ const measurements = ref<Array<{ warehousePalletId: string; palletNo: string; pa
|
||||
const blankVehicle = (): Vehicle => ({ mode: 'MASTER', vehicleId: null, plate: null, carrierName: null, capacity: { palletSpaces: null, maxLoadKg: null, maxVolumeCbm: null }, evidenceFileIds: [] })
|
||||
const blankDriver = (): Driver => ({ mode: 'MASTER', driverId: null, name: null, phone: null, evidence: { licenseNo: null, licenseExpiresOn: null, fileIds: [], expectedTaskEndAt: null } })
|
||||
const vehicle = ref<Vehicle>(blankVehicle()), driver = ref<Driver>(blankDriver())
|
||||
const missingVehicle = computed(() => vehicle.value.mode === 'MASTER' && !vehicle.value.vehicleId)
|
||||
const missingDriver = computed(() => driver.value.mode === 'MASTER' && !driver.value.driverId)
|
||||
const driverPhotos = computed({ get: () => driver.value.evidence?.photoFileIds || [], set: (ids: string[]) => { if (driver.value.evidence) driver.value.evidence.photoFileIds = ids } })
|
||||
// 新选司机的主档证照先按司机读取,已保存的冻结证照仍按排车读取。
|
||||
const masterLicenseReference = computed(() => driver.value.mode === 'MASTER' ? driver.value.evidence?.masterLicenseFileId : null)
|
||||
@@ -134,7 +136,10 @@ 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, 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':
|
||||
if (missingVehicle.value && vehicle.value.evidenceFileIds.length) throw new DispatchInputError('请先选择车辆,再保存车辆图片;当前图片尚未保存')
|
||||
if (missingDriver.value && (driver.value.evidence?.fileIds.length || driverPhotos.value.length)) throw new DispatchInputError('请先选择司机,再保存司机照片和驾驶证照片;当前图片尚未保存')
|
||||
return { ...common, vehicle: missingVehicle.value ? null : vehicle.value, driver: missingDriver.value ? 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('驳回时必须填写原因')
|
||||
@@ -148,7 +153,7 @@ function payload(): object {
|
||||
return { recordVersion: requireVersion(preview.value.recordVersion), idempotencyKey: common.idempotencyKey, manifestHash: preview.value.manifestHash, remark: form.remark || null } satisfies LoadingComplete
|
||||
}
|
||||
case 'SUBMIT_REVIEW':
|
||||
if (!detail.value.vehicleInfo.vehicle?.vehicleId || !detail.value.vehicleInfo.driver?.driverId) {
|
||||
if (['PICKUP', 'LOCAL_TRUCK'].includes(detail.value.taskType || '') && (!detail.value.vehicleInfo.vehicle?.vehicleId || !detail.value.vehicleInfo.driver?.driverId)) {
|
||||
throw new DispatchInputError('车辆信息尚未维护完整,请先点击“维护车辆”并保存车辆、司机后再提交审核')
|
||||
}
|
||||
return { ...common, remark: null }
|
||||
@@ -263,8 +268,8 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
<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-model="vehicle.evidenceFileIds" :dispatch-no="currentNo" kind="VEHICLE" label="车辆图片" :master-resource="vehicle.mode === 'MASTER' && vehicle.vehicleId ? { kind: 'VEHICLE', id: vehicle.vehicleId } : null" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.VEHICLE = $event" />
|
||||
<DispatchEvidenceFiles photo-card v-model="driverPhotos" :dispatch-no="currentNo" kind="DRIVER_PHOTO" label="司机照片" :master-resource="driver.mode === 'MASTER' && driver.driverId ? { kind: 'DRIVER', id: driver.driverId } : null" :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="驾驶证照片" :reference-ids="masterLicenseReference ? [masterLicenseReference] : []" :master-license="unsavedMasterLicense" :disabled="frozen || loading || uploadingEvidence || !allowed" @busy="evidenceBusy.DRIVER = $event" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -279,7 +284,7 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
<tr v-else><th scope="row">起运地</th><td>{{ detail.dispatchInfo.route?.split(' → ')[0] || '—' }}</td><th scope="row">目的地</th><td colspan="3">{{ detail.dispatchInfo.route?.split(' → ').slice(1).join(' → ') || '—' }}</td></tr>
|
||||
<tr><th scope="row">计划发车</th><td>{{ reviewTime(detail.dispatchInfo.plannedDepartureAt) }}</td><th scope="row">预计送达</th><td>{{ reviewTime(detail.dispatchInfo.estimatedArrivalAt) }}</td><th scope="row">货量</th><td>{{ detail.counts.palletCount }} 托 / {{ detail.counts.packageCount }} 箱</td></tr>
|
||||
</tbody></table>
|
||||
<el-alert v-if="!detail.vehicleInfo.vehicle?.vehicleId || !detail.vehicleInfo.driver?.driverId" title="车辆信息尚未维护完整,请先点击“维护车辆”并保存车辆、司机后再提交审核。" type="warning" :closable="false" show-icon />
|
||||
<el-alert v-if="['PICKUP', 'LOCAL_TRUCK'].includes(detail.taskType || '') && (!detail.vehicleInfo.vehicle?.vehicleId || !detail.vehicleInfo.driver?.driverId)" title="车辆信息尚未维护完整,请先点击“维护车辆”并保存车辆、司机后再提交审核。" type="warning" :closable="false" show-icon />
|
||||
</section>
|
||||
</template>
|
||||
<template v-else-if="currentAction === 'DISPATCH_REVIEW' || currentAction === 'LOADING_REVIEW'">
|
||||
@@ -328,7 +333,7 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
</template>
|
||||
<style scoped>
|
||||
.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-photo-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; gap: var(--admin-space-4); }
|
||||
.workflow-review-actions { display: flex; justify-content: flex-end; gap: var(--admin-space-3); }
|
||||
.workflow-review-actions > .el-button { margin-left: 0; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user