feat(health): 日聚合查询 API — GET /health/vital-signs/daily

- 新增 DailyAggQuery DTO(patient_id/device_type/start_date/end_date)
- 新增 get_daily_aggregations handler(需 health.device-readings.list 权限)
- 路由注册到 protected_routes
This commit is contained in:
iven
2026-05-04 02:54:13 +08:00
parent 4c1d98116a
commit 3a14b7efe3
3 changed files with 92 additions and 1 deletions

View File

@@ -22,3 +22,4 @@ pub mod health_data_handler;
pub mod patient_handler;
pub mod points_handler;
pub mod stats_handler;
pub mod vital_signs_daily_handler;

View File

@@ -0,0 +1,51 @@
use axum::extract::{FromRef, Query, State};
use axum::response::IntoResponse;
use axum::Extension;
use serde::Deserialize;
use utoipa::IntoParams;
use erp_core::error::AppError;
use erp_core::rbac::require_permission;
use erp_core::types::{ApiResponse, TenantContext};
use crate::service::vital_signs_daily_service;
use crate::state::HealthState;
#[derive(Debug, Deserialize, IntoParams)]
pub struct DailyAggQuery {
pub patient_id: Option<uuid::Uuid>,
pub device_type: Option<String>,
pub start_date: String,
pub end_date: String,
}
pub async fn get_daily_aggregations<S>(
State(state): State<HealthState>,
Extension(ctx): Extension<TenantContext>,
Query(query): Query<DailyAggQuery>,
) -> Result<impl IntoResponse, AppError>
where
HealthState: FromRef<S>,
S: Clone + Send + Sync + 'static,
{
require_permission(&ctx, "health.device-readings.list")?;
let start = query.start_date.parse::<chrono::NaiveDate>().map_err(|_| {
AppError::Validation("Invalid start_date format, expected YYYY-MM-DD".into())
})?;
let end = query.end_date.parse::<chrono::NaiveDate>().map_err(|_| {
AppError::Validation("Invalid end_date format, expected YYYY-MM-DD".into())
})?;
let results = vital_signs_daily_service::query_daily(
&state.db,
ctx.tenant_id,
query.patient_id,
query.device_type,
start,
end,
)
.await?;
Ok(axum::Json(ApiResponse::ok(results)))
}