153 lines
4.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 组织树 API
//!
//! 两个独立接口:
//! 1. /api/organization-tree — 返回多级组织->项目树
//! 2. /api/cabinets/filter — 根据组织/项目筛选设备列表
use axum::extract::{State, Query};
use axum::Json;
use serde::Deserialize;
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;
/// 组织树接口 — 返回多级组织->项目树
pub async fn organization_tree(
user: CurrentUser,
State(state): State<AppState>,
) -> Result<Json<Value>, AppError> {
auth::check_permission(&user, "device:view")?;
let db = &state.mysql;
// 获取所有组织带parent_id
let orgs: Vec<OrganizationRow> = sqlx::query_as(
"SELECT id, name, parent_id FROM organizations ORDER BY id"
)
.fetch_all(db)
.await?;
// 获取所有项目
let projects: Vec<ProjectRow> = sqlx::query_as(
"SELECT id, organization_id, name FROM projects ORDER BY id"
)
.fetch_all(db)
.await?;
// 递归构建树
fn build_tree(
orgs: &[OrganizationRow],
projects: &[ProjectRow],
parent_id: Option<i64>,
) -> Vec<TreeNode> {
orgs
.iter()
.filter(|o| o.parent_id == parent_id)
.map(|org| {
// 递归获取子组织
let children = build_tree(orgs, projects, Some(org.id));
// 获取该组织下的项目
let org_projects: Vec<TreeNode> = projects
.iter()
.filter(|p| p.organization_id == Some(org.id))
.map(|p| TreeNode {
id: p.id,
name: p.name.clone(),
children: None,
abstract_id: None,
imei: None,
status: None,
})
.collect();
// 合并子组织和项目
let mut all_children = children;
all_children.extend(org_projects);
TreeNode {
id: org.id,
name: org.name.clone(),
children: if all_children.is_empty() { None } else { Some(all_children) },
abstract_id: None,
imei: None,
status: None,
}
})
.collect()
}
let tree = build_tree(&orgs, &projects, None);
Ok(Json(json!(tree)))
}
/// 设备列表筛选参数
#[derive(Deserialize)]
pub struct CabinetFilterParams {
pub organization_id: Option<i64>,
pub project_id: Option<i64>,
}
/// 设备列表接口 — 根据组织/项目筛选
pub async fn filter_cabinets(
user: CurrentUser,
State(state): State<AppState>,
Query(params): Query<CabinetFilterParams>,
) -> Result<Json<Value>, AppError> {
auth::check_permission(&user, "device:view")?;
let db = &state.mysql;
let rows = if let Some(proj_id) = params.project_id {
// 按项目筛选
sqlx::query_as::<_, CabinetRow>(
"SELECT id, project_id, abstract_id, imei, iccid, name, address, status
FROM cabinets WHERE project_id = ? ORDER BY id"
)
.bind(proj_id)
.fetch_all(db)
.await?
} else if let Some(org_id) = params.organization_id {
// 按组织筛选(包括下级组织)
sqlx::query_as::<_, CabinetRow>(
"SELECT c.id, c.project_id, c.abstract_id, c.imei, c.iccid, c.name, c.address, c.status
FROM cabinets c
JOIN projects p ON c.project_id = p.id
WHERE p.organization_id IN (
SELECT id FROM organizations WHERE id = ? OR parent_id = ?
) ORDER BY c.id"
)
.bind(org_id)
.bind(org_id)
.fetch_all(db)
.await?
} else if user.role_level >= 2 {
// 总管理员看所有
sqlx::query_as::<_, CabinetRow>(
"SELECT id, project_id, abstract_id, imei, iccid, name, address, status
FROM cabinets ORDER BY id"
)
.fetch_all(db)
.await?
} else if let Some(org_id) = user.organization_id {
// 企业管理员只看本组织
sqlx::query_as::<_, CabinetRow>(
"SELECT c.id, c.project_id, c.abstract_id, c.imei, c.iccid, c.name, c.address, c.status
FROM cabinets c
JOIN projects p ON c.project_id = p.id
WHERE p.organization_id = ? ORDER BY c.id"
)
.bind(org_id)
.fetch_all(db)
.await?
} else {
vec![]
};
Ok(Json(json!(rows)))
}