This commit is contained in:
2026-08-13 14:37:59 +08:00
parent d0394210f6
commit da20613aa0
17 changed files with 50 additions and 54 deletions
+4 -3
View File
@@ -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 验收通过后,再使用开发验收账号通过浏览器逐页检查真实接口调用、原型、权限、错误态、空态和窄屏布局。
+5 -5
View File
@@ -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' },
],
},
{
@@ -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[] = [
@@ -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<string, string>): Promise<void> }
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<string, string>): Promise<void> }
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<string, unknown>): Promise<void>
@@ -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<string, unknown>): Promise<void> }
@@ -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<Record<string, unknown>>
@@ -69,9 +69,9 @@ const selectedRows = ref<ArapRow[]>([])
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'))
@@ -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<void> }).openDetail(statement)
await flushPromises()
expect(getFinanceFeeSource).not.toHaveBeenCalled()
@@ -71,9 +71,9 @@ const adjustStatement = ref<FinanceStatementReadModel | null>(null)
const adjustReason = ref('')
const adjustLines = ref<AdjustmentRow[]>([])
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'))
@@ -66,10 +66,9 @@ const receiptFile = ref<File | null>(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'))
@@ -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<string, unknown>, action: 'VOID' | 'REOPEN'): Promise<void> }
@@ -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<void>; submitAdjustment(): Promise<void>; 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<string, string>): Promise<void>; openCreate(): Promise<void>; submitCreate(): Promise<void>; openPayment(row: FinancePayableSettlement): void; submitPayment(): Promise<void>; 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<void> }
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)
@@ -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))
+9 -9
View File
@@ -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[]
@@ -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 } })
@@ -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: '装柜完成' },
@@ -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: '装柜完成' },
@@ -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)
-1
View File
@@ -9,7 +9,6 @@ const orderStatusLabels: Record<string, string> = {
CANCELLED: '已取消',
PENDING_REVIEW: '待审核',
WAIT_MEASURE: '待测量数据',
INBOUNDED: '已入库',
WAIT_SPLIT: '待分柜',
LOADING: '装柜中',
LOADED: '装柜完成',