diff --git a/admin/src/layout.tsx b/admin/src/layout.tsx index 23bec33..4908346 100644 --- a/admin/src/layout.tsx +++ b/admin/src/layout.tsx @@ -13,6 +13,11 @@ import { IconUser, IconMenuFold, IconMenuUnfold, + IconIdcard, + IconCompass, + IconRobot, + IconScan, + IconUserGroup, } from '@arco-design/web-react/icon'; import { useSelector } from 'react-redux'; import qs from 'query-string'; @@ -37,6 +42,18 @@ function getIconFromKey(key) { switch (key) { case 'dashboard': return ; + case 'card': + return ; + case 'crm': + return ; + case 'ai': + return ; + case 'nfc': + return ; + case 'team': + return ; + case 'settings-biz': + return ; case 'list': return ; case 'form': diff --git a/admin/src/routes.ts b/admin/src/routes.ts index 0ba4b4b..d3d8072 100644 --- a/admin/src/routes.ts +++ b/admin/src/routes.ts @@ -92,6 +92,7 @@ export const routes: IRoute[] = [ { name: 'menu.visualization', key: 'visualization', + ignore: true, children: [ { name: 'menu.visualization.dataAnalysis', @@ -120,6 +121,7 @@ export const routes: IRoute[] = [ { name: 'menu.list', key: 'list', + ignore: true, children: [ { name: 'menu.list.searchTable', @@ -134,6 +136,7 @@ export const routes: IRoute[] = [ { name: 'menu.form', key: 'form', + ignore: true, children: [ { name: 'menu.form.group', @@ -154,6 +157,7 @@ export const routes: IRoute[] = [ { name: 'menu.profile', key: 'profile', + ignore: true, children: [ { name: 'menu.profile.basic', @@ -165,6 +169,7 @@ export const routes: IRoute[] = [ { name: 'menu.result', key: 'result', + ignore: true, children: [ { name: 'menu.result.success', @@ -181,6 +186,7 @@ export const routes: IRoute[] = [ { name: 'menu.exception', key: 'exception', + ignore: true, children: [ { name: 'menu.exception.403', diff --git a/admin/tests/routes-menu.test.ts b/admin/tests/routes-menu.test.ts new file mode 100644 index 0000000..0adb1c8 --- /dev/null +++ b/admin/tests/routes-menu.test.ts @@ -0,0 +1,70 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { routes } from '../src/routes.ts'; + +const adminRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const layoutPath = path.join(adminRoot, 'src/layout.tsx'); + +const CORE_BIZ_MODULES = [ + 'dashboard', + 'card', + 'crm', + 'ai', + 'nfc', + 'team', + 'settings-biz', + 'user', +]; + +const UNRELATED_DEMO_MODULES = [ + 'visualization', + 'list', + 'form', + 'profile', + 'result', + 'exception', +]; + +test('1. 核心出海业务菜单必须保留在侧边栏正常展示 (ignore !== true)', () => { + for (const key of CORE_BIZ_MODULES) { + const route = routes.find((item) => item.key === key); + assert.ok(route, `routes.ts 必须存在核心业务模块: ${key}`); + assert.notEqual( + route.ignore, + true, + `核心业务模块 ${key} 不应被 ignore,必须展示在菜单中` + ); + } +}); + +test('2. 与出海业务无关的模板演示 Demo 菜单必须配置 ignore: true 进行隐藏', () => { + for (const key of UNRELATED_DEMO_MODULES) { + const route = routes.find((item) => item.key === key); + if (route) { + assert.equal( + route.ignore, + true, + `与需求无关的模板模块 ${key} 必须配置 ignore: true 隐藏` + ); + } + } +}); + +test('3. layout.tsx 必须为核心业务模块配置对应的 Arco 矢量图标', () => { + assert.ok(fs.existsSync(layoutPath), '必须存在 layout.tsx'); + const content = fs.readFileSync(layoutPath, 'utf-8'); + + // 必须映射业务模块图标 + assert.ok(content.includes("'card'"), "layout.tsx 必须为 'card' 模块配置图标"); + assert.ok(content.includes("'crm'"), "layout.tsx 必须为 'crm' 模块配置图标"); + assert.ok(content.includes("'ai'"), "layout.tsx 必须为 'ai' 模块配置图标"); + assert.ok(content.includes("'nfc'"), "layout.tsx 必须为 'nfc' 模块配置图标"); + assert.ok(content.includes("'team'"), "layout.tsx 必须为 'team' 模块配置图标"); + assert.ok( + content.includes("'settings-biz'"), + "layout.tsx 必须为 'settings-biz' 模块配置图标" + ); +});