feat(app): 管理端 Web 基座→暖记品牌迁移 + 日记管理页面
Phase 1 — 品牌替换:
- BRAND_DEFAULTS 回退值改为暖记品牌 (themes.ts)
- 登录页/侧边栏/底部回退文字 → 暖记 (Login, MainLayout)
- index.html title/meta/favicon → 暖记
- localStorage key → nuanji-theme, 默认主题 → warm
- 4 套主题色适配暖记设计系统 (珊瑚 #E07A5F / 蓝 / 深色 / 鼠尾草绿)
- 品牌信息通过系统设置配置,不硬编码
Phase 2 — 清理 HMS 模块:
- 删除 health/ai 页面 (~55+2)、API (~30+9)、组件、stores、hooks
- 重写 Home.tsx 为暖记 Dashboard
- 重写 NotificationPanel/MediaPicker 移除 health 依赖
- 清理 routeConfig 移除所有 health/ai 路由权限
Phase 3 — 暖记管理页面:
- API 层: api/diary/{types,journals,classes,topics,comments,stickers}.ts
- 班级管理: 班级列表+创建+成员查看+班级码复制 (ClassList)
- 日记审核: 日记列表+筛选+详情+老师点评 (JournalList)
- 主题管理: 班级选择+主题卡片+创建+过期标记 (TopicList)
- 贴纸管理: 贴纸包卡片+贴纸详情网格 (StickerPackList)
- 路由注册: /diary/classes, /diary/journals, /diary/topics, /diary/stickers
验证: tsc 0 error, vite build ✓, vitest 226/226 pass
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* 规则:
|
||||
* 1. 每个受保护路由必须在此声明至少一个权限码(TypeScript 强制非空数组)
|
||||
* 2. 子路由(如 /health/patients/:id)通过前缀匹配自动继承父路由权限,无需重复声明
|
||||
* 2. 子路由(如 /diary/classes/:id)通过前缀匹配自动继承父路由权限,无需重复声明
|
||||
* 3. 新增路由必须在此添加对应条目,否则 PrivateRoute 默认 403
|
||||
* 4. 冻结路由标记 frozen: true,自动归入 FROZEN_ROUTES
|
||||
*
|
||||
@@ -37,221 +37,11 @@ const ENTRIES: RoutePermissionEntry[] = [
|
||||
// 动态路由 catch-all: /plugins/:pluginId/:entityName 等
|
||||
{ path: "/plugins", permissions: ["plugin.list", "plugin.admin"] },
|
||||
|
||||
// ===== 健康管理 — 患者与医生 =====
|
||||
{
|
||||
path: "/health/patients",
|
||||
permissions: ["health.patient.list", "health.patient.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/tags",
|
||||
permissions: ["health.patient.list", "health.patient.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/doctors",
|
||||
permissions: ["health.doctor.list", "health.doctor.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/appointments",
|
||||
permissions: ["health.appointment.list", "health.appointment.manage"],
|
||||
},
|
||||
|
||||
// ===== 健康管理 — 随访与咨询 =====
|
||||
{
|
||||
path: "/health/follow-up-tasks",
|
||||
permissions: ["health.follow-up.list", "health.follow-up.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/follow-up-records",
|
||||
permissions: ["health.follow-up.list", "health.follow-up.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/follow-up-templates",
|
||||
permissions: [
|
||||
"health.follow-up-templates.list",
|
||||
"health.follow-up-templates.manage",
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/health/consultations",
|
||||
permissions: ["health.consultation.list", "health.consultation.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/action-inbox",
|
||||
permissions: ["health.action-inbox.list", "health.action-inbox.manage"],
|
||||
},
|
||||
|
||||
// ===== 健康管理 — 告警与设备 =====
|
||||
{
|
||||
path: "/health/alerts",
|
||||
permissions: ["health.alerts.list", "health.alerts.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/alert-dashboard",
|
||||
permissions: ["health.alerts.list", "health.alerts.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/alert-rules",
|
||||
permissions: ["health.alert-rules.list", "health.alert-rules.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/devices",
|
||||
permissions: ["health.devices.list", "health.devices.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/realtime-monitor",
|
||||
permissions: [
|
||||
"health.device-readings.list",
|
||||
"health.device-readings.manage",
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/health/ble-gateways",
|
||||
permissions: ["health.ble-gateways.list", "health.ble-gateways.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/critical-value-thresholds",
|
||||
permissions: [
|
||||
"health.critical-value-thresholds.list",
|
||||
"health.critical-value-thresholds.manage",
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/health/daily-monitoring",
|
||||
permissions: [
|
||||
"health.daily-monitoring.list",
|
||||
"health.daily-monitoring.manage",
|
||||
],
|
||||
},
|
||||
|
||||
// ===== 健康管理 — 诊断与知情同意(冻结,当前版本不启用) =====
|
||||
{
|
||||
path: "/health/diagnoses",
|
||||
permissions: ["health.health-data.list", "health.health-data.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
{
|
||||
path: "/health/consents",
|
||||
permissions: ["health.consent.list", "health.consent.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
|
||||
// ===== 健康管理 — AI 模块 =====
|
||||
{
|
||||
path: "/health/ai-prompts",
|
||||
permissions: ["ai.prompt.list", "ai.prompt.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/ai-analysis",
|
||||
permissions: ["ai.analysis.list", "ai.analysis.manage"],
|
||||
},
|
||||
{ path: "/health/ai-usage", permissions: ["ai.usage.list"] },
|
||||
{
|
||||
path: "/health/ai-config",
|
||||
permissions: ["ai.config.read", "ai.config.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/ai-knowledge",
|
||||
permissions: ["ai.knowledge.list", "ai.knowledge.manage"],
|
||||
},
|
||||
|
||||
// ===== 健康管理 — 积分商城 =====
|
||||
{
|
||||
path: "/health/points-rules",
|
||||
permissions: ["health.points.list", "health.points.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/points-products",
|
||||
permissions: ["health.points.list", "health.points.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/points-orders",
|
||||
permissions: ["health.points.list", "health.points.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/offline-events",
|
||||
permissions: ["health.points.list", "health.points.manage"],
|
||||
},
|
||||
|
||||
// ===== 健康管理 — 内容管理 =====
|
||||
{
|
||||
path: "/health/articles",
|
||||
permissions: ["health.articles.list", "health.articles.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/article-categories",
|
||||
permissions: ["health.articles.list", "health.articles.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/article-tags",
|
||||
permissions: ["health.articles.list", "health.articles.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/banners",
|
||||
permissions: ["health.banners.list", "health.banners.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/media-library",
|
||||
permissions: ["health.media.list", "health.media.manage"],
|
||||
},
|
||||
|
||||
// ===== 健康管理 — 其他 =====
|
||||
{
|
||||
path: "/health/oauth-clients",
|
||||
permissions: ["health.oauth.list", "health.oauth.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/statistics",
|
||||
permissions: ["health.health-data.list", "health.dashboard.manage"],
|
||||
},
|
||||
{
|
||||
path: "/health/medication-records",
|
||||
permissions: ["health.medication-records.list", "health.medication-records.manage"],
|
||||
},
|
||||
|
||||
// ===== 冻结路由 =====
|
||||
{
|
||||
path: "/health/care-plans",
|
||||
permissions: ["health.care-plan.list", "health.care-plan.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
{
|
||||
path: "/health/shifts",
|
||||
permissions: ["health.shifts.list", "health.shifts.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
{
|
||||
path: "/health/family-proxy",
|
||||
permissions: ["health.family-proxy.list", "health.family-proxy.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
{
|
||||
path: "/health/medications",
|
||||
permissions: [
|
||||
"health.medication-records.list",
|
||||
"health.medication-records.manage",
|
||||
],
|
||||
frozen: true,
|
||||
},
|
||||
{
|
||||
path: "/health/dialysis",
|
||||
permissions: ["health.dialysis.list", "health.dialysis.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
{
|
||||
path: "/health/dialysis-prescriptions",
|
||||
permissions: ["health.dialysis-prescription.list", "health.dialysis-prescription.manage"],
|
||||
frozen: true,
|
||||
},
|
||||
{
|
||||
path: "/health/schedules",
|
||||
permissions: ["health.appointment.list", "health.appointment.manage"],
|
||||
},
|
||||
|
||||
// ===== AI 聊天 =====
|
||||
{
|
||||
path: "/ai/chat",
|
||||
permissions: ["ai.chat.session.list", "ai.chat.session.manage"],
|
||||
},
|
||||
// ===== 暖记日记模块 =====
|
||||
{ path: "/diary/classes", permissions: ["diary.class.manage", "diary.journal.read"] },
|
||||
{ path: "/diary/journals", permissions: ["diary.journal.read", "diary.journal.manage"] },
|
||||
{ path: "/diary/topics", permissions: ["diary.topic.assign", "diary.journal.read"] },
|
||||
{ path: "/diary/stickers", permissions: ["diary.journal.read"] },
|
||||
];
|
||||
|
||||
/** 活跃路由的权限映射 — 自动从配置生成,供 PrivateRoute 使用 */
|
||||
@@ -282,13 +72,11 @@ if (import.meta.env.DEV) {
|
||||
* 新增详情页 Tab 时必须在此声明,否则 Tab 默认不可见(安全默认)。
|
||||
*/
|
||||
const TAB_PERM_ENTRIES: Array<{ key: string; permission?: string }> = [
|
||||
// 患者详情 /health/patients/:id
|
||||
{ key: "patient#info", permission: undefined },
|
||||
{ key: "patient#family", permission: "health.patient.manage" },
|
||||
{ key: "patient#health", permission: "health.health-data.list" },
|
||||
{ key: "patient#followup", permission: "health.follow-up.list" },
|
||||
{ key: "patient#points", permission: "health.points.list" },
|
||||
{ key: "patient#ai", permission: "ai.analysis.list" },
|
||||
// ===== 暖记日记模块 Tab 权限 =====
|
||||
{ key: "class#members", permission: "diary.class.manage" },
|
||||
{ key: "class#topics", permission: "diary.topic.assign" },
|
||||
{ key: "journal#detail", permission: "diary.journal.read" },
|
||||
{ key: "journal#comments", permission: "diary.comment.write" },
|
||||
];
|
||||
|
||||
export const TAB_PERMISSIONS: Record<string, string | undefined> = Object.fromEntries(
|
||||
@@ -298,7 +86,7 @@ export const TAB_PERMISSIONS: Record<string, string | undefined> = Object.fromEn
|
||||
/**
|
||||
* DEV 模式路由覆盖率校验。
|
||||
* 在 App.tsx 挂载后调用,检查所有实际路由是否都有权限声明。
|
||||
* 忽略带参数的子路由(如 /health/patients/:id),它们通过前缀匹配继承权限。
|
||||
* 忽略带参数的子路由(如 /diary/classes/:id),它们通过前缀匹配继承权限。
|
||||
*/
|
||||
export function validateRouteCoverage(registeredPaths: string[]): void {
|
||||
if (!import.meta.env.DEV) return;
|
||||
|
||||
Reference in New Issue
Block a user