use axum::Extension; use axum::extract::{FromRef, Path, Query, State}; use axum::response::IntoResponse; use serde::Deserialize; use utoipa::IntoParams; use uuid::Uuid; use erp_core::error::AppError; use erp_core::rbac::require_permission; use erp_core::types::{ApiResponse, TenantContext}; use crate::service::device_reading_service; use crate::state::HealthState; #[derive(Debug, Deserialize)] pub struct PatientPath { pub patient_id: Uuid, } #[derive(Debug, Deserialize, IntoParams)] pub struct ReadingListQuery { pub device_type: Option, pub hours: Option, pub page: Option, pub page_size: Option, } #[derive(Debug, Deserialize, IntoParams)] pub struct HourlyQuery { pub device_type: String, pub days: Option, pub page: Option, pub page_size: Option, } #[utoipa::path( post, path = "/health/patients/{patient_id}/device-readings/batch", responses((status = 200, description = "批量创建成功")), tag = "设备数据", security(("bearer_auth" = [])), )] pub async fn batch_create( State(state): State, Extension(ctx): Extension, Path(path): Path, axum::Json(body): axum::Json, ) -> Result where HealthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "health.device-readings.manage")?; let result = device_reading_service::batch_create_readings(&state, ctx.tenant_id, path.patient_id, body) .await?; Ok(axum::Json(ApiResponse::ok(result))) } #[utoipa::path( get, path = "/health/patients/{patient_id}/device-readings", responses((status = 200, description = "设备读数列表")), tag = "设备数据", security(("bearer_auth" = [])), )] pub async fn list_readings( State(state): State, Extension(ctx): Extension, Path(path): Path, Query(query): Query, ) -> Result where HealthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "health.device-readings.list")?; let page = query.page.unwrap_or(1); let page_size = query.page_size.unwrap_or(20).min(100); let result = device_reading_service::query_device_readings( &state, ctx.tenant_id, path.patient_id, query.device_type.as_deref(), query.hours, page, page_size, ) .await?; Ok(axum::Json(ApiResponse::ok(result))) } #[utoipa::path( get, path = "/health/patients/{patient_id}/device-readings/hourly", responses((status = 200, description = "小时聚合数据")), tag = "设备数据", security(("bearer_auth" = [])), )] pub async fn list_hourly( State(state): State, Extension(ctx): Extension, Path(path): Path, Query(query): Query, ) -> Result where HealthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "health.device-readings.list")?; let page = query.page.unwrap_or(1); let page_size = query.page_size.unwrap_or(20).min(100); let days = query.days.unwrap_or(7); let result = device_reading_service::query_hourly_readings( &state, ctx.tenant_id, path.patient_id, &query.device_type, days, page, page_size, ) .await?; Ok(axum::Json(ApiResponse::ok(result))) }