//! 组织树 API //! //! 返回组织->项目->设备完整树状结构。 //! 根据用户角色进行数据隔离:总管理员看全部,企业管理员只看本组织。 use axum::extract::State; use axum::Json; use serde_json::{json, Value}; use super::organizations::{CabinetRow, OrganizationRow, ProjectRow, TreeNode}; use crate::error::AppError; use crate::middleware::auth::{self, CurrentUser}; use crate::commands::AppState; /// GET /api/organization-tree — 返回组织->项目->设备完整树 /// /// 需要 `device:view` 权限。 /// 数据隔离:总管理员看所有组织,企业管理员只看本组织下的数据。 pub async fn organization_tree( user: CurrentUser, State(state): State, ) -> Result, AppError> { auth::check_permission(&user, "device:view")?; let db = &state.mysql; // 根据角色过滤组织:总管理员看所有,企业管理员只看本组织 let orgs: Vec = if user.role_level >= 2 { sqlx::query_as( r#"SELECT id, name FROM organizations ORDER BY id"#, ) .fetch_all(db) .await? } else if let Some(org_id) = user.organization_id { sqlx::query_as( r#"SELECT id, name FROM organizations WHERE id = ? ORDER BY id"#, ) .bind(org_id) .fetch_all(db) .await? } else { // 无组织关联的用户看不到任何数据 return Ok(Json(json!([]))); }; let projects: Vec = sqlx::query_as( r#"SELECT id, organization_id, name FROM projects ORDER BY id"#, ) .fetch_all(db) .await?; let cabinets: Vec = sqlx::query_as( r#"SELECT id, project_id, abstract_id, imei, name, status FROM cabinets ORDER BY id"#, ) .fetch_all(db) .await?; // 构建树 let tree: Vec = orgs .into_iter() .map(|org| { let org_projects: Vec = projects .iter() .filter(|p| p.organization_id == Some(org.id)) .cloned() .collect(); let children: Vec = org_projects .into_iter() .map(|proj| { let proj_cabinets: Vec = cabinets .iter() .filter(|c| c.project_id == Some(proj.id)) .cloned() .collect(); let cab_nodes: Vec = proj_cabinets .into_iter() .map(|c| TreeNode { id: c.id, name: c.name.unwrap_or_else(|| c.abstract_id.clone()), children: None, abstract_id: Some(c.abstract_id), imei: Some(c.imei), status: Some(c.status), }) .collect(); TreeNode { id: proj.id, name: proj.name, children: Some(cab_nodes), abstract_id: None, imei: None, status: None, } }) .collect(); TreeNode { id: org.id, name: org.name, children: Some(children), abstract_id: None, imei: None, status: None, } }) .collect(); Ok(Json(json!(tree))) }