diff --git a/src/handler/control.rs b/src/handler/control.rs index 49709b7..4edfb50 100644 --- a/src/handler/control.rs +++ b/src/handler/control.rs @@ -114,6 +114,47 @@ pub async fn get_unit( } } +#[derive(serde::Serialize)] +pub struct EquipmentDetail { + #[serde(flatten)] + pub equipment: crate::model::Equipment, + pub points: Vec, +} + +#[derive(serde::Serialize)] +pub struct UnitDetail { + #[serde(flatten)] + pub unit: crate::model::ControlUnit, + pub equipments: Vec, +} + +pub async fn get_unit_detail( + State(state): State, + Path(unit_id): Path, +) -> Result { + let unit = crate::service::get_unit_by_id(&state.pool, unit_id) + .await? + .ok_or_else(|| ApiErr::NotFound("Unit not found".to_string(), None))?; + + let equipments = crate::service::get_equipment_by_unit_id(&state.pool, unit_id).await?; + let equipment_ids: Vec = equipments.iter().map(|e| e.id).collect(); + let all_points = crate::service::get_points_by_equipment_ids(&state.pool, &equipment_ids).await?; + + let equipments = equipments + .into_iter() + .map(|eq| { + let points = all_points + .iter() + .filter(|p| p.equipment_id == Some(eq.id)) + .cloned() + .collect(); + EquipmentDetail { equipment: eq, points } + }) + .collect(); + + Ok(Json(UnitDetail { unit, equipments })) +} + #[derive(Debug, Deserialize, Validate)] pub struct CreateUnitReq { #[validate(length(min = 1, max = 100))] diff --git a/src/main.rs b/src/main.rs index fe9bb62..84f9729 100644 --- a/src/main.rs +++ b/src/main.rs @@ -243,6 +243,10 @@ fn build_router(state: AppState) -> Router { "/api/unit/{unit_id}/runtime", get(handler::control::get_unit_runtime), ) + .route( + "/api/unit/{unit_id}/detail", + get(handler::control::get_unit_detail), + ) .route( "/api/tag", get(handler::tag::get_tag_list).post(handler::tag::create_tag), diff --git a/src/model.rs b/src/model.rs index f33fccc..cc7c97f 100644 --- a/src/model.rs +++ b/src/model.rs @@ -86,7 +86,7 @@ pub struct Node { pub updated_at: DateTime, } -#[derive(Debug, Serialize, Deserialize, FromRow)] +#[derive(Debug, Clone, Serialize, Deserialize, FromRow)] #[allow(dead_code)] pub struct Point { pub id: Uuid, diff --git a/src/service/control.rs b/src/service/control.rs index 97f90c0..3455219 100644 --- a/src/service/control.rs +++ b/src/service/control.rs @@ -328,6 +328,21 @@ pub async fn get_equipment_by_unit_id( .await } +pub async fn get_points_by_equipment_ids( + pool: &PgPool, + equipment_ids: &[Uuid], +) -> Result, sqlx::Error> { + if equipment_ids.is_empty() { + return Ok(vec![]); + } + sqlx::query_as::<_, crate::model::Point>( + r#"SELECT * FROM point WHERE equipment_id = ANY($1) ORDER BY equipment_id, created_at"#, + ) + .bind(equipment_ids) + .fetch_all(pool) + .await +} + pub async fn get_equipment_role_points( pool: &PgPool, equipment_id: Uuid,