diff --git a/AGENTS.md b/AGENTS.md index 523a41bf..598fd78c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -138,6 +138,7 @@ pnpm build ## 全量验收脚本 -- 本地 Admin 自动回归由后端仓库的 `../../baiyue-firstleg/scripts/frontend-full-regression.ps1` 统一编排;先执行 `-DryRun`,再运行 `pnpm test` 和 `pnpm typecheck`。 -- 测试环境接口验收入口为 `../../baiyue-firstleg/scripts/admin-test-env-acceptance.mjs` 及 `../../baiyue-firstleg/scripts/admin-test-env-modules/`;这些脚本会写入测试数据,必须在当前对话获得明确测试环境授权后执行。 -- 脚本通过只证明自动化契约和接口检查通过;样式验收仍使用开发环境验收账号,通过浏览器逐页检查原型、权限、错误态、空态和窄屏布局。 +- Admin 全量验收唯一入口为 `../../baiyue-firstleg/scripts/admin-test-env-acceptance.mjs`,默认模块列表覆盖平台全模块;单模块定位先查 `../../baiyue-firstleg/scripts/admin-test-env-modules/README.md`。 +- 该入口通过测试环境 HTTP 验证真实服务、权限、状态、幂等和跨服务链路,会写入或停用测试数据,必须获得当前对话明确授权。 +- `pnpm test/typecheck` 和 `frontend-full-regression.ps1` 仅是本地质量检查,不代表 Admin 服务已完成全量验收。 +- HTTP 验收通过后,再使用开发验收账号通过浏览器逐页检查真实接口调用、原型、权限、错误态、空态和窄屏布局。 diff --git a/src/core/navigation/adminNavigation.ts b/src/core/navigation/adminNavigation.ts index 9bcb7cfc..789de5e9 100644 --- a/src/core/navigation/adminNavigation.ts +++ b/src/core/navigation/adminNavigation.ts @@ -140,11 +140,11 @@ export const adminNavigation: AdminNavigationNode[] = [ title: '财务管理', icon: PrototypeFinanceIcon, children: [ - { key: 'finance-customer-accounts', title: '客户账户', icon: CircleDollarSign, path: '/finance/customer-accounts', permission: 'platform:finance:customer-account:list', permissionAnyOf: ['platform:finance:account:view'] }, - { key: 'finance-customer-arap', title: '客户应收应付', icon: Database, path: '/finance/customer-arap', permission: 'platform:finance:customer-arap:list', permissionAnyOf: ['platform:finance:bill:view'] }, - { key: 'finance-customer-statements', title: '客户对账单', icon: FileCheck2, path: '/finance/customer-statements', permission: 'platform:finance:customer-statement:list', permissionAnyOf: ['platform:finance:bill:view'] }, - { key: 'finance-settlement-receivables', title: '结算单应收', icon: CircleDollarSign, path: '/finance/settlement-receivables', permission: 'platform:finance:settlement-ar:list', permissionAnyOf: ['platform:finance:settlement-ar:view'] }, - { key: 'finance-settlement-payables', title: '结算单应付', icon: Database, path: '/finance/settlement-payables', permission: 'platform:finance:settlement-ap:list', permissionAnyOf: ['platform:finance:settlement-ap:view'] }, + { key: 'finance-customer-accounts', title: '客户账户', icon: CircleDollarSign, path: '/finance/customer-accounts', permission: 'platform:finance:customer-account:list' }, + { key: 'finance-customer-arap', title: '客户应收应付', icon: Database, path: '/finance/customer-arap', permission: 'platform:finance:customer-arap:list' }, + { key: 'finance-customer-statements', title: '客户对账单', icon: FileCheck2, path: '/finance/customer-statements', permission: 'platform:finance:customer-statement:list' }, + { key: 'finance-settlement-receivables', title: '结算单应收', icon: CircleDollarSign, path: '/finance/settlement-receivables', permission: 'platform:finance:settlement-ar:list' }, + { key: 'finance-settlement-payables', title: '结算单应付', icon: Database, path: '/finance/settlement-payables', permission: 'platform:finance:settlement-ap:list' }, ], }, { diff --git a/src/modules/finance/pages/FinanceCustomerAccountsView.vue b/src/modules/finance/pages/FinanceCustomerAccountsView.vue index 672a407e..2a4f8e01 100644 --- a/src/modules/finance/pages/FinanceCustomerAccountsView.vue +++ b/src/modules/finance/pages/FinanceCustomerAccountsView.vue @@ -40,7 +40,7 @@ const ledgerPage = ref(1) const ledgerPageSize = ref(20) const ledgerTotal = ref(0) -const canView = computed(() => access.can('platform:finance:customer-account:list') || access.can('platform:finance:account:view')) +const canView = computed(() => access.can('platform:finance:customer-account:list')) const canViewTerms = computed(() => access.can('platform:finance:customer-terms:view')) const canUpdateTerms = computed(() => canViewTerms.value && access.can('platform:finance:customer-terms:update')) const queryFields: QueryField[] = [ diff --git a/src/modules/finance/pages/FinanceCustomerArapView.test.ts b/src/modules/finance/pages/FinanceCustomerArapView.test.ts index 74bc932e..9f589d05 100644 --- a/src/modules/finance/pages/FinanceCustomerArapView.test.ts +++ b/src/modules/finance/pages/FinanceCustomerArapView.test.ts @@ -80,7 +80,7 @@ describe('FinanceCustomerArapView G2 operations', () => { }) it('shows detail from the list permission but keeps G2 operations independent', async () => { - const wrapper = await mountView(['platform:finance:bill:view']) + const wrapper = await mountView(['platform:finance:customer-arap:list']) await loadRows(wrapper) const buttonLabels = wrapper.findAll('button').map((button) => button.text()) @@ -94,7 +94,7 @@ describe('FinanceCustomerArapView G2 operations', () => { }) it('loads all customers by default and keeps explicit customer filtering', async () => { - const wrapper = await mountView(['platform:finance:bill:view', 'platform:customer:list']) + const wrapper = await mountView(['platform:finance:customer-arap:list', 'platform:customer:list']) expect(listFinanceFeePool).toHaveBeenCalledWith(undefined, undefined) const vm = wrapper.vm as unknown as { load(model: Record): Promise } await vm.load({ customerId: '10001', direction: 'RECEIVABLE', status: '', keyword: '' }) @@ -109,7 +109,7 @@ describe('FinanceCustomerArapView G2 operations', () => { { poolItemId: 'RECEIVABLE:42', feeSourceId: '42', customerId: '10001', direction: 'RECEIVABLE', sourceType: 'INBOUND_FEE', sourceId: '81', sourceVersion: 3, orderId: null, inboundId: '91', containerId: null, feeItemName: '运费', amount: 100, currency: 'CNY', status: 'AVAILABLE', createdAt: '2026-08-11' }, { poolItemId: 'PAYABLE:43', feeSourceId: null, customerId: '10002', direction: 'PAYABLE', sourceType: 'MANUAL_COST', sourceId: '43', sourceVersion: 1, orderId: '11', inboundId: null, containerId: null, feeItemName: '拖车费', amount: 200, currency: 'CNY', status: 'POSTED', createdAt: '2026-08-10' }, ]) - const wrapper = await mountView(['platform:finance:bill:view']) + const wrapper = await mountView(['platform:finance:customer-arap:list']) const vm = wrapper.vm as unknown as { load(model: Record): Promise } await vm.load({ customerId: '', direction: '', status: '', keyword: '' }) await flushPromises() @@ -118,7 +118,7 @@ describe('FinanceCustomerArapView G2 operations', () => { }) it('loads detail and submits review and settlement changes with the returned version', async () => { - const wrapper = await mountView(['platform:finance:bill:view', 'platform:finance:fee-source:view', 'platform:finance:fee-source:review', 'platform:finance:fee-source:settlement']) + const wrapper = await mountView(['platform:finance:customer-arap:list', 'platform:finance:fee-source:view', 'platform:finance:fee-source:review', 'platform:finance:fee-source:settlement']) await loadRows(wrapper) const vm = wrapper.vm as unknown as { openDetail(row: Record): Promise @@ -145,7 +145,7 @@ describe('FinanceCustomerArapView G2 operations', () => { it('renders request and trace ids when detail loading fails', async () => { vi.mocked(getFinanceFeeSource).mockRejectedValueOnce(new ApiResponseError('费用来源不可用', 'FIN-FEE-404', 404, undefined, 'req-g2-error', 'trace-g2-error')) - const wrapper = await mountView(['platform:finance:bill:view', 'platform:finance:fee-source:view']) + const wrapper = await mountView(['platform:finance:customer-arap:list', 'platform:finance:fee-source:view']) await loadRows(wrapper) const vm = wrapper.vm as unknown as { openDetail(row: Record): Promise } @@ -157,7 +157,7 @@ describe('FinanceCustomerArapView G2 operations', () => { }) it('restores the independent detail route from its fee source id', async () => { - const wrapper = await mountView(['platform:finance:bill:view'], '/finance/customer-arap/42') + const wrapper = await mountView(['platform:finance:customer-arap:list'], '/finance/customer-arap/42') expect(getFinanceFeeSource).toHaveBeenCalledWith('42') expect(wrapper.text()).toContain('费用来源详情') expect(wrapper.text()).toContain('IB-91') @@ -165,7 +165,7 @@ describe('FinanceCustomerArapView G2 operations', () => { }) it('creates a reconciliation draft from selected eligible receivables', async () => { - const wrapper = await mountView(['platform:finance:bill:view', 'platform:finance:reconciliation:create']) + const wrapper = await mountView(['platform:finance:customer-arap:list', 'platform:finance:reconciliation:create']) await loadRows(wrapper) const vm = wrapper.vm as unknown as { selectedRows: Array> diff --git a/src/modules/finance/pages/FinanceCustomerArapView.vue b/src/modules/finance/pages/FinanceCustomerArapView.vue index bafca947..a36694be 100644 --- a/src/modules/finance/pages/FinanceCustomerArapView.vue +++ b/src/modules/finance/pages/FinanceCustomerArapView.vue @@ -69,9 +69,9 @@ const selectedRows = ref([]) const page = ref(1) const pageSize = ref(20) -const canView = computed(() => access.can('platform:finance:customer-arap:list') || access.can('platform:finance:bill:view')) +const canView = computed(() => access.can('platform:finance:customer-arap:list')) const canListCustomers = computed(() => canView.value || access.can('platform:customer:list')) -const canViewSource = computed(() => access.can('platform:finance:fee-source:view') || access.can('platform:finance:bill:view')) +const canViewSource = computed(() => access.can('platform:finance:customer-arap:list')) const canReviewSource = computed(() => access.can('platform:finance:fee-source:review')) const canSettleSource = computed(() => access.can('platform:finance:fee-source:settlement')) const canCreateStatement = computed(() => access.can('platform:finance:reconciliation:create')) diff --git a/src/modules/finance/pages/FinanceCustomerStatementsView.test.ts b/src/modules/finance/pages/FinanceCustomerStatementsView.test.ts index 886660ba..d1d47aee 100644 --- a/src/modules/finance/pages/FinanceCustomerStatementsView.test.ts +++ b/src/modules/finance/pages/FinanceCustomerStatementsView.test.ts @@ -34,7 +34,7 @@ const detail: FinanceReconciliationDetail = { revisions: [], } -async function mountPage(permissions = ['platform:finance:bill:view', 'platform:finance:fee-source:view']) { +async function mountPage(permissions = ['platform:finance:customer-statement:list', 'platform:finance:fee-source:view']) { const pinia = createPinia(); setActivePinia(pinia) const auth = useAuthStore(); auth.token = 'token'; auth.permissions = permissions useAccessPreviewStore().initializeAfterLogin() @@ -108,7 +108,7 @@ describe('FinanceCustomerStatementsView', () => { it('disables statement generation when customer selection permission is missing', async () => { vi.mocked(listPlatformTenants).mockClear() - await mountPage(['platform:finance:bill:view', 'platform:finance:reconciliation:create']) + await mountPage(['platform:finance:customer-statement:list', 'platform:finance:reconciliation:create']) const button = [...document.querySelectorAll('button')].find((item) => item.textContent?.includes('生成对账单')) expect(button).toBeTruthy() expect(button?.disabled).toBe(true) @@ -116,7 +116,7 @@ describe('FinanceCustomerStatementsView', () => { }) it('does not request fee-source details without its permission and keeps frozen trace fields visible', async () => { - const wrapper = await mountPage(['platform:finance:bill:view']) + const wrapper = await mountPage(['platform:finance:customer-statement:list']) await (wrapper.vm as unknown as { openDetail(row: FinanceStatementReadModel): Promise }).openDetail(statement) await flushPromises() expect(getFinanceFeeSource).not.toHaveBeenCalled() diff --git a/src/modules/finance/pages/FinanceCustomerStatementsView.vue b/src/modules/finance/pages/FinanceCustomerStatementsView.vue index 5482f032..85a91221 100644 --- a/src/modules/finance/pages/FinanceCustomerStatementsView.vue +++ b/src/modules/finance/pages/FinanceCustomerStatementsView.vue @@ -71,9 +71,9 @@ const adjustStatement = ref(null) const adjustReason = ref('') const adjustLines = ref([]) -const canView = computed(() => access.can('platform:finance:customer-statement:list') || access.can('platform:finance:bill:view')) +const canView = computed(() => access.can('platform:finance:customer-statement:list')) const canListCustomers = computed(() => access.can('platform:customer:list')) -const canViewFeeSource = computed(() => access.can('platform:finance:fee-source:view')) +const canViewFeeSource = computed(() => access.can('platform:finance:customer-statement:list')) const canCreate = computed(() => access.can('platform:finance:reconciliation:create')) const canReview = computed(() => access.can('platform:finance:reconciliation:review')) const canIssue = computed(() => access.can('platform:finance:reconciliation:issue')) diff --git a/src/modules/finance/pages/FinanceFormalSettlementPage.vue b/src/modules/finance/pages/FinanceFormalSettlementPage.vue index af95b719..07b4ff69 100644 --- a/src/modules/finance/pages/FinanceFormalSettlementPage.vue +++ b/src/modules/finance/pages/FinanceFormalSettlementPage.vue @@ -66,10 +66,9 @@ const receiptFile = ref(null) const receiptForm = ref({ receivedDate: new Date().toISOString().slice(0, 10), amount: 0, paymentMethod: 'BANK_TRANSFER' as 'BANK_TRANSFER' | 'CASH' | 'OTHER', remark: '' }) const actionBusy = ref(false) -const viewPermission = computed(() => props.kind === 'receivable' ? 'platform:finance:settlement-ar:view' : 'platform:finance:settlement-ap:view') const createPermission = computed(() => props.kind === 'receivable' ? 'platform:finance:settlement-ar:create' : 'platform:finance:settlement-ap:create') const listPermission = computed(() => props.kind === 'receivable' ? 'platform:finance:settlement-ar:list' : 'platform:finance:settlement-ap:list') -const canView = computed(() => access.can(listPermission.value) || access.can(viewPermission.value)) +const canView = computed(() => access.can(listPermission.value)) const canListCustomers = computed(() => access.can('platform:customer:list')) const canCreate = computed(() => access.can(createPermission.value)) const canPay = computed(() => props.kind === 'payable' && access.can('platform:finance:payment:create')) diff --git a/src/modules/finance/pages/FinanceG3G4Operations.test.ts b/src/modules/finance/pages/FinanceG3G4Operations.test.ts index d279e6dc..b4d97f05 100644 --- a/src/modules/finance/pages/FinanceG3G4Operations.test.ts +++ b/src/modules/finance/pages/FinanceG3G4Operations.test.ts @@ -94,7 +94,7 @@ describe('finance G3/G4 page operations', () => { }) it('loads frozen G3 detail and submits multiple selected adjustment lines', async () => { - const pinia = piniaWithPermissions(['platform:finance:bill:view', 'platform:finance:reconciliation:adjust']) + const pinia = piniaWithPermissions(['platform:finance:customer-statement:list', 'platform:finance:reconciliation:adjust']) const wrapper = mount(FinanceCustomerStatementsView, { attachTo: document.body, global: { plugins: [pinia, ElementPlus] } }) await flushPromises() const vm = wrapper.vm as unknown as { @@ -121,7 +121,7 @@ describe('finance G3/G4 page operations', () => { }) it('loads AR linkage, uploads a voucher and allocates a real receipt to its statement', async () => { - const pinia = piniaWithPermissions(['platform:finance:settlement-ar:view', 'platform:finance:receipt:create']) + const pinia = piniaWithPermissions(['platform:finance:settlement-ar:list', 'platform:finance:receipt:create']) const wrapper = mount(FinanceFormalSettlementPage, { props: { kind: 'receivable' }, attachTo: document.body, global: { plugins: [pinia, ElementPlus] } }) await flushPromises() const vm = wrapper.vm as unknown as { @@ -145,7 +145,7 @@ describe('finance G3/G4 page operations', () => { it('submits settlement void and reopen actions with the current version and reason', async () => { const prompt = vi.spyOn(ElMessageBox, 'prompt').mockResolvedValue({ value: '账务冲销' } as never) - const pinia = piniaWithPermissions(['platform:finance:settlement-ar:view', 'platform:finance:settlement:void']) + const pinia = piniaWithPermissions(['platform:finance:settlement-ar:list', 'platform:finance:settlement:void']) const wrapper = mount(FinanceFormalSettlementPage, { props: { kind: 'receivable' }, attachTo: document.body, global: { plugins: [pinia, ElementPlus] } }) await flushPromises() const vm = wrapper.vm as unknown as { performAction(row: Record, action: 'VOID' | 'REOPEN'): Promise } diff --git a/src/modules/finance/pages/FinanceG3G4Views.test.ts b/src/modules/finance/pages/FinanceG3G4Views.test.ts index 0d7d79ee..97c88bee 100644 --- a/src/modules/finance/pages/FinanceG3G4Views.test.ts +++ b/src/modules/finance/pages/FinanceG3G4Views.test.ts @@ -83,9 +83,9 @@ describe('Finance G3/G4 views', () => { vi.mocked(createFinanceSettlementPayment).mockReset().mockResolvedValue({ ...settlementDetail, paidAmount: 100, outstandingAmount: 100, status: 'PARTIALLY_PAID', version: 5 }) }) - it('hides G3/G4 commands when only legacy bill view permission is present', async () => { - const statements = await mountWithAccess(FinanceCustomerStatementsView, ['platform:finance:bill:view']) - const settlements = await mountWithAccess(FinanceFormalSettlementPage, ['platform:finance:bill:view'], { kind: 'payable' }) + it('hides G3/G4 commands when list permissions are absent', async () => { + const statements = await mountWithAccess(FinanceCustomerStatementsView, []) + const settlements = await mountWithAccess(FinanceFormalSettlementPage, [], { kind: 'payable' }) expect(statements.text()).not.toContain('生成对账单') expect(settlements.text()).toContain('无权访问结算单应付') expect(createPayableSettlement).not.toHaveBeenCalled() @@ -93,7 +93,7 @@ describe('Finance G3/G4 views', () => { }) it('submits every selected adjustment line with the detail version', async () => { - const wrapper = await mountWithAccess(FinanceCustomerStatementsView, ['platform:finance:bill:view', 'platform:finance:reconciliation:adjust']) + const wrapper = await mountWithAccess(FinanceCustomerStatementsView, ['platform:finance:customer-statement:list', 'platform:finance:reconciliation:adjust']) const vm = wrapper.vm as unknown as { openAdjustment(row: FinanceStatementReadModel): Promise; submitAdjustment(): Promise; adjustReason: string; adjustLines: Array<{ selected: boolean; adjustedAmount: number; reason: string }> } await vm.openAdjustment(statement) vm.adjustReason = '月末核对更正' @@ -103,7 +103,7 @@ describe('Finance G3/G4 views', () => { }) it('creates a payable settlement and registers a voucher-backed payment', async () => { - const wrapper = await mountWithAccess(FinanceFormalSettlementPage, ['platform:finance:settlement-ap:view', 'platform:finance:settlement-ap:create', 'platform:finance:payment:create'], { kind: 'payable' }) + const wrapper = await mountWithAccess(FinanceFormalSettlementPage, ['platform:finance:settlement-ap:list', 'platform:finance:settlement-ap:create', 'platform:finance:payment:create'], { kind: 'payable' }) const vm = wrapper.vm as unknown as { load(model: Record): Promise; openCreate(): Promise; submitCreate(): Promise; openPayment(row: FinancePayableSettlement): void; submitPayment(): Promise; createForm: { supplierId: string; dueDate: string; feeSourceIds: string[] }; paymentFile: File | null; paymentForm: { amount: number; transactionDate: string; method: 'BANK_TRANSFER'; referenceNo: string; remark: string } } await vm.load({ customerId: '10001' }); await vm.openCreate() expect(listPlatformPartners).toHaveBeenCalledWith({ page: 1, size: 200, status: 'ACTIVE' }) @@ -118,7 +118,7 @@ describe('Finance G3/G4 views', () => { it('renders request and trace ids when G3 detail loading fails', async () => { vi.mocked(getReconciliationStatement).mockRejectedValueOnce(new ApiResponseError('对账单不可用', 'FIN_404', 404, undefined, 'req-g3-error', 'trace-g3-error')) - const wrapper = await mountWithAccess(FinanceCustomerStatementsView, ['platform:finance:bill:view']) + const wrapper = await mountWithAccess(FinanceCustomerStatementsView, ['platform:finance:customer-statement:list']) const vm = wrapper.vm as unknown as { openDetail(row: FinanceStatementReadModel): Promise } await vm.openDetail(statement); await flushPromises() expect(document.body.textContent).toContain('req-g3-error') @@ -126,9 +126,9 @@ describe('Finance G3/G4 views', () => { }) it('loads all customers by default and applies explicit customer filters', async () => { - const statements = await mountWithAccess(FinanceCustomerStatementsView, ['platform:finance:bill:view']) - const receivables = await mountWithAccess(FinanceFormalSettlementPage, ['platform:finance:settlement-ar:view'], { kind: 'receivable' }) - const payables = await mountWithAccess(FinanceFormalSettlementPage, ['platform:finance:settlement-ap:view'], { kind: 'payable' }) + const statements = await mountWithAccess(FinanceCustomerStatementsView, ['platform:finance:customer-statement:list']) + const receivables = await mountWithAccess(FinanceFormalSettlementPage, ['platform:finance:settlement-ar:list'], { kind: 'receivable' }) + const payables = await mountWithAccess(FinanceFormalSettlementPage, ['platform:finance:settlement-ap:list'], { kind: 'payable' }) expect(listFinanceStatements).toHaveBeenCalledWith(undefined) expect(listFinanceReceivableSettlements).toHaveBeenCalledWith(undefined) diff --git a/src/modules/finance/pages/FinanceManualPage.vue b/src/modules/finance/pages/FinanceManualPage.vue index e5eca79f..42785542 100644 --- a/src/modules/finance/pages/FinanceManualPage.vue +++ b/src/modules/finance/pages/FinanceManualPage.vue @@ -87,7 +87,7 @@ let receiptBillsRequest = 0 let costOptionsRequest = 0 const title = computed(() => ({ bills: '客户对账单', receipts: '结算单应收', costs: '结算单应付' }[props.mode])) -const viewPermission = computed(() => ({ bills: 'platform:finance:bill:view', receipts: 'platform:finance:receipt:view', costs: 'platform:finance:cost:view' }[props.mode])) +const viewPermission = computed(() => ({ bills: 'platform:finance:customer-statement:list', receipts: 'platform:finance:receipt:view', costs: 'platform:finance:cost:view' }[props.mode])) const createPermission = computed(() => ({ bills: 'platform:finance:bill:create', receipts: 'platform:finance:receipt:create', costs: 'platform:finance:cost:create' }[props.mode])) const canView = computed(() => access.can(viewPermission.value)) const canCreate = computed(() => Boolean(createPermission.value) && access.can(createPermission.value)) diff --git a/src/modules/finance/routes.ts b/src/modules/finance/routes.ts index c8aaa718..be31c313 100644 --- a/src/modules/finance/routes.ts +++ b/src/modules/finance/routes.ts @@ -1,13 +1,13 @@ import type { RouteRecordRaw } from 'vue-router' export const financeRoutes = [ - { path: 'finance/customer-accounts', name: 'finance-customer-accounts', component: () => import('./pages/FinanceCustomerAccountsView.vue'), meta: { title: '客户账户', description: '查看客户 CNY 应收台账并维护独立账期', permission: 'platform:finance:customer-account:list', permissionAnyOf: ['platform:finance:account:view'] } }, - { path: 'finance/customer-accounts/:customerId', name: 'finance-customer-account-detail', component: () => import('./pages/FinanceCustomerAccountsView.vue'), meta: { title: '客户账户详情', description: '查看客户派生财务汇总与账户流水', permission: 'platform:finance:customer-account:list', permissionAnyOf: ['platform:finance:account:view'], showPageHeading: false } }, - { path: 'finance/customer-arap', name: 'finance-customer-arap', component: () => import('./pages/FinanceCustomerArapView.vue'), meta: { title: '客户应收应付', description: '按客户追溯入库单、订单和柜次费用来源', permission: 'platform:finance:customer-arap:list', permissionAnyOf: ['platform:finance:bill:view'] } }, - { path: 'finance/customer-arap/:feeSourceId', name: 'finance-customer-arap-detail', component: () => import('./pages/FinanceCustomerArapView.vue'), meta: { title: '费用来源详情', description: '查看费用来源、审核进度、关联业务与操作记录', permission: 'platform:finance:customer-arap:list', permissionAnyOf: ['platform:finance:bill:view'], showPageHeading: false } }, - { path: 'finance/customer-statements', name: 'finance-customer-statements', component: () => import('./pages/FinanceCustomerStatementsView.vue'), meta: { title: '客户对账单', description: '维护 CNY 客户对账单并在出账后冻结', permission: 'platform:finance:customer-statement:list', permissionAnyOf: ['platform:finance:bill:view'] } }, - { path: 'finance/settlement-receivables', name: 'finance-settlement-receivables', component: () => import('./pages/FinanceSettlementReceivablesView.vue'), meta: { title: '结算单应收', description: '登记客户收款、凭证及对应对账单金额', permission: 'platform:finance:settlement-ar:list', permissionAnyOf: ['platform:finance:settlement-ar:view'] } }, - { path: 'finance/settlement-receivables/:settlementId', name: 'finance-settlement-receivable-detail', component: () => import('./pages/FinanceSettlementReceivablesView.vue'), meta: { title: '应收结算单详情', description: '查看应收结算信息、费用明细和收款记录', permission: 'platform:finance:settlement-ar:list', permissionAnyOf: ['platform:finance:settlement-ar:view'], showPageHeading: false } }, - { path: 'finance/settlement-payables', name: 'finance-settlement-payables', component: () => import('./pages/FinanceSettlementPayablesView.vue'), meta: { title: '结算单应付', description: '登记单票及整柜公共成本并追溯业务来源', permission: 'platform:finance:settlement-ap:list', permissionAnyOf: ['platform:finance:settlement-ap:view'] } }, - { path: 'finance/settlement-payables/:settlementId', name: 'finance-settlement-payable-detail', component: () => import('./pages/FinanceSettlementPayablesView.vue'), meta: { title: '应付结算单详情', description: '查看应付结算信息、费用明细和付款记录', permission: 'platform:finance:settlement-ap:list', permissionAnyOf: ['platform:finance:settlement-ap:view'], showPageHeading: false } }, + { path: 'finance/customer-accounts', name: 'finance-customer-accounts', component: () => import('./pages/FinanceCustomerAccountsView.vue'), meta: { title: '客户账户', description: '查看客户 CNY 应收台账并维护独立账期', permission: 'platform:finance:customer-account:list' } }, + { path: 'finance/customer-accounts/:customerId', name: 'finance-customer-account-detail', component: () => import('./pages/FinanceCustomerAccountsView.vue'), meta: { title: '客户账户详情', description: '查看客户派生财务汇总与账户流水', permission: 'platform:finance:customer-account:list', showPageHeading: false } }, + { path: 'finance/customer-arap', name: 'finance-customer-arap', component: () => import('./pages/FinanceCustomerArapView.vue'), meta: { title: '客户应收应付', description: '按客户追溯入库单、订单和柜次费用来源', permission: 'platform:finance:customer-arap:list' } }, + { path: 'finance/customer-arap/:feeSourceId', name: 'finance-customer-arap-detail', component: () => import('./pages/FinanceCustomerArapView.vue'), meta: { title: '费用来源详情', description: '查看费用来源、审核进度、关联业务与操作记录', permission: 'platform:finance:customer-arap:list', showPageHeading: false } }, + { path: 'finance/customer-statements', name: 'finance-customer-statements', component: () => import('./pages/FinanceCustomerStatementsView.vue'), meta: { title: '客户对账单', description: '维护 CNY 客户对账单并在出账后冻结', permission: 'platform:finance:customer-statement:list' } }, + { path: 'finance/settlement-receivables', name: 'finance-settlement-receivables', component: () => import('./pages/FinanceSettlementReceivablesView.vue'), meta: { title: '结算单应收', description: '登记客户收款、凭证及对应对账单金额', permission: 'platform:finance:settlement-ar:list' } }, + { path: 'finance/settlement-receivables/:settlementId', name: 'finance-settlement-receivable-detail', component: () => import('./pages/FinanceSettlementReceivablesView.vue'), meta: { title: '应收结算单详情', description: '查看应收结算信息、费用明细和收款记录', permission: 'platform:finance:settlement-ar:list', showPageHeading: false } }, + { path: 'finance/settlement-payables', name: 'finance-settlement-payables', component: () => import('./pages/FinanceSettlementPayablesView.vue'), meta: { title: '结算单应付', description: '登记单票及整柜公共成本并追溯业务来源', permission: 'platform:finance:settlement-ap:list' } }, + { path: 'finance/settlement-payables/:settlementId', name: 'finance-settlement-payable-detail', component: () => import('./pages/FinanceSettlementPayablesView.vue'), meta: { title: '应付结算单详情', description: '查看应付结算信息、费用明细和付款记录', permission: 'platform:finance:settlement-ap:list', showPageHeading: false } }, ] satisfies RouteRecordRaw[] diff --git a/src/modules/unified-orders/api/unifiedOrders.test.ts b/src/modules/unified-orders/api/unifiedOrders.test.ts index 6411ddc6..edcaf84c 100644 --- a/src/modules/unified-orders/api/unifiedOrders.test.ts +++ b/src/modules/unified-orders/api/unifiedOrders.test.ts @@ -52,7 +52,7 @@ describe('unified orders API contract', () => { it('forwards every main-status tab with search and pagination unchanged', async () => { const statuses = [ - 'PENDING_REVIEW', 'WAIT_MEASURE', 'INBOUNDED', 'WAIT_SPLIT', + 'PENDING_REVIEW', 'WAIT_MEASURE', 'WAIT_SPLIT', 'LOADING', 'LOADED', 'DELIVERED', ] as const vi.mocked(http.get).mockResolvedValue({ data: { records: [], page: 3, size: 20, total: 0, pages: 0 } }) diff --git a/src/modules/unified-orders/api/unifiedOrders.ts b/src/modules/unified-orders/api/unifiedOrders.ts index ab004f30..c4418970 100644 --- a/src/modules/unified-orders/api/unifiedOrders.ts +++ b/src/modules/unified-orders/api/unifiedOrders.ts @@ -5,7 +5,6 @@ export const unifiedOrdersApiPath = '/platform/v1/orders' export type UnifiedOrderMainStatus = | 'PENDING_REVIEW' | 'WAIT_MEASURE' - | 'INBOUNDED' | 'WAIT_SPLIT' | 'LOADING' | 'LOADED' @@ -14,7 +13,6 @@ export type UnifiedOrderMainStatus = export const unifiedOrderStatusOptions: Array<{ value: UnifiedOrderMainStatus; label: string }> = [ { value: 'PENDING_REVIEW', label: '待审核' }, { value: 'WAIT_MEASURE', label: '待测量数据' }, - { value: 'INBOUNDED', label: '已入库' }, { value: 'WAIT_SPLIT', label: '待分柜' }, { value: 'LOADING', label: '装柜中' }, { value: 'LOADED', label: '装柜完成' }, diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.requests.test.ts b/src/modules/unified-orders/pages/UnifiedOrdersView.requests.test.ts index d85832f8..23617953 100644 --- a/src/modules/unified-orders/pages/UnifiedOrdersView.requests.test.ts +++ b/src/modules/unified-orders/pages/UnifiedOrdersView.requests.test.ts @@ -21,7 +21,6 @@ vi.mock('@/modules/unified-orders/api/unifiedOrders', () => ({ unifiedOrderStatusOptions: [ { value: 'PENDING_REVIEW', label: '待审核' }, { value: 'WAIT_MEASURE', label: '待测量数据' }, - { value: 'INBOUNDED', label: '已入库' }, { value: 'WAIT_SPLIT', label: '待分柜' }, { value: 'LOADING', label: '装柜中' }, { value: 'LOADED', label: '装柜完成' }, diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts index 70942205..3575320b 100644 --- a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts +++ b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts @@ -7,9 +7,9 @@ const source = readFileSync(resolve(process.cwd(), 'src/modules/unified-orders/p const routeSource = readFileSync(resolve(process.cwd(), 'src/modules/unified-orders/routes.ts'), 'utf8') describe('UnifiedOrdersView contract', () => { - it('only exposes the seven product main statuses', () => { + it('only exposes the six product main statuses', () => { expect(unifiedOrderStatusOptions.map((item) => item.label)).toEqual([ - '待审核', '待测量数据', '已入库', '待分柜', '装柜中', '装柜完成', '派送完成', + '待审核', '待测量数据', '待分柜', '装柜中', '装柜完成', '派送完成', ]) for (const legacyLabel of ['待客户确认', '差异处理中', '派送中', '进入分柜']) { expect(source).not.toContain(legacyLabel) diff --git a/src/modules/unified-orders/status.ts b/src/modules/unified-orders/status.ts index e426c475..85f4e3d0 100644 --- a/src/modules/unified-orders/status.ts +++ b/src/modules/unified-orders/status.ts @@ -9,7 +9,6 @@ const orderStatusLabels: Record = { CANCELLED: '已取消', PENDING_REVIEW: '待审核', WAIT_MEASURE: '待测量数据', - INBOUNDED: '已入库', WAIT_SPLIT: '待分柜', LOADING: '装柜中', LOADED: '装柜完成',