fix: 修复角色测试发现的 5 个共性问题
- 修复前端路由守卫前缀碰撞(/health/articles 匹配 /health/article-categories) - 补全 6 条缺失路由权限映射(appointments/follow-up-records/article-categories/article-tags/plugins/market) - 修复 critical-alerts API 500(escalation_level 字段 INT2/i16 与 Entity i32 类型不匹配) - 新增迁移 000128:告警状态修正 + 菜单权限码补全 + 非admin角色移除基础模块权限
This commit is contained in:
@@ -106,9 +106,12 @@ const ROUTE_PERMISSIONS: Record<string, string[]> = {
|
||||
'/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'],
|
||||
@@ -121,6 +124,8 @@ const ROUTE_PERMISSIONS: Record<string, string[]> = {
|
||||
'/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'],
|
||||
@@ -153,13 +158,14 @@ function PrivateRoute({ children }: { children: React.ReactNode }) {
|
||||
// 首页/工作台始终放行
|
||||
if (path === '/' || path === '') return <>{children}</>;
|
||||
|
||||
const matchedPrefix = Object.keys(ROUTE_PERMISSIONS).find((prefix) => path.startsWith(prefix));
|
||||
const matchedPrefix = Object.keys(ROUTE_PERMISSIONS).find(
|
||||
(prefix) => path === prefix || path.startsWith(prefix + '/'),
|
||||
);
|
||||
if (matchedPrefix) {
|
||||
const required = ROUTE_PERMISSIONS[matchedPrefix];
|
||||
const hasAccess = required.some((r) => permissions.includes(r));
|
||||
if (!hasAccess) return <ForbiddenPage />;
|
||||
} else {
|
||||
// 未在 ROUTE_PERMISSIONS 中注册的路由,默认拒绝
|
||||
return <ForbiddenPage />;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ pub struct Model {
|
||||
pub acknowledged_by: Option<Uuid>,
|
||||
#[sea_orm(skip_serializing_if = "Option::is_none")]
|
||||
pub acknowledged_at: Option<DateTimeUtc>,
|
||||
pub escalation_level: i32,
|
||||
pub escalation_level: i16,
|
||||
pub created_at: DateTimeUtc,
|
||||
pub updated_at: DateTimeUtc,
|
||||
#[sea_orm(skip_serializing_if = "Option::is_none")]
|
||||
|
||||
@@ -127,6 +127,7 @@ mod m20260505_000124_freeze_deferred_menus;
|
||||
mod m20260506_000125_restructure_menus_and_roles;
|
||||
mod m20260506_000126_fix_role_permissions_cleanup;
|
||||
mod m20260507_000127_fix_doctor_extra_permissions;
|
||||
mod m20260507_000128_fix_alert_status_and_menu_perms;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
@@ -261,6 +262,7 @@ impl MigratorTrait for Migrator {
|
||||
Box::new(m20260506_000125_restructure_menus_and_roles::Migration),
|
||||
Box::new(m20260506_000126_fix_role_permissions_cleanup::Migration),
|
||||
Box::new(m20260507_000127_fix_doctor_extra_permissions::Migration),
|
||||
Box::new(m20260507_000128_fix_alert_status_and_menu_perms::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
//! 修复告警状态 + 菜单权限码 + 角色权限清理
|
||||
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
let db = manager.get_connection();
|
||||
|
||||
// === 1. 修复告警 seed 数据状态:active → pending ===
|
||||
// alerts 表中 status='active' 的记录统一改为 'pending'
|
||||
db.execute_unprepared(
|
||||
"UPDATE alerts SET status = 'pending', updated_at = NOW() \
|
||||
WHERE status = 'active' AND deleted_at IS NULL",
|
||||
)
|
||||
.await?;
|
||||
|
||||
// critical_alert 表同理
|
||||
db.execute_unprepared(
|
||||
"UPDATE critical_alert SET status = 'pending', updated_at = NOW() \
|
||||
WHERE status = 'active' AND deleted_at IS NULL",
|
||||
)
|
||||
.await?;
|
||||
|
||||
// === 2. 为缺失 permission 的菜单补上权限码 ===
|
||||
|
||||
// m20260505_000116 创建的菜单缺少 permission 字段
|
||||
let menu_perms: &[(&str, &str)] = &[
|
||||
("/health/care-plans", "health.care-plan.list"),
|
||||
("/health/shifts", "health.shifts.list"),
|
||||
("/health/medications", "health.medication-records.manage"),
|
||||
("/health/ble-gateways", "health.ble-gateways.list"),
|
||||
("/health/critical-value-thresholds", "health.critical-value-thresholds.list"),
|
||||
("/health/diagnoses", "health.health-data.list"),
|
||||
("/health/family-proxy", "health.patient.list"),
|
||||
("/health/consents", "health.consent.list"),
|
||||
("/health/realtime-monitor", "health.device-readings.list"),
|
||||
("/health/oauth-clients", "health.oauth.list"),
|
||||
("/health/follow-up-templates", "health.follow-up-templates.list"),
|
||||
];
|
||||
|
||||
for &(path, perm) in menu_perms {
|
||||
db.execute_unprepared(&format!(
|
||||
"UPDATE menus SET permission = '{perm}', updated_at = NOW() \
|
||||
WHERE path = '{path}' AND deleted_at IS NULL AND (permission IS NULL OR permission = '')"
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
|
||||
// === 3. 清理非 admin 角色不应有的基础模块权限 ===
|
||||
// user.list / user.manage / config.settings.list / config.settings.manage
|
||||
// 应只属于 admin 角色
|
||||
let over_privileged_codes = vec![
|
||||
"user.list",
|
||||
"user.manage",
|
||||
"config.settings.list",
|
||||
"config.settings.manage",
|
||||
];
|
||||
for code in &over_privileged_codes {
|
||||
db.execute_unprepared(&format!(
|
||||
"UPDATE role_permissions SET deleted_at = NOW(), updated_at = NOW() \
|
||||
FROM roles r, permissions p \
|
||||
WHERE role_permissions.role_id = r.id \
|
||||
AND role_permissions.permission_id = p.id \
|
||||
AND r.code NOT IN ('admin') \
|
||||
AND p.code = '{code}' \
|
||||
AND role_permissions.deleted_at IS NULL"
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user