This commit is contained in:
2026-08-05 10:46:42 +08:00
parent 3ffa7ec55f
commit eede351038
6 changed files with 146 additions and 126 deletions
+24 -3
View File
@@ -3,6 +3,22 @@ import { describe, expect, it } from 'vitest'
import { adminNavigation, filterAdminNavigation, type AdminNavigationNode } from '@/core/navigation/adminNavigation'
import AdminSidebarMenu from './AdminSidebarMenu.vue'
const visibleNavigation = filterAdminNavigation(adminNavigation, new Set([
'platform:customer:list',
'platform:warehouse:list',
'platform:firstleg:inbound:list',
'platform:location:list',
'platform:pallet:list',
'firstleg:fba-pricing:rule:view',
'firstleg:fba-pricing:rate:view',
'platform:express:list',
'platform:counterparty:list',
'platform:download:list',
'platform:user:list',
'platform:role:list',
'platform:permission:list',
]))
const stubs = {
'el-menu': {
props: ['defaultActive', 'collapse'],
@@ -21,7 +37,7 @@ const stubs = {
describe('AdminSidebarMenu', () => {
it('renders the visible phase-one modules and forwards the active route', () => {
const wrapper = mount(AdminSidebarMenu, {
props: { items: adminNavigation, activePath: '/system/users', collapsed: false },
props: { items: visibleNavigation, activePath: '/system/users', collapsed: false },
global: { stubs },
})
@@ -30,17 +46,22 @@ describe('AdminSidebarMenu', () => {
const paths = wrapper.findAll('[data-kind="item"]').map((node) => node.attributes('data-index'))
expect(groupTitles).toContain('客户管理')
expect(groupTitles).toContain('供应商中心')
expect(groupTitles).toContain('系统管理')
expect(groupTitles).not.toContain('财务管理')
expect(paths).not.toContain('/dashboard')
expect(paths).toContain('/orders/first-leg')
expect(paths).toContain('/inbounds')
expect(paths).toContain('/master-data/express-companies')
expect(paths).not.toContain('/orders/first-leg')
expect(paths).toContain('/first-leg-pricing/customer-rules')
expect(paths).toContain('/downloads')
expect(paths).not.toContain('/prototype/reports/overview')
expect(paths).toContain('/system/permissions')
})
it('forwards desktop collapse state to Element Plus', () => {
const wrapper = mount(AdminSidebarMenu, {
props: { items: adminNavigation, activePath: '/', collapsed: true },
props: { items: visibleNavigation, activePath: '/', collapsed: true },
global: { stubs },
})
+1 -1
View File
@@ -74,7 +74,7 @@ describe('admin router access metadata', () => {
expect(resolved.matched.some((record) => record.meta.requiresAuth)).toBe(true)
})
it('keeps visible navigation paths and permissions aligned with routes', () => {
it('keeps every registered navigation path and permission aligned with routes', () => {
for (const item of getNavigationLeaves(adminNavigation)) {
const resolved = router.resolve(item.path)
const pageRoute = resolved.matched.at(-1)
+74 -16
View File
@@ -8,32 +8,65 @@ import {
} from './adminNavigation'
describe('adminNavigation', () => {
it('exposes implemented phase-one and phase-two menus while retaining future prototype nodes as comments', () => {
it('keeps the latest prototype menu skeleton in source order and groups additions under general', () => {
expect(adminNavigation.map((item) => item.title)).toEqual([
'首页数据看板',
'客户管理',
'国内仓',
'头程订单',
'头程计费',
'海外派送',
'服务中心',
'供应商中心',
'货柜管理',
'海外业务',
'海外仓库存',
'财务管理',
'销售管理',
'通用',
'系统管理',
])
expect(adminNavigation[0].children?.map((item) => item.title)).toEqual(['客户列表'])
expect(adminNavigation.find((item) => item.key === 'customers')?.children?.map((item) => item.title)).toEqual([
'客户列表',
'海外仓阶梯费用',
])
expect(adminNavigation.find((item) => item.key === 'domestic-warehouse')?.children?.map((item) => item.title)).toEqual([
'仓库管理',
'入库单',
'入库单列表',
'入库单测量',
'测量数据审核',
'库位管理',
'托盘管理',
])
expect(adminNavigation.find((item) => item.key === 'first-leg-pricing')?.children?.map((item) => item.title)).toEqual([
'客户计费规则',
'船司 FBA 价格',
expect(adminNavigation.find((item) => item.key === 'supplier-center')?.children?.map((item) => item.title)).toEqual([
'供应商列表',
'快递公司',
'往来单位',
])
expect(adminNavigation.find((item) => item.key === 'overseas-inventory')?.children?.map((item) => item.title)).toEqual([
'入库单',
'换标单',
'出库单',
'托盘管理',
'箱号管理',
'产品库',
'退货库存',
'暂扣库存',
])
expect(adminNavigation.find((item) => item.key === 'general')?.children?.map((item) => item.title)).toEqual([
'产品信息',
'费用项目',
'FBA编码地址',
'船期价格表',
'车辆列表',
'仓库管理',
'头程订单',
'头程计费',
'下载中心',
'菜单权限',
])
expect(adminNavigation.find((item) => item.key === 'general')?.children?.map((item) => item.title)).toContain('快递公司')
expect(adminNavigation.find((item) => item.key === 'general')?.children?.map((item) => item.title)).toContain('下载中心')
expect(adminNavigation.find((item) => item.key === 'system')?.children?.map((item) => item.title)).toEqual([
'用户管理',
'角色权限',
'菜单权限',
'租户管理',
'品牌设置',
])
})
@@ -42,9 +75,12 @@ describe('adminNavigation', () => {
const paths = leaves.map((item) => item.path)
const permissions = leaves.flatMap((item) => item.permission ? [item.permission] : [])
expect(paths).not.toContain('/dashboard')
expect(paths).not.toContain('/prototype/finance/profit-report')
expect(paths).not.toContain('/prototype/system-management/brand-settings')
expect(paths).toContain('/dashboard')
expect(paths).toContain('/orders/first-leg')
expect(paths).toContain('/first-leg-pricing/customer-rules')
expect(paths).toContain('/downloads')
expect(paths).toContain('/prototype/finance/profit-report')
expect(paths).toContain('/prototype/system-management/brand-settings')
expect(paths).toContain('/system/permissions')
expect(new Set(paths).size).toBe(paths.length)
expect(new Set(permissions).size).toBe(permissions.length)
@@ -59,11 +95,33 @@ describe('adminNavigation', () => {
expect(paths).toContain('/system/permissions')
expect(paths).not.toContain('/prototype/finance/profit-report')
expect(paths).not.toContain('/customers')
expect(filtered.map((item) => item.title)).toEqual(['通用'])
expect(filtered).not.toBe(adminNavigation)
expect(filtered.find((item) => item.key === 'system')).not.toBe(adminNavigation.find((item) => item.key === 'system'))
expect(filtered[0]).not.toBe(adminNavigation.find((item) => item.key === 'general'))
expect(JSON.stringify(adminNavigation, (key, value) => key === 'icon' ? '[icon]' : value)).toBe(sourceSnapshot)
})
it('keeps hidden prototype nodes out of the live menu while preserving implemented placements', () => {
const filtered = filterAdminNavigation(adminNavigation, new Set([
'platform:firstleg:inbound:list',
'platform:express:list',
'platform:counterparty:list',
'platform:warehouse:list',
]))
const paths = getNavigationLeaves(filtered).map((item) => item.path)
expect(filtered.map((item) => item.title)).toEqual(['国内仓', '供应商中心', '通用'])
expect(paths).toEqual([
'/inbounds',
'/master-data/express-companies',
'/master-data/counterparties',
'/warehouses',
])
expect(paths).not.toContain('/dashboard')
expect(paths).not.toContain('/orders/first-leg')
expect(paths).not.toContain('/prototype/finance/profit-report')
})
it('keeps the merged customer entry for existing review-only roles', () => {
const filtered = filterAdminNavigation(adminNavigation, new Set(['platform:customer:review']))
+45 -104
View File
@@ -6,6 +6,7 @@ import {
CircleDollarSign,
Database,
Download,
FileCheck2,
KeyRound,
Settings,
ShieldCheck,
@@ -22,7 +23,7 @@ export interface AdminNavigationNode {
path?: string
permission?: string
permissionAnyOf?: string[]
/** Set to true to remove a prototype module from the sidebar without deleting its route. */
/** Set to true to remove a registered entry from the sidebar without deleting its route. */
hidden?: boolean
children?: AdminNavigationNode[]
}
@@ -34,8 +35,7 @@ export interface AdminNavigationLeaf extends AdminNavigationNode {
}
export const adminNavigation: AdminNavigationNode[] = [
// 原型菜单暂未接入一期范围;恢复展示时移除对应注释即可。
// { key: 'dashboard', title: '首页数据看板', icon: ClipboardList, path: '/dashboard' },
{ key: 'dashboard', title: '首页数据看板', icon: ClipboardList, path: '/dashboard', hidden: true },
{
key: 'customers',
title: '客户管理',
@@ -43,7 +43,7 @@ export const adminNavigation: AdminNavigationNode[] = [
iconColor: '#52c41a',
children: [
{ key: 'customers-list', title: '客户列表', icon: Building2, path: '/customers', permission: 'platform:customer:list', permissionAnyOf: ['platform:customer:review'] },
// { key: 'warehouse-tier-fee', title: '海外仓阶梯费用', icon: Building2, path: '/prototype/customer-management/warehouse-tier-fee' },
{ key: 'warehouse-tier-fee', title: '海外仓阶梯费用', icon: Building2, path: '/prototype/customer-management/warehouse-tier-fee', hidden: true },
],
},
{
@@ -52,39 +52,18 @@ export const adminNavigation: AdminNavigationNode[] = [
icon: WarehouseIcon,
iconColor: '#52c41a',
children: [
{ key: 'warehouses', title: '仓库管理', icon: WarehouseIcon, path: '/warehouses', permission: 'platform:warehouse:list' },
{ key: 'inbound-list', title: '入库单', icon: ClipboardList, path: '/inbounds', permission: 'platform:firstleg:inbound:list' },
{ key: 'inbound-list', title: '入库单列表', icon: ClipboardList, path: '/inbounds', permission: 'platform:firstleg:inbound:list' },
{ key: 'inbound-dedup', title: '入库单测量', icon: ClipboardList, path: '/prototype/domestic-warehouse/inbound-dedup', hidden: true },
{ key: 'inbound-measure', title: '测量数据审核', icon: FileCheck2, path: '/prototype/domestic-warehouse/inbound-measure', hidden: true },
{ key: 'locations', title: '库位管理', icon: WarehouseIcon, path: '/master-data/locations', permission: 'platform:location:list' },
{ key: 'pallets', title: '托盘管理', icon: WarehouseIcon, path: '/master-data/pallets', permission: 'platform:pallet:list' },
// { key: 'inbound-dedup', title: '入库单测量', icon: ClipboardList, path: '/prototype/domestic-warehouse/inbound-dedup' },
// { key: 'inbound-measure', title: '测量数据审核', icon: FileCheck2, path: '/prototype/domestic-warehouse/inbound-measure' },
// { key: 'inbound-receive', title: '接收审核', icon: FileCheck2, path: '/prototype/domestic-warehouse/inbound-receive' },
// { key: 'overseas-location', title: '库位管理', icon: WarehouseIcon, path: '/prototype/domestic-warehouse/location-management' },
// { key: 'pallet-management', title: '托盘管理', icon: WarehouseIcon, path: '/prototype/domestic-warehouse/pallet-management' },
],
},
{
key: 'first-leg-orders',
title: '头程订单',
icon: ClipboardList,
iconColor: '#1890ff',
path: '/orders/first-leg',
permission: 'platform:order:list',
},
{
key: 'first-leg-pricing',
title: '头程计费',
icon: CircleDollarSign,
iconColor: '#13a8a8',
children: [
{ key: 'fba-customer-rules', title: '客户计费规则', icon: Database, path: '/first-leg-pricing/customer-rules', permission: 'firstleg:fba-pricing:rule:view' },
{ key: 'fba-carrier-rates', title: '船司 FBA 价格', icon: CircleDollarSign, path: '/first-leg-pricing/carrier-rates', permission: 'firstleg:fba-pricing:rate:view' },
],
},
/* {
key: 'overseas-delivery',
title: '海外派送',
icon: Truck,
hidden: true,
children: [
{ key: 'outbound-dispatch', title: '派送单列表', icon: Truck, path: '/prototype/overseas-delivery/dispatch-list' },
{ key: 'outbound-vehicle', title: '排车列表', icon: Truck, path: '/prototype/overseas-delivery/vehicle-scheduling' },
@@ -92,21 +71,11 @@ export const adminNavigation: AdminNavigationNode[] = [
{ key: 'outbound-selfpick', title: '自提单', icon: ClipboardList, path: '/prototype/overseas-delivery/self-pickup' },
],
},
{
key: 'overseas-inventory',
title: '海外仓库存',
icon: WarehouseIcon,
children: [
{ key: 'overseas-stock', title: '库存列表', icon: WarehouseIcon, path: '/prototype/overseas-inventory/stock-list' },
{ key: 'overseas-inbound', title: '海外入库单', icon: ClipboardList, path: '/prototype/overseas-inventory/inbound-orders' },
{ key: 'overseas-outbound', title: '出库单', icon: ClipboardList, path: '/prototype/overseas-inventory/outbound-orders' },
{ key: 'overseas-relabel', title: '换标订单', icon: ClipboardList, path: '/prototype/overseas-inventory/relabel-orders' },
],
},
{
key: 'service-center',
title: '服务中心',
icon: ClipboardList,
hidden: true,
children: [
{ key: 'booking-list', title: '订舱列表', icon: ClipboardList, path: '/prototype/service-center/booking-list' },
{ key: 'truck-list', title: '拖车列表', icon: Truck, path: '/prototype/service-center/truck-list' },
@@ -117,13 +86,16 @@ export const adminNavigation: AdminNavigationNode[] = [
title: '供应商中心',
icon: ContactRound,
children: [
{ key: 'supplier-list', title: '供应商列表', icon: ContactRound, path: '/prototype/supplier-center/supplier-list' },
{ key: 'supplier-list', title: '供应商列表', icon: ContactRound, path: '/prototype/supplier-center/supplier-list', hidden: true },
{ key: 'express-companies', title: '快递公司', icon: Truck, path: '/master-data/express-companies', permission: 'platform:express:list' },
{ key: 'counterparties', title: '往来单位', icon: ContactRound, path: '/master-data/counterparties', permission: 'platform:counterparty:list' },
],
},
{
key: 'container-management',
title: '货柜管理',
icon: WarehouseIcon,
hidden: true,
children: [
{ key: 'container-list', title: '货柜列表', icon: WarehouseIcon, path: '/prototype/container-management/container-list' },
{ key: 'container-manifest', title: '装柜清单', icon: ClipboardList, path: '/prototype/container-management/manifest' },
@@ -134,27 +106,18 @@ export const adminNavigation: AdminNavigationNode[] = [
key: 'overseas-business',
title: '海外业务',
icon: Building2,
hidden: true,
children: [
{ key: 'overseas-users', title: '用户管理', icon: Users, path: '/prototype/overseas-business/users' },
{ key: 'overseas-purchase', title: '采购订单', icon: ClipboardList, path: '/prototype/overseas-business/purchase-orders' },
{ key: 'overseas-truck', title: '本土卡车', icon: Truck, path: '/prototype/overseas-business/local-truck' },
{ key: 'overseas-looseboard', title: '本土散板', icon: ClipboardList, path: '/prototype/overseas-business/local-looseboard' },
],
},
{
key: 'overseas-warehouse-orders',
title: '海外仓下单',
icon: ClipboardList,
children: [
{ key: 'overseas-order-inbound', title: '退货入库', icon: ClipboardList, path: '/prototype/overseas-warehouse-orders/return-inbound' },
{ key: 'overseas-order-relabel', title: '退货换标', icon: ClipboardList, path: '/prototype/overseas-warehouse-orders/return-relabel' },
{ key: 'overseas-order-outbound', title: '退货出库', icon: ClipboardList, path: '/prototype/overseas-warehouse-orders/return-outbound' },
],
},
{
key: 'fba-returns',
title: 'FBA退货',
icon: FileCheck2,
key: 'overseas-inventory',
title: '海外仓库存',
icon: WarehouseIcon,
hidden: true,
children: [
{ key: 'fba-inbound-order', title: '入库单', icon: ClipboardList, path: '/prototype/fba-returns/inbound-orders' },
{ key: 'fba-relabel-order', title: '换标单', icon: ClipboardList, path: '/prototype/fba-returns/relabel-orders' },
@@ -163,12 +126,14 @@ export const adminNavigation: AdminNavigationNode[] = [
{ key: 'fba-carton', title: '箱号管理', icon: ClipboardList, path: '/prototype/fba-returns/carton-management' },
{ key: 'fba-product', title: '产品库', icon: Database, path: '/prototype/fba-returns/product-catalog' },
{ key: 'fba-return-stock', title: '退货库存', icon: WarehouseIcon, path: '/prototype/fba-returns/return-stock' },
{ key: 'overseas-held-stock', title: '暂扣库存', icon: WarehouseIcon, path: '/prototype/overseas-inventory/stock-list' },
],
},
{
key: 'finance',
title: '财务管理',
icon: Database,
icon: CircleDollarSign,
hidden: true,
children: [
{ key: 'customer-arap', title: '客户应收应付', icon: Database, path: '/prototype/finance/customer-arap' },
{ key: 'customer-recon-stmt', title: '客户对账单', icon: FileCheck2, path: '/prototype/finance/customer-reconciliation' },
@@ -179,64 +144,40 @@ export const adminNavigation: AdminNavigationNode[] = [
],
},
{
key: 'vehicle-management',
title: '车辆管理',
icon: Truck,
children: [
{ key: 'vehicle-list', title: '车辆列表', icon: Truck, path: '/prototype/vehicle-management/vehicle-list' },
],
},
{
key: 'reports',
title: '报表中心',
icon: Database,
children: [
{ key: 'report-overview', title: '报表总览', icon: Database, path: '/prototype/reports/overview' },
{ key: 'report-income', title: '收支报表', icon: Database, path: '/prototype/reports/income-expense' },
{ key: 'report-ar-aging', title: '应收账龄分析', icon: Database, path: '/prototype/reports/ar-aging' },
{ key: 'report-cost', title: '费用构成分析', icon: Database, path: '/prototype/reports/cost-composition' },
{ key: 'report-freight', title: '运费报表', icon: Database, path: '/prototype/reports/freight' },
{ key: 'report-business', title: '业务统计报表', icon: Database, path: '/prototype/reports/business-statistics' },
],
},
*/
{
key: 'general',
title: '通用',
icon: Database,
iconColor: '#722ed1',
children: [
// { key: 'general-product', title: '产品信息', icon: Database, path: '/prototype/general/product-information' },
// { key: 'general-fee', title: '费用项目', icon: Database, path: '/prototype/general/fee-items' },
// { key: 'general-fba', title: 'FBA编码地址', icon: Database, path: '/prototype/general/fba-address' },
// { key: 'general-pallet', title: '托盘管理', icon: WarehouseIcon, path: '/prototype/general/pallet-management' },
// { key: 'general-location', title: '库位/货架管理', icon: WarehouseIcon, path: '/prototype/general/location-management' },
{ key: 'express-companies', title: '快递公司', icon: Truck, path: '/master-data/express-companies', permission: 'platform:express:list' },
{ key: 'counterparties', title: '往来单位', icon: ContactRound, path: '/master-data/counterparties', permission: 'platform:counterparty:list' },
{ key: 'download-center', title: '下载中心', icon: Download, path: '/downloads', permission: 'platform:download:list' },
// { key: 'general-voyage', title: '船期价格表', icon: Database, path: '/prototype/general/voyage-price-list' },
],
},
/* {
key: 'sales',
title: '销售管理',
icon: Users,
hidden: true,
children: [
{ key: 'sales-visits', title: '拜访记录', icon: Users, path: '/prototype/sales/visit-records' },
{ key: 'sales-commission', title: '销售提成', icon: Database, path: '/prototype/sales/commission' },
],
},
{
key: 'messages',
title: '消息中心',
icon: ClipboardList,
key: 'general',
title: '通用',
icon: Database,
iconColor: '#722ed1',
children: [
{ key: 'message-management', title: '消息管理', icon: ClipboardList, path: '/prototype/messages/management' },
{ key: 'message-template', title: '模板管理', icon: ClipboardList, path: '/prototype/messages/templates' },
{ key: 'my-messages', title: '我的消息', icon: ClipboardList, path: '/prototype/messages/my-messages' },
// { key: 'general-fba', title: 'FBA编码地址', icon: Database, path: '/prototype/general/fba-address', hidden: true },
// { key: 'general-voyage', title: '船期价格表', icon: Database, path: '/prototype/general/voyage-price-list', hidden: true },
// { key: 'first-leg-orders', title: '头程订单', icon: ClipboardList, path: '/orders/first-leg', permission: 'platform:order:list', hidden: true },
// {
// key: 'first-leg-pricing',
// title: '头程计费',
// icon: CircleDollarSign,
// children: [
// { key: 'fba-customer-rules', title: '客户计费规则', icon: Database, path: '/first-leg-pricing/customer-rules', permission: 'firstleg:fba-pricing:rule:view' },
// ],
// },
{ key: 'general-product', title: '产品信息', icon: Database, path: '/prototype/general/product-information', hidden: false },
{ key: 'general-fee', title: '费用项目', icon: Database, path: '/prototype/general/fee-items', hidden: false },
{ key: 'warehouses', title: '仓库管理', icon: WarehouseIcon, path: '/warehouses', permission: 'platform:warehouse:list' },
{ key: 'fba-carrier-rates', title: '船期价格表', icon: CircleDollarSign, path: '/first-leg-pricing/carrier-rates', permission: 'firstleg:fba-pricing:rate:view' },
{ key: 'vehicle-list', title: '车辆列表', icon: Truck, path: '/prototype/vehicle-management/vehicle-list', hidden: false },
{ key: 'download-center', title: '下载中心', icon: Download, path: '/downloads', permission: 'platform:download:list' },
],
},
*/
{
key: 'system',
title: '系统管理',
@@ -245,9 +186,9 @@ export const adminNavigation: AdminNavigationNode[] = [
children: [
{ key: 'internal-users', title: '用户管理', icon: Users, path: '/system/users', permission: 'platform:user:list' },
{ key: 'roles', title: '角色权限', icon: ShieldCheck, path: '/system/roles', permission: 'platform:role:list' },
{ key: 'tenant-management', title: '租户管理', icon: Building2, path: '/prototype/system-management/tenant-management', hidden: true },
{ key: 'brand-settings', title: '品牌设置', icon: Settings, path: '/prototype/system-management/brand-settings', hidden: true },
{ key: 'permissions', title: '菜单权限', icon: KeyRound, path: '/system/permissions', permission: 'platform:permission:list' },
// { key: 'tenant-management', title: '租户管理', icon: Building2, path: '/prototype/system-management/tenant-management' },
// { key: 'brand-settings', title: '品牌设置', icon: Settings, path: '/prototype/system-management/brand-settings' },
],
},
]
+1 -1
View File
@@ -55,7 +55,7 @@ export const prototypeModuleRoutes: RouteRecordRaw[] = [
['prototype/overseas-delivery/self-pickup', 'outbound-selfpick', '自提单'],
]),
...createRoutes(moduleViews.overseasInventory, [
['prototype/overseas-inventory/stock-list', 'overseas-stock', '库存列表'],
['prototype/overseas-inventory/stock-list', 'overseas-stock', '暂扣库存'],
['prototype/overseas-inventory/inbound-orders', 'overseas-inbound', '海外入库单'],
['prototype/overseas-inventory/outbound-orders', 'overseas-outbound', '出库单'],
['prototype/overseas-inventory/relabel-orders', 'overseas-relabel', '换标订单'],