From 975e0057e304a30eb93fcb53f07eef325a84e8ed Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Wed, 12 Aug 2026 14:08:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DomesticOutboundListStates.test.ts | 17 ++- src/modules/iam/pages/PermissionsView.test.ts | 10 ++ src/modules/iam/pages/PermissionsView.vue | 2 +- src/modules/iam/pages/RolesView.test.ts | 11 ++ src/modules/iam/pages/RolesView.vue | 7 +- .../InboundMeasurementPanel.test.ts | 19 +++ .../measurement/InboundMeasurementPanel.vue | 142 +++++++++++++++++- src/modules/inbounds/measurement/api.test.ts | 18 ++- src/modules/inbounds/measurement/api.ts | 18 +++ src/modules/inbounds/measurement/types.ts | 11 ++ .../pages/TruckAppointmentDetailView.test.ts | 15 ++ .../pages/TruckAppointmentDetailView.vue | 6 +- .../pages/TruckAppointmentsView.test.ts | 14 ++ .../trucking/pages/TruckAppointmentsView.vue | 2 +- .../pages/UnifiedOrdersView.test.ts | 9 ++ src/shared/api/http.test.ts | 21 ++- src/shared/api/http.ts | 23 ++- src/shared/components/DataTable.test.ts | 23 +++ src/shared/utils/uiLayoutPreference.test.ts | 34 ++++- src/shared/utils/uiLayoutPreference.ts | 5 +- 20 files changed, 378 insertions(+), 29 deletions(-) create mode 100644 src/modules/trucking/pages/TruckAppointmentDetailView.test.ts diff --git a/src/app/DomesticOutboundListStates.test.ts b/src/app/DomesticOutboundListStates.test.ts index d5d83df8..8710e804 100644 --- a/src/app/DomesticOutboundListStates.test.ts +++ b/src/app/DomesticOutboundListStates.test.ts @@ -3,13 +3,13 @@ import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' const pages = [ - ['src/modules/container-loading/pages/ContainersView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无货柜"', 'statusText(row.planStatus)', 'platform:firstleg:container:view'], - ['src/modules/loading-lists/components/LoadingListsView.vue', ':loading="loading"', 'LoadErrorState', ':empty-text="`暂无符合筛选条件的${title}`"', 'loadingListStatusLabel(row.status)', 'canView'], - ['src/modules/ocean-bookings/pages/OceanBookingsView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合筛选条件的订舱"', 'oceanBookingStatusLabel(row.status)', 'platform:firstleg:ocean-booking:view'], - ['src/modules/port-schedules/pages/PortSchedulesView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合条件的船期"', "row.expired ? '已过期' : '有效'", 'platform:firstleg:port-schedule:view'], - ['src/modules/trucking/pages/TruckAppointmentsView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合筛选条件的拖车预约"', 'statusLabel(row.status)', 'platform:firstleg:truck-appointment:view'], - ['src/modules/customs/pages/CustomsCasesView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无报关协同记录"', 'customsStatusLabel(row.status)', 'platform:firstleg:customs:view'], - ['src/modules/outbound-dispatch/pages/OutboundDispatchesView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合条件的出仓记录"', 'outboundDispatchStatusLabel(row.dispatchStatus)', 'platform:firstleg:outbound-dispatch:view'], + ['src/modules/container-loading/pages/ContainersView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无货柜"', 'statusText(row.planStatus)', 'platform:firstleg:container:view', '@retry="loadRows"'], + ['src/modules/loading-lists/components/LoadingListsView.vue', ':loading="loading"', 'LoadErrorState', ':empty-text="`暂无符合筛选条件的${title}`"', 'loadingListStatusLabel(row.status)', 'canView', '@retry="load"'], + ['src/modules/ocean-bookings/pages/OceanBookingsView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合筛选条件的订舱"', 'oceanBookingStatusLabel(row.status)', 'platform:firstleg:ocean-booking:view', '@retry="load"'], + ['src/modules/port-schedules/pages/PortSchedulesView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合条件的船期"', "row.expired ? '已过期' : '有效'", 'platform:firstleg:port-schedule:view', '@retry="load"'], + ['src/modules/trucking/pages/TruckAppointmentsView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合筛选条件的拖车预约"', 'statusLabel(row.status)', 'platform:firstleg:truck-appointment:view', '@retry="load"'], + ['src/modules/customs/pages/CustomsCasesView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无报关协同记录"', 'customsStatusLabel(row.status)', 'platform:firstleg:customs:view', '@retry="load"'], + ['src/modules/outbound-dispatch/pages/OutboundDispatchesView.vue', ':loading="loading"', 'LoadErrorState', 'empty-text="暂无符合条件的出仓记录"', 'outboundDispatchStatusLabel(row.dispatchStatus)', 'platform:firstleg:outbound-dispatch:view', '@retry="load"'], ] as const function source(path: string) { @@ -17,13 +17,14 @@ function source(path: string) { } describe('domestic outbound list state contracts', () => { - it.each(pages)('%s exposes loading, error, empty, translated status and view-permission states', (path, loading, error, empty, status, viewPermission) => { + it.each(pages)('%s exposes loading, error, empty, translated status, view permission and retry states', (path, loading, error, empty, status, viewPermission, retry) => { const content = source(path) expect(content).toContain(loading) expect(content).toContain(error) expect(content).toContain(empty) expect(content).toContain(status) expect(content).toContain(viewPermission) + expect(content).toContain(retry) }) it('keeps list component state when route details return to the cached workspace list', () => { diff --git a/src/modules/iam/pages/PermissionsView.test.ts b/src/modules/iam/pages/PermissionsView.test.ts index 37f35b62..cfae55b5 100644 --- a/src/modules/iam/pages/PermissionsView.test.ts +++ b/src/modules/iam/pages/PermissionsView.test.ts @@ -1,10 +1,14 @@ import { createPinia, setActivePinia } from 'pinia' +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' import { flushPromises, shallowMount } from '@vue/test-utils' import { beforeEach, describe, expect, it, vi } from 'vitest' import { listPlatformPermissions, type PlatformPermissionResource } from '@/modules/iam/api/platformIam' import { useAuthStore } from '@/core/auth/auth' import PermissionsView from './PermissionsView.vue' +const permissionsSource = readFileSync(resolve(process.cwd(), 'src/modules/iam/pages/PermissionsView.vue'), 'utf8') + vi.mock('@/modules/iam/api/platformIam', () => ({ changePlatformPermissionStatus: vi.fn(), createPlatformPermission: vi.fn(), @@ -81,6 +85,12 @@ describe('PermissionsView IAM mode', () => { vi.mocked(listPlatformPermissions).mockReset() }) + it('keeps technical permission fields out of the default list and labels the table', () => { + expect(permissionsSource).toContain("{ key: 'code', label: '权限编码', minWidth: 220, slotName: 'code', defaultVisible: false }") + expect(permissionsSource).toContain("{ key: 'endpoint', label: '路由 / 接口', minWidth: 260, slotName: 'endpoint', defaultVisible: false }") + expect(permissionsSource).toContain('aria-label="平台权限资源列表"') + }) + it('loads the platform permission resource tree from IAM', async () => { vi.mocked(listPlatformPermissions).mockResolvedValue([permission]) diff --git a/src/modules/iam/pages/PermissionsView.vue b/src/modules/iam/pages/PermissionsView.vue index f4b65d9d..e2b31f27 100644 --- a/src/modules/iam/pages/PermissionsView.vue +++ b/src/modules/iam/pages/PermissionsView.vue @@ -276,7 +276,7 @@ onMounted(loadPermissions)
- +
- + - + diff --git a/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts b/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts index 7645d062..168c166b 100644 --- a/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts +++ b/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts @@ -7,6 +7,7 @@ import { useAuthStore } from '@/core/auth/auth' import { useAccessPreviewStore } from '@/core/access/accessPreview' import { downloadInboundMeasurementImage, + createManualCartonScan, getInboundMeasurement, submitInboundMeasurement, updateConfirmedPackageCount, @@ -15,6 +16,7 @@ import type { InboundMeasurementDetail } from './types' import InboundMeasurementPanel from './InboundMeasurementPanel.vue' vi.mock('./api', () => ({ + createManualCartonScan: vi.fn(), downloadInboundMeasurementImage: vi.fn(), getInboundMeasurement: vi.fn(), saveInboundMeasurementDraft: vi.fn(), @@ -133,6 +135,10 @@ describe('InboundMeasurementPanel', () => { measurementId: '9001', version: 2, processStatus: 'MEASURE_PENDING', measureReviewStatus: 'PENDING', recommendedPalletType: 'STANDARD', feeId: null, feeNo: null, feeStatus: null, }) + vi.mocked(createManualCartonScan).mockReset().mockResolvedValue({ + measurementId: '9001', measurementVersion: 3, itemId: '9102', boxCode: 'RK202608040001#10-2', + confirmedPackageCount: 1, + }) vi.spyOn(ElMessageBox, 'confirm').mockResolvedValue(undefined as never) }) @@ -151,6 +157,19 @@ describe('InboundMeasurementPanel', () => { expect(wrapper.text()).toContain('预览图片') }) + it('opens the manual carton entry form in an editable measurement state', async () => { + const wrapper = await mountPanel() + const button = wrapper.findAll('button').find((candidate) => candidate.text().includes('手动录入箱规')) + expect(button?.attributes('disabled')).toBeUndefined() + await button?.trigger('click') + expect(wrapper.text()).toContain('手动录入箱规') + + expect(document.body.textContent).toContain('箱号') + expect(document.body.textContent).toContain('测量长(cm)') + expect(document.body.textContent).toContain('测量图片') + expect(document.body.textContent).toContain('保存箱规') + }) + it('does not expose unknown measurement source codes', async () => { vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ sourceType: 'LEGACY_DEVICE' })) diff --git a/src/modules/inbounds/measurement/InboundMeasurementPanel.vue b/src/modules/inbounds/measurement/InboundMeasurementPanel.vue index 72b92931..8ff43ae9 100644 --- a/src/modules/inbounds/measurement/InboundMeasurementPanel.vue +++ b/src/modules/inbounds/measurement/InboundMeasurementPanel.vue @@ -1,7 +1,7 @@