feat: split domestic and overseas container workbenches

This commit is contained in:
2026-09-08 19:57:42 +08:00
parent 296a8246ad
commit 8910e88563
26 changed files with 365 additions and 219 deletions
@@ -57,7 +57,7 @@ describe('LoadingListsView', () => {
expect(source).not.toContain('internalContainerNo')
})
it('opens both preload and confirmed details as independent route pages', () => {
it('keeps preload routes while completed lists move into domestic container detail', () => {
expect(source).toContain("name: 'preload-plan-detail'")
expect(source).toContain("name: 'loading-list-detail'")
expect(source).not.toContain('confirmed-inline-detail')
@@ -66,8 +66,8 @@ describe('LoadingListsView', () => {
expect(confirmedDetailSource).toContain('返回列表')
expect(confirmedDetailSource).toContain('router.back()')
expect(confirmedDetailSource).toContain('@media (min-width: 1920px) { .confirmed-loading-detail-page { width: 100%; max-width: none; gap: 12px; } }')
expect(routesSource).toContain("path: 'loading-lists/:planId'")
expect(routesSource).toContain("name: 'loading-list-detail'")
expect(routesSource).not.toContain("path: 'loading-lists/:planId'")
expect(routesSource).not.toContain("name: 'loading-list-detail'")
})
it('keeps the real transport edit contract in a 620px centered modal on the detail page', () => {
+1
View File
@@ -2,3 +2,4 @@ export * from './api/platformLoadingLists'
export { loadingListRoutes } from './routes'
export { loadingListStatusLabel } from './status'
export { default as ContainerFeesPanel } from './components/ContainerFeesPanel.vue'
export { default as LoadingListDetailDrawer } from './components/LoadingListDetailDrawer.vue'
@@ -2,7 +2,7 @@ import { flushPromises, shallowMount } from '@vue/test-utils'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ElMessage } from 'element-plus'
import { ApiResponseError, http } from '@/shared/api/http'
import { getPreloadPlan } from '../api/platformLoadingLists'
import { getConfirmedLoadingList, getPreloadPlan } from '../api/platformLoadingLists'
import PreloadPlanDetailView from './PreloadPlanDetailView.vue'
const routerReplace = vi.hoisted(() => vi.fn())
@@ -15,6 +15,7 @@ vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({
vi.mock('@/core/workspace-tabs/workspaceTabs', () => ({ useWorkspaceTabsStore: () => ({ removeByIds: removeWorkspaceTabs }) }))
vi.mock('../api/platformLoadingLists', () => ({
confirmPreloadPlan: vi.fn(),
getConfirmedLoadingList: vi.fn(),
getPreloadPlan: vi.fn(),
updateLoadingItemWarehouseRemark: vi.fn(),
updatePreloadTransport: vi.fn(),
@@ -52,6 +53,7 @@ describe('PreloadPlanDetailView lifecycle handoff', () => {
it('replaces the current tab after authoritative lifecycle resolution', async () => {
vi.spyOn(http, 'get').mockResolvedValue(lifecycle('LOADING_LIST', 'COMPLETED'))
vi.mocked(getConfirmedLoadingList).mockResolvedValue({ summary: { containerBookingId: '2900000000000000001' }, items: [], histories: [] } as never)
const message = vi.spyOn(ElMessage, 'success').mockImplementation(() => undefined as never)
const wrapper = await mountView()
@@ -63,9 +65,9 @@ describe('PreloadPlanDetailView lifecycle handoff', () => {
expect(getPreloadPlan).not.toHaveBeenCalled()
expect(routerReplace).toHaveBeenCalledTimes(1)
expect(routerReplace).toHaveBeenCalledWith({
name: 'loading-list-detail',
params: { planId: '1900000000000000001' },
query: { warehouseId: '1900000000000000002' },
name: 'domestic-container-detail',
params: { containerId: '2900000000000000001' },
query: { tab: 'loading-list' },
})
expect(removeWorkspaceTabs).toHaveBeenCalledWith(['preload-plan-detail'])
expect(routerReplace.mock.invocationCallOrder[0]).toBeLessThan(removeWorkspaceTabs.mock.invocationCallOrder[0]!)
@@ -24,11 +24,11 @@ describe('PreloadPlanDetailView prototype contract', () => {
expect(source).toContain('/loading-plans/${encodeURIComponent(planId.value)}/lifecycle')
expect(source).toContain("lifecycle.detailResource === 'LOADING_LIST'")
expect(source).toContain("lifecycle.planStatus !== 'COMPLETED'")
expect(source).toContain("router.replace({ name: 'loading-list-detail'")
expect(source).toContain("router.replace({ name: 'domestic-container-detail'")
expect(source).toContain("workspace.removeByIds(['preload-plan-detail'])")
expect(source).toContain('装柜已完成,已切换至装柜清单详情')
expect(source).not.toContain("preloadError.code !== 'A0404'")
expect(source).not.toContain('getConfirmedLoadingList')
expect(source).toContain('getConfirmedLoadingList')
expect(source).not.toContain("router.push({ name: 'loading-list-detail'")
})
@@ -11,7 +11,7 @@ import { getApiErrorDetails, http, unwrapApiResponse, type ApiEnvelope, type Api
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { useWorkspaceTabsStore } from '@/core/workspace-tabs/workspaceTabs'
import LoadingListDetailDrawer from '../components/LoadingListDetailDrawer.vue'
import { confirmPreloadPlan, getPreloadPlan, updateLoadingItemWarehouseRemark, updatePreloadTransport, type LoadingDetail, type LoadingItem, type PreloadSummary } from '../api/platformLoadingLists'
import { confirmPreloadPlan, getConfirmedLoadingList, getPreloadPlan, updateLoadingItemWarehouseRemark, updatePreloadTransport, type LoadingDetail, type LoadingItem, type PreloadSummary } from '../api/platformLoadingLists'
const route = useRoute()
const router = useRouter()
@@ -96,7 +96,8 @@ async function loadDetail() {
error.value = { code: 'MODE_STATUS_MISMATCH', message: '装柜计划阶段异常,暂时无法切换详情,请稍后重试。' }
return
}
await router.replace({ name: 'loading-list-detail', params: { planId: planId.value }, query: { warehouseId: warehouseId.value } })
const confirmed = await getConfirmedLoadingList(planId.value, warehouseId.value)
await router.replace({ name: 'domestic-container-detail', params: { containerId: confirmed.summary.containerBookingId }, query: { tab: 'loading-list' } })
workspace.removeByIds(['preload-plan-detail'])
if (sequence === loadSequence) ElMessage.success('装柜已完成,已切换至装柜清单详情')
return
+1 -3
View File
@@ -2,12 +2,10 @@ import { describe, expect, it } from 'vitest'
import { loadingListRoutes } from './routes'
describe('loading list routes', () => {
it('declares preload list/detail and completed list entries with backend permissions', () => {
it('keeps completed loading lists inside domestic container detail', () => {
expect(loadingListRoutes.map((route) => [route.path, route.meta.permission])).toEqual([
['loading-plans', 'platform:firstleg:preload:list'],
['loading-plans/:planId', 'platform:firstleg:preload:list'],
['loading-lists', 'platform:firstleg:loading-list:list'],
['loading-lists/:planId', 'platform:firstleg:loading-list:list'],
])
})
})
-20
View File
@@ -21,24 +21,4 @@ export const loadingListRoutes = [
permission: 'platform:firstleg:preload:list',
},
},
{
path: 'loading-lists',
name: 'loading-lists',
component: () => import('./pages/ConfirmedLoadingListsView.vue'),
meta: {
title: '装柜清单',
description: '查看全部仓库已完成且永久只读的装柜清单',
permission: 'platform:firstleg:loading-list:list',
},
},
{
path: 'loading-lists/:planId',
name: 'loading-list-detail',
component: () => import('./pages/ConfirmedLoadingListDetailView.vue'),
meta: {
title: '装柜清单详情',
description: '查看装柜清单基本信息、货物明细、费用和操作历史',
permission: 'platform:firstleg:loading-list:list',
},
},
] satisfies RouteRecordRaw[]