feat(health): Track 3 医疗阈值 — warning 种子 + 患者端只读 API
- 新增 6 条 warning 级别阈值种子数据(血压/心率/血糖参考范围) - 新增 GET /health/critical-value-thresholds/public 患者端只读接口 - 扩展 indicator 验证支持 blood_sugar_fasting/postprandial 等新指标
This commit is contained in:
@@ -109,3 +109,16 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(Json(ApiResponse::ok(())))
|
Ok(Json(ApiResponse::ok(())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 患者端只读接口 — 返回当前租户所有活跃阈值,仅需认证。
|
||||||
|
pub async fn list_public_thresholds<S>(
|
||||||
|
State(state): State<HealthState>,
|
||||||
|
Extension(ctx): Extension<TenantContext>,
|
||||||
|
) -> Result<Json<ApiResponse<Vec<crate::entity::critical_value_threshold::Model>>>, AppError>
|
||||||
|
where
|
||||||
|
HealthState: FromRef<S>,
|
||||||
|
S: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
let list = critical_value_threshold_service::find_thresholds(&state.db, ctx.tenant_id).await?;
|
||||||
|
Ok(Json(ApiResponse::ok(list)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -608,6 +608,11 @@ impl HealthModule {
|
|||||||
axum::routing::put(critical_value_threshold_handler::update_threshold)
|
axum::routing::put(critical_value_threshold_handler::update_threshold)
|
||||||
.delete(critical_value_threshold_handler::delete_threshold),
|
.delete(critical_value_threshold_handler::delete_threshold),
|
||||||
)
|
)
|
||||||
|
// 患者端只读阈值(仅需认证)
|
||||||
|
.route(
|
||||||
|
"/health/critical-value-thresholds/public",
|
||||||
|
axum::routing::get(critical_value_threshold_handler::list_public_thresholds),
|
||||||
|
)
|
||||||
// 知情同意记录
|
// 知情同意记录
|
||||||
.route(
|
.route(
|
||||||
"/health/patients/{patient_id}/consents",
|
"/health/patients/{patient_id}/consents",
|
||||||
|
|||||||
@@ -186,7 +186,16 @@ fn validate_direction(direction: &str) -> HealthResult<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate_indicator(indicator: &str) -> HealthResult<()> {
|
fn validate_indicator(indicator: &str) -> HealthResult<()> {
|
||||||
let valid = ["systolic_bp", "diastolic_bp", "heart_rate", "blood_sugar"];
|
let valid = [
|
||||||
|
"systolic_bp",
|
||||||
|
"diastolic_bp",
|
||||||
|
"heart_rate",
|
||||||
|
"blood_sugar",
|
||||||
|
"blood_sugar_fasting",
|
||||||
|
"blood_sugar_postprandial",
|
||||||
|
"blood_oxygen",
|
||||||
|
"temperature",
|
||||||
|
];
|
||||||
if valid.contains(&indicator) {
|
if valid.contains(&indicator) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ mod m20260501_000098_create_ai_suggestion;
|
|||||||
mod m20260501_000099_create_ai_risk_threshold;
|
mod m20260501_000099_create_ai_risk_threshold;
|
||||||
mod m20260501_000100_seed_action_inbox_menu;
|
mod m20260501_000100_seed_action_inbox_menu;
|
||||||
mod m20260502_000101_seed_health_dictionaries;
|
mod m20260502_000101_seed_health_dictionaries;
|
||||||
|
mod m20260502_000102_seed_warning_thresholds;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
@@ -209,6 +210,7 @@ impl MigratorTrait for Migrator {
|
|||||||
Box::new(m20260501_000099_create_ai_risk_threshold::Migration),
|
Box::new(m20260501_000099_create_ai_risk_threshold::Migration),
|
||||||
Box::new(m20260501_000100_seed_action_inbox_menu::Migration),
|
Box::new(m20260501_000100_seed_action_inbox_menu::Migration),
|
||||||
Box::new(m20260502_000101_seed_health_dictionaries::Migration),
|
Box::new(m20260502_000101_seed_health_dictionaries::Migration),
|
||||||
|
Box::new(m20260502_000102_seed_warning_thresholds::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
//! 补充 warning 级别危急值阈值种子数据
|
||||||
|
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
let db = manager.get_connection();
|
||||||
|
|
||||||
|
let result = db
|
||||||
|
.query_one(sea_orm::Statement::from_string(
|
||||||
|
sea_orm::DatabaseBackend::Postgres,
|
||||||
|
"SELECT id::text FROM tenant LIMIT 1".to_string(),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let tid = match result {
|
||||||
|
Some(row) => row.try_get_by_index::<String>(0).unwrap_or_default(),
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// warning 级别阈值 — 用于小程序体征参考范围
|
||||||
|
let sql = format!(
|
||||||
|
r#"
|
||||||
|
INSERT INTO critical_value_threshold (id, tenant_id, indicator, direction, threshold_value, level, is_active, created_at, updated_at)
|
||||||
|
VALUES
|
||||||
|
(gen_random_uuid(), '{tid}', 'systolic_bp', 'high', 140, 'warning', true, now(), now()),
|
||||||
|
(gen_random_uuid(), '{tid}', 'diastolic_bp', 'high', 90, 'warning', true, now(), now()),
|
||||||
|
(gen_random_uuid(), '{tid}', 'heart_rate', 'high', 100, 'warning', true, now(), now()),
|
||||||
|
(gen_random_uuid(), '{tid}', 'heart_rate', 'low', 60, 'warning', true, now(), now()),
|
||||||
|
(gen_random_uuid(), '{tid}', 'blood_sugar_fasting', 'high', 6.1, 'warning', true, now(), now()),
|
||||||
|
(gen_random_uuid(), '{tid}', 'blood_sugar_postprandial','high', 7.8, 'warning', true, now(), now())
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
db.execute(sea_orm::Statement::from_string(
|
||||||
|
sea_orm::DatabaseBackend::Postgres,
|
||||||
|
sql,
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
let db = manager.get_connection();
|
||||||
|
db.execute(sea_orm::Statement::from_string(
|
||||||
|
sea_orm::DatabaseBackend::Postgres,
|
||||||
|
"DELETE FROM critical_value_threshold WHERE level = 'warning'".to_string(),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user