From 41515e5becdebd56491c6b5ffc9f8976a050eab0 Mon Sep 17 00:00:00 2001 From: iven Date: Fri, 15 May 2026 19:27:10 +0800 Subject: [PATCH] =?UTF-8?q?refactor(web):=20=E6=B6=88=E9=99=A4=E4=BE=A7?= =?UTF-8?q?=E8=BE=B9=E6=A0=8F=E7=A1=AC=E7=BC=96=E7=A0=81=20=E2=80=94=20ico?= =?UTF-8?q?nMap=20=E6=8A=BD=E7=A6=BB=20+=20routeTitleFallback=20=E7=B2=BE?= =?UTF-8?q?=E7=AE=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - iconMap 抽离为 utils/iconRegistry.tsx(单一真相源),补齐 10 个后端 seed 使用但前端缺失的图标 - MainLayout import 从 28 个图标减少到 6 个(仅保留布局专用图标) - routeTitleFallback 从 26 条精简到 10 条(仅保留动态参数路由 + 无后端菜单的静态路由) - 后端菜单已覆盖的 16 条标题映射移除(由 getTitleFromMenus 从后端数据获取) - wiki 关键数字更新:迁移 146、权限码 132 --- apps/web/src/layouts/MainLayout.tsx | 100 +++----------------------- apps/web/src/utils/iconRegistry.tsx | 107 ++++++++++++++++++++++++++++ wiki/index.md | 4 +- 3 files changed, 119 insertions(+), 92 deletions(-) create mode 100644 apps/web/src/utils/iconRegistry.tsx diff --git a/apps/web/src/layouts/MainLayout.tsx b/apps/web/src/layouts/MainLayout.tsx index ba0f478..d0f7a18 100644 --- a/apps/web/src/layouts/MainLayout.tsx +++ b/apps/web/src/layouts/MainLayout.tsx @@ -1,41 +1,12 @@ import { useCallback, useState, memo, useEffect, useMemo } from 'react'; import { Layout, Avatar, Space, Dropdown, Tooltip, Spin, theme } from 'antd'; import { - HomeOutlined, - UserOutlined, - SafetyOutlined, - ApartmentOutlined, - SettingOutlined, MenuFoldOutlined, MenuUnfoldOutlined, - PartitionOutlined, LogoutOutlined, - MessageOutlined, SearchOutlined, AppstoreOutlined, - TeamOutlined, - TableOutlined, - TagsOutlined, RightOutlined, - HeartOutlined, - CalendarOutlined, - PhoneOutlined, - CommentOutlined, - MedicineBoxOutlined, - TrophyOutlined, - ShopOutlined, - FileTextOutlined, - DashboardOutlined, - RobotOutlined, - HistoryOutlined, - BarChartOutlined, - AlertOutlined, - BellOutlined, - ControlOutlined, - InboxOutlined, - ApiOutlined, - ReadOutlined, - ExperimentOutlined, } from '@ant-design/icons'; import { useNavigate, useLocation } from 'react-router-dom'; import { useAppStore } from '../stores/app'; @@ -43,6 +14,7 @@ import { useAuthStore } from '../stores/auth'; import { usePluginStore } from '../stores/plugin'; import type { PluginMenuGroup } from '../stores/plugin'; import { getMenusForUser, type MenuInfo } from '../api/menus'; +import { getIcon } from '../utils/iconRegistry'; import NotificationPanel from '../components/NotificationPanel'; import ThemeSwitcher from '../components/ThemeSwitcher'; @@ -54,74 +26,22 @@ interface MenuItem { label: string; } -// 完整图标映射表 -const iconMap: Record = { - HomeOutlined: , - UserOutlined: , - SafetyOutlined: , - ApartmentOutlined: , - SettingOutlined: , - PartitionOutlined: , - MessageOutlined: , - AppstoreOutlined: , - TeamOutlined: , - TableOutlined: , - TagsOutlined: , - HeartOutlined: , - CalendarOutlined: , - PhoneOutlined: , - CommentOutlined: , - MedicineBoxOutlined: , - TrophyOutlined: , - ShopOutlined: , - FileTextOutlined: , - DashboardOutlined: , - RobotOutlined: , - HistoryOutlined: , - BarChartOutlined: , - AlertOutlined: , - BellOutlined: , - ControlOutlined: , - InboxOutlined: , - ApiOutlined: , - ReadOutlined: , - ExperimentOutlined: , -}; - -function getIcon(name?: string): React.ReactNode { - if (!name) return ; - return iconMap[name] || ; -} - -// 路由标题 fallback(给动态参数路由用) +// 路由标题 fallback — 仅保留后端菜单无法覆盖的路由 +// 1. 动态参数路由(:id/:id/edit)— 菜单表不会存储这些路径 +// 2. 无后端菜单记录的静态页面路由 const routeTitleFallback: Record = { + // 动态参数路由 '/health/patients/:id': '患者详情', - '/health/follow-up-records': '随访记录', '/health/consultations/:id': '咨询详情', - '/health/points-rules': '积分规则管理', - '/health/offline-events': '线下活动管理', - '/health/articles': '内容管理', '/health/articles/new': '新建文章', '/health/articles/:id/edit': '编辑文章', + '/health/care-plans/:id': '护理计划详情', + '/health/shifts/:id': '班次详情', + '/health/ble-gateways/:id': '网关详情', + // 无后端菜单的静态路由 + '/health/follow-up-records': '随访记录', '/health/article-categories': '分类管理', '/health/article-tags': '标签管理', - '/health/alerts': '告警列表', - '/health/alert-dashboard': '告警仪表盘', - '/health/alert-rules': '告警规则', - '/health/devices': '设备管理', - '/health/dialysis': '透析管理', - '/health/follow-up-templates': '随访模板管理', - '/health/care-plans': '护理计划', - '/health/care-plans/:id': '护理计划详情', - '/health/shifts': '班次管理', - '/health/shifts/:id': '班次详情', - '/health/medications': '药物记录', - '/health/ble-gateways': 'BLE 网关管理', - '/health/ble-gateways/:id': '网关详情', - '/health/critical-value-thresholds': '危急值阈值', - '/health/diagnoses': '诊断记录', - '/health/family-proxy': '家庭健康代理', - '/health/consents': '知情同意管理', }; function getTitleFromMenus(path: string, menus: MenuInfo[]): string | undefined { diff --git a/apps/web/src/utils/iconRegistry.tsx b/apps/web/src/utils/iconRegistry.tsx new file mode 100644 index 0000000..3de6490 --- /dev/null +++ b/apps/web/src/utils/iconRegistry.tsx @@ -0,0 +1,107 @@ +/** + * 图标注册表 — 菜单图标名称 → React 组件的单一真相源 + * + * 后端 menus.icon 字段存储图标名称字符串(如 "HomeOutlined"), + * 前端通过此注册表将其转换为对应的 Ant Design 图标组件。 + * + * 新增后端 seed 图标时必须同步在此添加映射,否则侧边栏回退为 AppstoreOutlined。 + */ + +import { + HomeOutlined, + UserOutlined, + SafetyOutlined, + ApartmentOutlined, + SettingOutlined, + PartitionOutlined, + MessageOutlined, + AppstoreOutlined, + TeamOutlined, + TableOutlined, + TagsOutlined, + HeartOutlined, + CalendarOutlined, + PhoneOutlined, + CommentOutlined, + MedicineBoxOutlined, + TrophyOutlined, + ShopOutlined, + FileTextOutlined, + DashboardOutlined, + RobotOutlined, + HistoryOutlined, + BarChartOutlined, + AlertOutlined, + BellOutlined, + ControlOutlined, + InboxOutlined, + ApiOutlined, + ReadOutlined, + ExperimentOutlined, + // 以下为后端 seed 使用但原 iconMap 缺失的图标 + AuditOutlined, + ClockCircleOutlined, + FileSearchOutlined, + FormOutlined, + MonitorOutlined, + PictureOutlined, + SafetyCertificateOutlined, + SolutionOutlined, + SwapOutlined, + WifiOutlined, +} from '@ant-design/icons'; +import type { ReactNode } from 'react'; + +export const iconRegistry: Record = { + // 基础模块 + HomeOutlined: , + UserOutlined: , + SafetyOutlined: , + ApartmentOutlined: , + SettingOutlined: , + PartitionOutlined: , + MessageOutlined: , + AppstoreOutlined: , + TeamOutlined: , + TableOutlined: , + TagsOutlined: , + SearchOutlined: , // 搜索无专属侧边栏图标 + + // 健康模块 + HeartOutlined: , + CalendarOutlined: , + PhoneOutlined: , + CommentOutlined: , + MedicineBoxOutlined: , + TrophyOutlined: , + ShopOutlined: , + FileTextOutlined: , + DashboardOutlined: , + RobotOutlined: , + HistoryOutlined: , + BarChartOutlined: , + AlertOutlined: , + BellOutlined: , + ControlOutlined: , + InboxOutlined: , + ApiOutlined: , + ReadOutlined: , + ExperimentOutlined: , + + // 健康模块(补充原缺失) + AuditOutlined: , + ClockCircleOutlined: , + FileSearchOutlined: , + FormOutlined: , + MonitorOutlined: , + PictureOutlined: , + SafetyCertificateOutlined: , + SolutionOutlined: , + SwapOutlined: , + WifiOutlined: , +}; + +export function getIcon(name?: string): ReactNode { + if (!name) return ; + return iconRegistry[name] || ; +} diff --git a/wiki/index.md b/wiki/index.md index 4d46786..7ee9801 100644 --- a/wiki/index.md +++ b/wiki/index.md @@ -11,7 +11,7 @@ | Rust crate | 17 个(erp-core + 5 基础业务 + erp-health + erp-ai + erp-dialysis + erp-plugin + 7 插件/原型) | | Rust 源文件 | **649 个** | | 数据库表 | 30 基础表 + 49 健康业务表 + 9 AI 表 + 3 媒体库/轮播图表 | -| 数据库迁移 | **145 个**(最新 m20260513_000145) | +| 数据库迁移 | **146 个**(最新 m20260515_000146) | | 后端路由 | 260+ 个(11 公开 + 14 FHIR + 2 网关 + ~240 受保护) | | 核心模块 | 5 基础 (auth/config/workflow/message/plugin) + 3 业务 (health + ai + dialysis) | | erp-health 实体 | **57 个** Entity(31 handler / 36 service / 21 DTO,189 文件) | @@ -21,7 +21,7 @@ | 前端单元测试 | 88 个测试文件(472 Web 断言 + 39 MP 断言)+ 13 E2E spec(124 断言) | | 后端测试 | **943 个函数**(762 同步 + 181 异步),79 个文件含内联测试 | | 事件系统 | 31 事件类型(health 模块内)/ 23 幂等消费者 / Outbox + LISTEN/NOTIFY | -| 权限码 | **128 个**(health 28 + auth 25 + ai 7 + workflow 8 + dialysis 5 + plugin 2 + Copilot + 媒体库) | +| 权限码 | **132 个**(health 59 + auth 17 + ai 9 + workflow 8 + dialysis 6 + plugin 2 + config 13 + message 5 + Copilot 5) | | 生产 unwrap | **24 处**(从 514 降至 24),全为安全解包 | | utoipa 注解 | 88 个文件含注解 | | Clippy | **全 workspace 0 警告**(2026-05-07 清零) |