fix: 系统性预防角色测试高频问题(5 方案落地)
P0 — 默认拒绝 + 强制守卫: - 创建 routeConfig.ts 作为前端路由权限的单一真相源 - TypeScript 强制每个路由声明非空权限数组,不可能遗漏 - 自动生成 ROUTE_PERMISSIONS 和 FROZEN_ROUTES - 修正 3 个前端权限码不匹配后端 P0 — CI 权限扫描: - 新增 tools/check_permissions.py 校验脚本 - 发现并修复 tenant.manage 未注册问题 P1 — 聚合接口容错: - erp-core 新增 safe_aggregate 工具函数 - 仪表盘统计 handler 重构 P1 — 状态机一致性自检: - validation.rs 新增 3 个自检测试 fix: lint-staged eslint Windows 兼容性
This commit is contained in:
@@ -8,6 +8,7 @@ import { ErrorBoundary } from './components/ErrorBoundary';
|
||||
import { useAuthStore } from './stores/auth';
|
||||
import { useAppStore } from './stores/app';
|
||||
import type { ThemeName } from './stores/app';
|
||||
import { ROUTE_PERMISSIONS, FROZEN_ROUTES } from './routeConfig';
|
||||
|
||||
const Home = lazy(() => import('./pages/Home'));
|
||||
const Users = lazy(() => import('./pages/Users'));
|
||||
@@ -71,15 +72,6 @@ const ArticleEditor = lazy(() => import('./pages/health/ArticleEditor'));
|
||||
const ArticleCategoryManage = lazy(() => import('./pages/health/ArticleCategoryManage'));
|
||||
const ArticleTagManage = lazy(() => import('./pages/health/ArticleTagManage'));
|
||||
|
||||
const FROZEN_ROUTES = [
|
||||
'/health/care-plans',
|
||||
'/health/shifts',
|
||||
'/health/family-proxy',
|
||||
'/health/medications',
|
||||
'/health/dialysis',
|
||||
'/health/schedules',
|
||||
];
|
||||
|
||||
function FrozenRoute() {
|
||||
return <Result status="info" title="功能暂未开放" subTitle="该功能正在优化中,敬请期待" />;
|
||||
}
|
||||
@@ -98,49 +90,6 @@ function ForbiddenPage() {
|
||||
);
|
||||
}
|
||||
|
||||
const ROUTE_PERMISSIONS: Record<string, string[]> = {
|
||||
'/users': ['user.list', 'user.manage'],
|
||||
'/roles': ['role.list', 'role.manage'],
|
||||
'/organizations': ['organization.list', 'organization.manage'],
|
||||
'/workflow': ['workflow.list', 'workflow.read'],
|
||||
'/messages': ['message.list'],
|
||||
'/settings': ['config.settings.list', 'config.settings.manage'],
|
||||
'/plugins/admin': ['plugin.list', 'plugin.manage'],
|
||||
'/plugins/market': ['plugin.list', 'plugin.manage'],
|
||||
'/health/patients': ['health.patient.list', 'health.patient.manage'],
|
||||
'/health/doctors': ['health.doctor.list', 'health.doctor.manage'],
|
||||
'/health/appointments': ['health.appointment.list', 'health.appointment.manage'],
|
||||
'/health/follow-up-tasks': ['health.follow-up.list', 'health.follow-up.manage'],
|
||||
'/health/follow-up-records': ['health.follow-up.list', 'health.follow-up.manage'],
|
||||
'/health/consultations': ['health.consultation.list', 'health.consultation.manage'],
|
||||
'/health/action-inbox': ['health.action-inbox.list', 'health.action-inbox.manage'],
|
||||
'/health/follow-up-templates': ['health.follow-up-templates.list', 'health.follow-up-templates.manage'],
|
||||
'/health/diagnoses': ['health.health-data.list', 'health.health-data.manage'],
|
||||
'/health/consents': ['health.consent.list', 'health.consent.manage'],
|
||||
'/health/realtime-monitor': ['health.device-readings.list', 'health.device-readings.manage'],
|
||||
'/health/alert-dashboard': ['health.alerts.list', 'health.alerts.manage'],
|
||||
'/health/alerts': ['health.alerts.list', 'health.alerts.manage'],
|
||||
'/health/devices': ['health.devices.list', 'health.devices.manage'],
|
||||
'/health/ble-gateways': ['health.ble-gateways.list', 'health.ble-gateways.manage'],
|
||||
'/health/critical-value-thresholds': ['health.critical-value-thresholds.list', 'health.critical-value-thresholds.manage'],
|
||||
'/health/articles': ['health.articles.list', 'health.articles.manage'],
|
||||
'/health/article-categories': ['health.articles.list', 'health.articles.manage'],
|
||||
'/health/article-tags': ['health.articles.list', 'health.articles.manage'],
|
||||
'/health/points-rules': ['health.points.list', 'health.points.manage'],
|
||||
'/health/points-products': ['health.points.list', 'health.points.manage'],
|
||||
'/health/points-orders': ['health.points.list', 'health.points.manage'],
|
||||
'/health/offline-events': ['health.points.list', 'health.points.manage'],
|
||||
'/health/ai-prompts': ['ai.prompt.list', 'ai.prompt.manage'],
|
||||
'/health/ai-analysis': ['ai.analysis.list', 'ai.analysis.manage'],
|
||||
'/health/ai-usage': ['ai.usage.list'],
|
||||
'/health/oauth-clients': ['health.oauth.list', 'health.oauth.manage'],
|
||||
'/health/statistics': ['health.health-data.list', 'health.dashboard.manage'],
|
||||
'/health/tags': ['health.patient.list', 'health.patient.manage'],
|
||||
'/health/daily-monitoring': ['health.device-readings.list', 'health.device-readings.manage'],
|
||||
'/health/alert-rules': ['health.alert-rules.list', 'health.alert-rules.manage'],
|
||||
'/health/medication-records': ['health.medication-records.manage'],
|
||||
};
|
||||
|
||||
function PrivateRoute({ children }: { children: React.ReactNode }) {
|
||||
const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
|
||||
const permissions = useAuthStore((s) => s.permissions);
|
||||
|
||||
Reference in New Issue
Block a user