diff --git a/src/navigation/clientNavigation.test.mjs b/src/navigation/clientNavigation.test.mjs index 6da3593..0a0e52c 100644 --- a/src/navigation/clientNavigation.test.mjs +++ b/src/navigation/clientNavigation.test.mjs @@ -41,7 +41,7 @@ test('keeps the confirmed top-level sequence from the client workbench prototype ) }) -test('keeps the confirmed navigation groups and leaf order', () => { +test('keeps only implemented navigation groups visible', () => { assert.deepEqual( clientNavigation.map((node) => ({ title: node.title, @@ -51,23 +51,7 @@ test('keeps the confirmed navigation groups and leaf order', () => { { title: '业务总览', children: undefined }, { title: '头程物流', - children: ['头程下单', '一键导入', '快速下单'], - }, - { - title: '出海下单', - children: ['海外采购', '美国本土卡', '美本土散板'], - }, - { - title: '海外仓', - children: ['贴标申请', '退货入库', '退货换标', '退货出库'], - }, - { - title: '订单管理', - children: ['我的订单', '入库订单列表', '派送订单列表'], - }, - { - title: '财务结算', - children: ['应付账单'], + children: ['头程下单'], }, { title: '企业管理', @@ -78,7 +62,7 @@ test('keeps the confirmed navigation groups and leaf order', () => { ) }) -test('provides icons and unique keys recursively for every prototype item', () => { +test('provides icons and unique keys recursively for every visible item', () => { const nodes = collectNavigationNodes(clientNavigation) for (const node of nodes) { @@ -87,26 +71,13 @@ test('provides icons and unique keys recursively for every prototype item', () = assert.equal(new Set(nodes.map((node) => node.key)).size, nodes.length) }) -test('flattens the complete prototype tree with unique paths', () => { +test('flattens visible leaves with unique paths', () => { const leaves = getNavigationLeaves(clientNavigation) const paths = leaves.map((leaf) => leaf.path) assert.deepEqual(paths, [ '/', '/orders/first-leg', - '/first-leg/import', - '/first-leg/quick-order', - '/cross-border/procurement', - '/cross-border/domestic-trucking', - '/cross-border/pallet-shipping', - '/overseas-warehouse/labeling', - '/overseas-warehouse/return-inbound', - '/overseas-warehouse/return-relabel', - '/overseas-warehouse/return-outbound', - '/orders/my', - '/orders/inbound', - '/orders/delivery', - '/finance/payables', '/company/profile', '/organization/members', '/organization/roles', @@ -114,39 +85,23 @@ test('flattens the complete prototype tree with unique paths', () => { '/account/profile', ]) assert.equal(new Set(paths).size, paths.length) - assert.ok(leaves.filter((leaf) => leaf.permission).every((leaf) => leaf.permission?.trim().length > 0)) + assert.ok(leaves.every((leaf) => leaf.permission.trim().length > 0)) }) test('filters inaccessible leaves and empty navigation groups', () => { const visible = filterNavigationByPermissions(clientNavigation, ['account:profile:view', 'order:first-leg:list']) - assert.deepEqual(getNavigationLeaves(visible).map((item) => item.path), [ - '/orders/first-leg', - '/first-leg/import', - '/first-leg/quick-order', - '/cross-border/procurement', - '/cross-border/domestic-trucking', - '/cross-border/pallet-shipping', - '/overseas-warehouse/labeling', - '/overseas-warehouse/return-inbound', - '/overseas-warehouse/return-relabel', - '/overseas-warehouse/return-outbound', - '/orders/my', - '/orders/inbound', - '/orders/delivery', - '/finance/payables', - '/account/profile', - ]) - assert.deepEqual(visible.map((item) => item.title), ['头程物流', '出海下单', '海外仓', '订单管理', '财务结算', '我的信息']) + assert.deepEqual(getNavigationLeaves(visible).map((item) => item.path), ['/orders/first-leg', '/account/profile']) + assert.deepEqual(visible.map((item) => item.title), ['头程物流', '我的信息']) assert.equal(getFirstAccessiblePath(['account:profile:view']), '/account/profile') assert.equal(getFirstAccessiblePath([]), '/forbidden') }) test('excludes entries marked for manual hiding without affecting other visible items', () => { const visible = filterNavigationByPermissions([ - { key: 'shown', title: '显示入口', icon: LayoutGrid, path: '/shown' }, - { key: 'hidden', title: '隐藏入口', icon: LayoutGrid, path: '/hidden', hidden: true }, - ], []) + { key: 'shown', title: '显示入口', icon: LayoutGrid, path: '/shown', permission: 'shown:view' }, + { key: 'hidden', title: '隐藏入口', icon: LayoutGrid, path: '/hidden', permission: 'hidden:view', hidden: true }, + ], ['shown:view', 'hidden:view']) assert.deepEqual(getNavigationLeaves(visible).map((item) => item.path), ['/shown']) }) diff --git a/src/navigation/clientNavigation.ts b/src/navigation/clientNavigation.ts index ddf14a9..13aac40 100644 --- a/src/navigation/clientNavigation.ts +++ b/src/navigation/clientNavigation.ts @@ -5,17 +5,10 @@ import { ClipboardList, KeyRound, LayoutGrid, - Package, - PlaneTakeoff, - ReceiptText, Settings, - Ship, ShieldCheck, - Tags, Truck, Users, - Warehouse, - Zap, } from '@lucide/vue' export interface ClientNavigationBaseNode { @@ -28,7 +21,7 @@ export interface ClientNavigationBaseNode { export interface ClientNavigationLeaf extends ClientNavigationBaseNode { path: string - permission?: string + permission: string children?: never } @@ -48,49 +41,52 @@ export const clientNavigation: ClientNavigationNode[] = [ icon: Truck, children: [ { key: 'first-leg-orders', title: '头程下单', icon: ClipboardList, path: '/orders/first-leg', permission: 'order:first-leg:list' }, - { key: 'first-leg-import', title: '一键导入', icon: Package, path: '/first-leg/import' }, - { key: 'first-leg-quick-order', title: '快速下单', icon: Zap, path: '/first-leg/quick-order' }, - ], - }, - { - key: 'cross-border', - title: '出海下单', - icon: PlaneTakeoff, - children: [ - { key: 'cross-border-procurement', title: '海外采购', icon: Package, path: '/cross-border/procurement' }, - { key: 'cross-border-domestic-trucking', title: '美国本土卡', icon: Truck, path: '/cross-border/domestic-trucking' }, - { key: 'cross-border-pallet-shipping', title: '美本土散板', icon: Ship, path: '/cross-border/pallet-shipping' }, - ], - }, - { - key: 'overseas-warehouse', - title: '海外仓', - icon: Warehouse, - children: [ - { key: 'overseas-labeling', title: '贴标申请', icon: Tags, path: '/overseas-warehouse/labeling' }, - { key: 'overseas-return-inbound', title: '退货入库', icon: Package, path: '/overseas-warehouse/return-inbound' }, - { key: 'overseas-return-relabel', title: '退货换标', icon: Tags, path: '/overseas-warehouse/return-relabel' }, - { key: 'overseas-return-outbound', title: '退货出库', icon: Truck, path: '/overseas-warehouse/return-outbound' }, - ], - }, - { - key: 'order-management', - title: '订单管理', - icon: ClipboardList, - children: [ - { key: 'orders-my', title: '我的订单', icon: ReceiptText, path: '/orders/my' }, - { key: 'orders-inbound', title: '入库订单列表', icon: Package, path: '/orders/inbound' }, - { key: 'orders-delivery', title: '派送订单列表', icon: Truck, path: '/orders/delivery' }, - ], - }, - { - key: 'finance', - title: '财务结算', - icon: ReceiptText, - children: [ - { key: 'finance-payables', title: '应付账单', icon: ReceiptText, path: '/finance/payables' }, + // 原型入口:接入批量导入接口与权限资源后再放开。 + // { key: 'first-leg-import', title: '一键导入', icon: Package, path: '/first-leg/import', permission: 'merchant:first-leg:import' }, + // 原型入口:接入快速下单接口与权限资源后再放开。 + // { key: 'first-leg-quick-order', title: '快速下单', icon: Zap, path: '/first-leg/quick-order', permission: 'merchant:first-leg:quick-create' }, ], }, + // 原型菜单:对应页面目录与路由已预留,接入后端接口、权限资源后取消注释。 + // { + // key: 'cross-border', + // title: '出海下单', + // icon: PlaneTakeoff, + // children: [ + // { key: 'cross-border-procurement', title: '海外采购', icon: Package, path: '/cross-border/procurement', permission: 'merchant:cross-border:procurement' }, + // { key: 'cross-border-domestic-trucking', title: '美国本土卡', icon: Truck, path: '/cross-border/domestic-trucking', permission: 'merchant:cross-border:domestic-trucking' }, + // { key: 'cross-border-pallet-shipping', title: '美本土散板', icon: Ship, path: '/cross-border/pallet-shipping', permission: 'merchant:cross-border:pallet-shipping' }, + // ], + // }, + // { + // key: 'overseas-warehouse', + // title: '海外仓', + // icon: Warehouse, + // children: [ + // { key: 'overseas-labeling', title: '贴标申请', icon: Tags, path: '/overseas-warehouse/labeling', permission: 'merchant:overseas-warehouse:labeling' }, + // { key: 'overseas-return-inbound', title: '退货入库', icon: Package, path: '/overseas-warehouse/return-inbound', permission: 'merchant:overseas-warehouse:return-inbound' }, + // { key: 'overseas-return-relabel', title: '退货换标', icon: Tags, path: '/overseas-warehouse/return-relabel', permission: 'merchant:overseas-warehouse:return-relabel' }, + // { key: 'overseas-return-outbound', title: '退货出库', icon: Truck, path: '/overseas-warehouse/return-outbound', permission: 'merchant:overseas-warehouse:return-outbound' }, + // ], + // }, + // { + // key: 'order-management', + // title: '订单管理', + // icon: ClipboardList, + // children: [ + // { key: 'orders-my', title: '我的订单', icon: ReceiptText, path: '/orders/my', permission: 'merchant:order:list' }, + // { key: 'orders-inbound', title: '入库订单列表', icon: Package, path: '/orders/inbound', permission: 'merchant:warehouse:inbound:list' }, + // { key: 'orders-delivery', title: '派送订单列表', icon: Truck, path: '/orders/delivery', permission: 'merchant:warehouse:delivery:list' }, + // ], + // }, + // { + // key: 'finance', + // title: '财务结算', + // icon: ReceiptText, + // children: [ + // { key: 'finance-payables', title: '应付账单', icon: ReceiptText, path: '/finance/payables', permission: 'merchant:finance:payables:list' }, + // ], + // }, { key: 'company', title: '企业管理', @@ -126,7 +122,7 @@ export function filterNavigationByPermissions( for (const node of nodes) { if (node.hidden) continue if (!isNavigationGroup(node)) { - if (!node.permission || allowed.has(node.permission)) result.push(node) + if (allowed.has(node.permission)) result.push(node) continue } const children = filterNavigationByPermissions(node.children, permissions) @@ -136,7 +132,7 @@ export function filterNavigationByPermissions( } export function getFirstAccessiblePath(permissions: readonly string[]) { - return getNavigationLeaves(filterNavigationByPermissions(clientNavigation, permissions)).find((leaf) => leaf.permission)?.path ?? '/forbidden' + return getNavigationLeaves(filterNavigationByPermissions(clientNavigation, permissions))[0]?.path ?? '/forbidden' } function findNavigationParentKeys(