2026-08-13 11:57:44 +08:00
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
|
import { mount } from '@vue/test-utils'
|
|
|
|
|
import ElementPlus from 'element-plus'
|
|
|
|
|
import ContainerOverviewPanel from './ContainerOverviewPanel.vue'
|
|
|
|
|
import type { ContainerOverview } from '../types'
|
|
|
|
|
|
|
|
|
|
const overview: ContainerOverview = {
|
|
|
|
|
container: { id: '7', bookingNo: 'BK-1', cabinetNo: 'CB-1', containerNo: 'MSCU-1', status: 'LOADING', warehouseId: '8', warehouseName: '义乌仓', voyageNo: 'V1', vesselName: '船一', version: 2 },
|
|
|
|
|
loadingPlanId: '9',
|
2026-08-14 14:27:03 +08:00
|
|
|
pda: { taskId: '10', loadingPlanId: '9', containerBookingId: '7', taskStatus: 'IN_PROGRESS', workflowStatus: 'AWAITING_REVIEW', taskVersion: 2, itemCount: 4, completedItemCount: 4, unresolvedItemCount: 0, photoCounts: [{ evidenceType: 'PHOTO_STEP_EMPTY_CONTAINER', count: 2 }], photos: [{ evidenceId: '20', tenantId: '21', inboundId: '22', evidenceType: 'PHOTO_STEP_EMPTY_CONTAINER', fileId: '23', fileName: 'empty.jpg', status: 'ACTIVE', downloadPath: '/api/platform/v1/containers/7/pda/photos/23/download', uploadedAt: '2026-08-13T12:30:00' }], exceptionReasons: ['一项待复核'] },
|
2026-08-13 11:57:44 +08:00
|
|
|
documents: [{ id: '11', documentType: 'DELIVERY_ORDER', fileId: '9007199254740999', fileName: 'do.pdf', fileHash: null, uploadedBy: '13', uploadedByName: '操作员', uploadedAt: '2026-08-13T10:00:00', version: 1, completed: false }],
|
|
|
|
|
exception: { active: true, reason: '码头查验', markedBy: '13', markedByName: '操作员', markedAt: '2026-08-13T11:00:00' },
|
|
|
|
|
exceptionHistory: [{ id: '14', action: 'MARK', reason: '码头查验', operatorId: '13', operatorName: '操作员', occurredAt: '2026-08-13T11:00:00' }],
|
|
|
|
|
timeline: [{ eventType: 'TRANSPORT_UPDATE', detail: '更新预计到港时间', operatorId: '13', operatorName: '操作员', occurredAt: '2026-08-13T12:00:00' }],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe('ContainerOverviewPanel', () => {
|
|
|
|
|
it('renders documents, PDA progress, exception history and timeline from the aggregate DTO', () => {
|
|
|
|
|
const wrapper = mount(ContainerOverviewPanel, { props: { overview, canManageDocuments: true, canManageException: true }, global: { plugins: [ElementPlus] } })
|
|
|
|
|
expect(wrapper.text()).toContain('DO 资料')
|
|
|
|
|
expect(wrapper.text()).toContain('do.pdf')
|
|
|
|
|
expect(wrapper.text()).toContain('PDA 作业进度')
|
2026-08-14 14:27:03 +08:00
|
|
|
expect(wrapper.text()).toContain('待人工复核')
|
|
|
|
|
expect(wrapper.text()).toContain('空柜照片')
|
|
|
|
|
expect(wrapper.text()).not.toContain('PHOTO_STEP_EMPTY_CONTAINER')
|
2026-08-13 11:57:44 +08:00
|
|
|
expect(wrapper.text()).toContain('一项待复核')
|
|
|
|
|
expect(wrapper.text()).toContain('码头查验')
|
|
|
|
|
expect(wrapper.text()).toContain('更新预计到港时间')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('emits stable document types and does not expose file ids in visible text', async () => {
|
|
|
|
|
const wrapper = mount(ContainerOverviewPanel, { props: { overview, canManageDocuments: true, canManageException: true }, global: { plugins: [ElementPlus] } })
|
|
|
|
|
const updateButton = wrapper.findAll('button').find((button) => button.text().includes('更新'))!
|
|
|
|
|
await updateButton.trigger('click')
|
|
|
|
|
expect(wrapper.emitted('uploadDocument')?.[0]).toEqual(['DELIVERY_ORDER'])
|
|
|
|
|
expect(wrapper.text()).not.toContain('9007199254740999')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('emits the backend-provided photo object from an accessible view control', async () => {
|
|
|
|
|
const wrapper = mount(ContainerOverviewPanel, { props: { overview, canManageDocuments: true, canManageException: true }, global: { plugins: [ElementPlus] } })
|
|
|
|
|
await wrapper.find('button[aria-label="查看装柜照片 empty.jpg"]').trigger('click')
|
2026-08-14 14:27:03 +08:00
|
|
|
expect(wrapper.emitted('previewPhoto')?.[0]?.[0]).toMatchObject({ evidenceId: '20', downloadPath: '/api/platform/v1/containers/7/pda/photos/23/download' })
|
2026-08-13 11:57:44 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('renders empty and forbidden/load failure states without exposing credentials', () => {
|
|
|
|
|
const withoutPhotos = { ...overview, pda: overview.pda ? { ...overview.pda, photos: [] } : null }
|
|
|
|
|
const wrapper = mount(ContainerOverviewPanel, { props: { overview: withoutPhotos, canManageDocuments: false, canManageException: false, photoError: { message: '当前账号无权访问该数据,请联系管理员确认权限', code: 'HTTP_403', requestId: 'req-photo' } }, global: { plugins: [ElementPlus] } })
|
|
|
|
|
expect(wrapper.text()).toContain('暂无可查看的有效照片')
|
|
|
|
|
expect(wrapper.text()).toContain('当前账号无权访问该数据')
|
|
|
|
|
expect(wrapper.text()).toContain('req-photo')
|
|
|
|
|
expect(wrapper.text()).not.toContain('Authorization')
|
|
|
|
|
})
|
|
|
|
|
})
|