# 任务015:Nemotron审查问题修复 ## 目标 修复Nemotron审查发现的7个严重问题。 ## 修复清单 ### 1. 权限码种子数据缺失( 高优先级) **位置:** `src/db/migrate.rs` **问题:** `org:*`、`project:*`、`device:edit` 等权限码未在`seed_permissions`中初始化。 **修复方案:** ```rust // 在 seed_permissions 函数中添加缺失的权限码 let permissions = vec![ // ... 已有的权限码 // 组织管理 ("org:view", "查看组织"), ("org:create", "创建组织"), ("org:edit", "编辑组织"), ("org:delete", "删除组织"), // 项目管理 ("project:view", "查看项目"), ("project:create", "创建项目"), ("project:edit", "编辑项目"), ("project:delete", "删除项目"), // 设备管理(补充) ("device:edit", "编辑设备"), ]; // 插入数据库(使用 INSERT IGNORE 避免重复) for (code, name) in permissions { sqlx::query( "INSERT IGNORE INTO permissions (code, name) VALUES (?, ?)" ) .bind(code) .bind(name) .execute(pool) .await?; } ``` **角色权限分配:** ```rust // 总管理员 — 全部权限 // 企业管理员 — 添加 org:*, project:*, device:edit 权限 // 普通用户 — 只保留 view 权限 ``` ### 2. H5接口数据隔离(🔴 高优先级) **位置:** `src/routes/h5.rs` **问题:** `get_dashboard`返回全局统计数据,`get_cabinet_detail`/`get_compartment_detail`无权限校验。 **修复方案:** ```rust /// GET /api/h5/dashboard — H5首页数据(带组织隔离) pub async fn get_dashboard( user: CurrentUser, State(state): State, ) -> Result, AppError> { auth::check_permission(&user, "device:view")?; let db = &state.mysql; // 根据角色过滤数据 let org_filter = if user.role_level >= 2 { None // 总管理员看全部 } else { user.organization_id // 企业管理员只看本组织 }; // 查询柜子统计(带组织过滤) let cabinet_stats = if let Some(org_id) = org_filter { sqlx::query_as::<_, (i64, i64, i64, i64)>( r#"SELECT COUNT(*) as total, SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as online, SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) as charging, SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) as fault FROM cabinets c INNER JOIN projects p ON c.project_id = p.id WHERE p.organization_id = ?"# ) .bind(org_id) .fetch_one(db) .await? } else { // 总管理员查询全部 // ... }; Ok(Json(json!({ "total": cabinet_stats.0, "online": cabinet_stats.1, "charging": cabinet_stats.2, "fault": cabinet_stats.3 }))) } /// GET /api/h5/cabinets/:id — H5设备详情(带权限校验) pub async fn get_cabinet_detail( user: CurrentUser, State(state): State, Path(id): Path, ) -> Result, AppError> { auth::check_permission(&user, "device:view")?; let db = &state.mysql; // 验证用户是否有权访问该设备 if user.role_level < 2 { if let Some(org_id) = user.organization_id { let access: Option<(i64,)> = sqlx::query_as( r#"SELECT c.id FROM cabinets c INNER JOIN projects p ON c.project_id = p.id WHERE c.id = ? AND p.organization_id = ?"# ) .bind(id) .bind(org_id) .fetch_optional(db) .await?; if access.is_none() { return Err(AppError::Forbidden("无权访问该设备".into())); } } else { return Err(AppError::Forbidden("无组织关联".into())); } } // ... 原有查询逻辑 } ``` ### 3. 前后端H5告警字段匹配(🔴 中优先级) **位置:** `src/routes/h5.rs` 和 `src/h5/pages/home.tsx` **问题:** 后端返回`{compartment_id, cabinet_id}`,前端期望`{project, cabinet}`。 **修复方案(后端):** ```rust // 修改告警查询,返回前端期望的字段 let alerts = sqlx::query_as::<_, (String, String, String)>( r#"SELECT p.name as project, cab.name as cabinet, dl.content as message FROM device_logs dl INNER JOIN cabinets cab ON dl.cabinet_id = cab.id INNER JOIN projects p ON cab.project_id = p.id WHERE dl.log_type = 3 -- 告警 ORDER BY dl.created_at DESC LIMIT 10"# ) .fetch_all(db) .await?; Ok(Json(json!({ "alerts": alerts.iter().map(|(project, cabinet, message)| { json!({ "project": project, "cabinet": cabinet, "message": message }) }).collect::>() }))) ``` ### 4. 其他严重问题修复 **4.1 SQL参数化(charge_records.rs)** ```rust // 确保所有SQL查询使用参数化绑定 // 检查并修复任何 format! 拼接SQL的地方 ``` **4.2 数据库索引(migrate.rs)** ```rust // 添加关键索引 sqlx::query("CREATE INDEX idx_cabinets_project ON cabinets(project_id)") .execute(pool).await?; sqlx::query("CREATE INDEX idx_charge_records_cabinet ON charge_records(cabinet_id)") .execute(pool).await?; sqlx::query("CREATE INDEX idx_device_logs_cabinet ON device_logs(cabinet_id)") .execute(pool).await?; ``` **4.3 消除重复代码** ```rust // 提取公共的组织过滤逻辑到 middleware/auth.rs pub fn org_condition(user: &CurrentUser) -> String { if user.role_level >= 2 { String::new() } else if let Some(org_id) = user.organization_id { format!("AND organization_id = {}", org_id) } else { "AND 1=0".to_string() } } ``` ## 质量约束 1. 完成代码后执行 `cargo check` + `cargo clippy` + `tsc --noEmit`,零报错零警告 2. 分层拆分,单函数≤80行,命名语义化,完整注释 3. 所有外部IO/网络请求异常捕获,禁止裸panic 4. 分支逻辑全覆盖,不遗漏兜底分支 5. 常量抽离,不使用废弃API 6. Rust内存安全,React函数组件+Hooks 7. H5接口必须添加权限校验和组织数据隔离