优化
This commit is contained in:
@@ -134,7 +134,8 @@ it('retains edited values and the original validation response when the action i
|
||||
expect(state.form.remark).toBe('用户未保存的本轮备注')
|
||||
expect(state.detail.recordVersion).toBe(0)
|
||||
expect(wrapper.text()).toContain('预计到达时间须在发车之后')
|
||||
expect(wrapper.text()).toContain('A0400')
|
||||
expect(wrapper.text()).not.toContain('A0400')
|
||||
expect(wrapper.text()).not.toContain('validation-request')
|
||||
expect(wrapper.text()).not.toContain('原操作结果尚待核对')
|
||||
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||
await state.retryError()
|
||||
@@ -150,7 +151,7 @@ it('allows another click after rejection even when a later read would fail', asy
|
||||
await state.submit(); await flushPromises()
|
||||
expect(wrapper.emitted('rejected')).toEqual([[expect.objectContaining({ code: 'A0409', requestId: 'reject-request' })]])
|
||||
expect(useDispatchCommandRecovery(() => identity.id).pending.value).toBeNull()
|
||||
expect(wrapper.text()).toContain('A0409')
|
||||
expect(wrapper.text()).not.toContain('A0409')
|
||||
expect(wrapper.text()).not.toContain('原操作结果尚待核对')
|
||||
expect(state.form.remark).toBe('保留本次备注')
|
||||
await state.submit()
|
||||
|
||||
@@ -10,7 +10,6 @@ import { useAuthStore } from '@/core/auth/auth'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
||||
import * as api from '../api/dispatches'
|
||||
import { getTransport } from '../api/transportTasks'
|
||||
@@ -254,7 +253,7 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
<div class="density-dialog-sections">
|
||||
<el-alert v-if="cargoAction" :title="cargoEntryMessage" type="warning" :closable="false" show-icon />
|
||||
<el-alert v-if="dispatchRejectionReason(detail?.reviews)" title="已退回客服处理,请核对原因后重新提交调度审核。" :description="dispatchRejectionReason(detail?.reviews)" type="warning" :closable="false" show-icon />
|
||||
<LoadErrorState v-if="error && !cargoAction" title="排车操作未完成" :message="error.message" :loading="loading || busy || uploadingEvidence" retry-text="刷新当前资料" @retry="retryError"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
||||
<LoadErrorState v-if="error && !cargoAction" title="排车操作未完成" :message="error.message" :loading="loading || busy || uploadingEvidence" retry-text="刷新当前资料" @retry="retryError"></LoadErrorState>
|
||||
<el-alert v-if="detail && !allowed && !pending" :title="detail?.actions[currentAction]?.blockReason || '当前操作未获得允许,请核对权限与作业状态'" type="warning" :closable="false" show-icon />
|
||||
<el-form v-if="detail && !cargoAction" class="density-form density-dialog-sections" label-position="left" label-width="130px" :disabled="frozen || loading || uploadingEvidence || !allowed">
|
||||
<section v-if="currentOperation === 'ROUTE' && route" class="density-dialog-section" data-tone="source" aria-label="本车卸货顺序"><h3 class="density-dialog-section__title">卸货顺序</h3>
|
||||
@@ -323,7 +322,7 @@ watch([open, () => props.dispatchNo, () => props.action, () => props.operation],
|
||||
<el-form-item v-if="currentAction === 'CANCEL' && currentOperation !== 'ROUTE'" label="取消原因" label-position="top" required>
|
||||
<el-input v-model="form.reason" aria-label="取消原因" type="textarea" :rows="4" placeholder="请填写取消原因" />
|
||||
</el-form-item>
|
||||
<section v-else-if="currentOperation === 'ROUTE' || ['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' || currentAction === 'RETURN_TO_REVIEW' ? '原因(必填)' : '审核意见(选填)'" :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="currentOperation === 'ROUTE' || ['RETURN_TO_REVIEW', 'DISPATCH_REVIEW', 'LOADING_REVIEW'].includes(currentAction)" class="density-dialog-section" :data-tone="isReview ? 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' || currentAction === 'RETURN_TO_REVIEW' ? '原因(必填)' : '审核意见(选填)'" :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>
|
||||
|
||||
@@ -5,6 +5,7 @@ import TransportExecutionPanel from './TransportExecutionPanel.vue'
|
||||
import { assignTransport, commandTransport, downloadTransportEvidence, getTransport, uploadTransport, type TransportDetail } from '../api/transportTasks'
|
||||
import { getDriver } from '@/modules/overseas-master-data'
|
||||
import DispatchEvidenceFiles from './DispatchEvidenceFiles.vue'
|
||||
import { ApiResponseError } from '@/shared/api/http'
|
||||
|
||||
const can = vi.hoisted(() => vi.fn((_code: string) => true))
|
||||
vi.mock('vue-router', () => ({ onBeforeRouteLeave: vi.fn() }))
|
||||
@@ -150,7 +151,7 @@ it('requires three categories and sends photos with both current versions for re
|
||||
it('restores saved photos and retains uploads after a failed save', async () => {
|
||||
const value = facts(); value.dispatchRecordVersion = 9
|
||||
value.resources = { vehicle: { vehicleId: '1', evidenceFileIds: ['21'] }, driver: { driverId: '2', evidence: { photoFileIds: ['22'], fileIds: ['23'] } } } as TransportDetail['resources']
|
||||
vi.mocked(getTransport).mockResolvedValue(value); vi.mocked(assignTransport).mockRejectedValue(new Error('保存失败'))
|
||||
vi.mocked(getTransport).mockResolvedValue(value); vi.mocked(assignTransport).mockRejectedValue(new ApiResponseError('司机预计任务结束时间须晚于当前时间', 'A0400', 400, undefined, 'save-request', 'save-trace'))
|
||||
const wrapper = mount(TransportExecutionPanel, { ...photoOptions, props: { dispatchNo: 'PC1', editResources: true } }); await flushPromises()
|
||||
const cards = wrapper.findAllComponents(DispatchEvidenceFiles)
|
||||
expect(cards.map(card => card.props('modelValue'))).toEqual([['21'], ['22'], ['23']])
|
||||
@@ -158,6 +159,8 @@ it('restores saved photos and retains uploads after a failed save', async () =>
|
||||
cards[0]!.vm.$emit('update:modelValue', ['24']); await flushPromises()
|
||||
await wrapper.findAll('button').find(button => button.text() === '保存车辆司机')!.trigger('click'); await flushPromises()
|
||||
expect(cards[0]!.props('modelValue')).toEqual(['24'])
|
||||
expect(wrapper.text()).toContain('司机预计任务结束时间须晚于当前时间')
|
||||
for (const diagnostic of ['A0400', 'save-request', 'save-trace']) expect(wrapper.text()).not.toContain(diagnostic)
|
||||
expect(wrapper.emitted('saved')).toBeUndefined(); wrapper.unmount()
|
||||
})
|
||||
it('clears old photos when selecting another vehicle or driver and ignores late license responses', async () => {
|
||||
|
||||
@@ -7,8 +7,6 @@ import { onBeforeRouteLeave } from 'vue-router'
|
||||
import { Truck, Package, RefreshCw, Trash2 } from '@lucide/vue'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { ApiResponseError, getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
||||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import { listVehicles, listDrivers, getDriver, pickupStatusLabels, type VehicleDetail, type DriverDetail, type PickupTask, type PickupEvidence } from '@/modules/overseas-master-data'
|
||||
import DispatchEvidenceFiles from './DispatchEvidenceFiles.vue'
|
||||
@@ -195,7 +193,7 @@ onBeforeUnmount(clearTruckPreviewUrls)
|
||||
</script>
|
||||
<template>
|
||||
<section class="transport-execution admin-density admin-workbench" aria-label="运输任务执行">
|
||||
<LoadErrorState v-if="error" title="操作未完成" :message="error.message" :show-retry="false"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
||||
<el-alert v-if="error" :title="error.message" type="error" :closable="false" show-icon />
|
||||
|
||||
<template v-if="detail && trip">
|
||||
<header class="transport-toolbar">
|
||||
|
||||
Reference in New Issue
Block a user