diff --git a/src/modules/order-management/deliveryOrders.test.mjs b/src/modules/order-management/deliveryOrders.test.mjs index 02dcbe3..ded9b86 100644 --- a/src/modules/order-management/deliveryOrders.test.mjs +++ b/src/modules/order-management/deliveryOrders.test.mjs @@ -33,7 +33,7 @@ test('uses only authenticated merchant delivery endpoints without customer scope test('keeps list, read-only detail and create permissions independent in active routes', () => { const listRoute = routesSource.match(/path: 'orders\/delivery',[\s\S]*?\n\s*},/)?.[0] ?? '' assert.match(listRoute, /permission: 'merchant:warehouse:delivery:list'/) - assert.doesNotMatch(listRoute, /navigation:/) + assert.match(listRoute, /navigation: \{ key: 'orders-delivery', icon: Truck \}/) assert.match(routesSource, /path: 'orders\/delivery\/create'[\s\S]*DeliveryOrderCreateView\.vue[\s\S]*permission: 'merchant:warehouse:delivery:create'/) assert.match(routesSource, /path: 'orders\/delivery\/:deliveryNo'[\s\S]*DeliveryOrderDetailView\.vue[\s\S]*props: true[\s\S]*permission: 'merchant:warehouse:delivery:list'/) assert.match(routesSource, /orders-delivery-create[\s\S]*keepAlive: false/) diff --git a/src/modules/order-management/routes.ts b/src/modules/order-management/routes.ts index c6811eb..9deae96 100644 --- a/src/modules/order-management/routes.ts +++ b/src/modules/order-management/routes.ts @@ -1,4 +1,4 @@ -import { ClipboardList, ReceiptText } from '@lucide/vue' +import { ClipboardList, ReceiptText, Truck, Warehouse } from '@lucide/vue' import type { ClientModuleManifest } from '../types.ts' export const orderManagementModule = { @@ -19,6 +19,7 @@ export const orderManagementModule = { component: () => import('./views/InboundOrdersView.vue'), release: 'active', meta: { title: '入库订单列表', description: '查询海外仓入库订单', permission: 'merchant:warehouse:inbound:list' }, + navigation: { key: 'orders-inbound', icon: Warehouse }, }, { path: 'orders/inbound/:planNo/detail', @@ -34,6 +35,7 @@ export const orderManagementModule = { component: () => import('./views/DeliveryOrdersView.vue'), release: 'active', meta: { title: '派送订单列表', description: '查询海外仓派送订单', permission: 'merchant:warehouse:delivery:list' }, + navigation: { key: 'orders-delivery', icon: Truck }, }, { path: 'orders/delivery/create', diff --git a/src/navigation/clientNavigation.test.mjs b/src/navigation/clientNavigation.test.mjs index 494f794..926f714 100644 --- a/src/navigation/clientNavigation.test.mjs +++ b/src/navigation/clientNavigation.test.mjs @@ -52,7 +52,7 @@ test('keeps standalone business pages at the client sidebar root', () => { { title: '首页', children: undefined }, { title: '订单中心', - children: ['头程订单', '海外采购', '美国本土卡', '美本土散板'], + children: ['头程订单', '入库订单', '派送订单', '海外采购', '美国本土卡', '美本土散板'], }, { title: '报关资料', children: undefined }, { title: '船期价格', children: undefined }, @@ -88,6 +88,8 @@ test('flattens visible leaves with unique paths', () => { assert.deepEqual(paths, [ '/', '/orders/first-leg', + '/orders/inbound', + '/orders/delivery', '/cross-border/procurement', '/cross-border/domestic-trucking', '/cross-border/pallet-shipping', @@ -119,6 +121,24 @@ test('filters inaccessible leaves and empty navigation groups', () => { assert.equal(getFirstAccessiblePath([]), '/forbidden') }) +test('exposes active inbound and delivery queries only with their existing read permissions', () => { + const deliveryOnly = ['merchant:warehouse:delivery:list'] + const inboundOnly = ['merchant:warehouse:inbound:list'] + assert.deepEqual(getNavigationLeaves(filterNavigationByPermissions(clientNavigation, deliveryOnly)) + .map(({ title, path }) => ({ title, path })), [{ title: '派送订单', path: '/orders/delivery' }]) + assert.deepEqual(getNavigationLeaves(filterNavigationByPermissions(clientNavigation, inboundOnly)) + .map(({ title, path }) => ({ title, path })), [{ title: '入库订单', path: '/orders/inbound' }]) + assert.equal(getFirstAccessiblePath(deliveryOnly), '/orders/delivery') + assert.equal(getFirstAccessiblePath(inboundOnly), '/orders/inbound') + assert.deepEqual(getNavigationLeaves(filterNavigationByPermissions(clientNavigation, + ['merchant:warehouse:delivery:create'])), []) + assert.deepEqual(getRouteBreadcrumbs('/orders/delivery/DL-1', '派送单详情'), [ + { title: '首页', path: '/' }, { title: '订单中心' }, + { title: '派送订单', path: '/orders/delivery' }, { title: '派送单详情' }, + ]) + assert.deepEqual(getNavigationParentKeys(clientNavigation, '/orders/delivery'), ['order-center']) +}) + test('excludes entries marked for manual hiding without affecting other visible items', () => { const visible = filterNavigationByPermissions([ { key: 'shown', title: '显示入口', icon: LayoutGrid, path: '/shown', permission: 'shown:view' }, @@ -339,7 +359,7 @@ test('keeps the dashboard route permission synchronized with navigation', () => assert.match(dashboardRoute, /permission: 'dashboard:view'/) }) -test('keeps internal operational pages routable without exposing them in customer navigation', () => { +test('exposes customer business lists and keeps utility routes outside navigation', () => { const routerSource = [ 'first-leg', 'cross-border', @@ -364,8 +384,6 @@ test('keeps internal operational pages routable without exposing them in custome const hiddenActivePaths = new Set([ 'first-leg/quick-order', - 'orders/inbound', - 'orders/delivery', 'overseas-warehouse/return-inventory', 'overseas-warehouse/return-cartons', ]) diff --git a/src/navigation/clientNavigation.ts b/src/navigation/clientNavigation.ts index be4b6c3..321af20 100644 --- a/src/navigation/clientNavigation.ts +++ b/src/navigation/clientNavigation.ts @@ -52,6 +52,8 @@ export const clientNavigation: ClientNavigationNode[] = [ icon: ClipboardList, children: [ requireLeaf('first-leg-orders', '头程订单'), + requireLeaf('orders-inbound', '入库订单'), + requireLeaf('orders-delivery', '派送订单'), requireLeaf('cross-border-procurement'), requireLeaf('cross-border-domestic-trucking'), requireLeaf('cross-border-pallet-shipping'),