feat(db): 8 条 Copilot 趋势/复合类告警规则种子数据

趋势类(4): 收缩压快速上升、肌酐连续上升、体重连续上升、血压趋势上升
复合类(4): eGFR+血钾双重危急、透析间期+血压、失约+依从性、Kt/V+血压
This commit is contained in:
iven
2026-05-12 22:30:16 +08:00
parent 78c052ecc9
commit a87425e551
3 changed files with 174 additions and 31 deletions

View File

@@ -144,6 +144,7 @@ mod m20260512_000139_create_copilot_insights;
mod m20260512_000140_create_copilot_risk_snapshots;
mod m20260512_000141_create_copilot_chat_logs;
mod m20260512_000142_seed_copilot_rules;
mod m20260512_000143_seed_copilot_alert_rules;
pub struct Migrator;
@@ -295,6 +296,7 @@ impl MigratorTrait for Migrator {
Box::new(m20260512_000140_create_copilot_risk_snapshots::Migration),
Box::new(m20260512_000141_create_copilot_chat_logs::Migration),
Box::new(m20260512_000142_seed_copilot_rules::Migration),
Box::new(m20260512_000143_seed_copilot_alert_rules::Migration),
]
}
}

View File

@@ -0,0 +1,141 @@
//! 8 条 Copilot 趋势/复合类告警规则种子数据
//!
//! 覆盖 spec §3.2 告警分级场景:
//! - 趋势类(4): 收缩压快速上升、肌酐连续上升、体重连续上升、血压趋势上升
//! - 复合类(4): eGFR+血钾双重危急、透析间期+血压、失约+依从性、Kt/V+血压
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 nil_tenant = "00000000-0000-0000-0000-000000000000";
// 8 条趋势/复合类告警规则
// (idx, name, category, condition_expr, score, severity, suggestion, sort_order)
let rules: &[(i32, &str, &str, &str, i16, &str, &str, i32)] = &[
// 趋势类规则
(
20,
"收缩压快速上升",
"vital_signs",
r#"{"and":[{"=": [{"var":"vital_signs.systolic.trend_rising"}, true]},{">": [{"var":"vital_signs.systolic.change_pct"}, 15]}]}"#,
3,
"warning",
"血压短时间内快速上升,需排除急性因素,建议加测并通知主治医生",
20,
),
(
21,
"肌酐连续上升",
"lab",
r#"{"and":[{"=": [{"var":"lab_reports.creatinine.trend_rising"}, true]},{">": [{"var":"lab_reports.creatinine.change_pct"}, 10]}]}"#,
3,
"warning",
"肌酐连续上升且环比增幅>10%,需排除急性肾损伤可能",
21,
),
(
22,
"体重连续上升",
"vital_signs",
r#"{"=": [{"var":"vital_signs.weight.trend_rising"}, true]}"#,
2,
"info",
"体重连续上升,需评估水钠潴留情况",
22,
),
(
23,
"血压趋势整体上升",
"vital_signs",
r#"{"=": [{"var":"vital_signs.systolic.trend_rising"}, true]}"#,
2,
"info",
"血压呈持续上升趋势,建议关注并调整降压方案",
23,
),
// 复合类规则
(
24,
"eGFR<45且血钾>5.0",
"composite",
r#"{"and":[{"<": [{"var":"lab_reports.egfr.latest"}, 45]},{">": [{"var":"lab_reports.potassium.latest"}, 5.0]}]}"#,
5,
"critical",
"eGFR严重下降且血钾升高需紧急评估并考虑紧急透析",
24,
),
(
25,
"透析间期体重增长+血压极高",
"composite",
r#"{"and":[{">": [{"var":"dialysis.interdialytic_weight_gain_pct"}, 5]},{">": [{"var":"vital_signs.systolic_bp_morning.latest"}, 160]}]}"#,
4,
"critical",
"透析间期体重增长过多且血压极高,需紧急评估液体管理和降压方案",
25,
),
(
26,
"失约+药物依从性不足",
"composite",
r#"{"and":[{">": [{"var":"follow_up.missed_count"}, 2]},{"<": [{"var":"medication.adherence_rate"}, 70]}]}"#,
3,
"warning",
"随访失约且药物依从性不足,建议加强患者教育和主动联系",
26,
),
(
27,
"透析质量危急",
"composite",
r#"{"and":[{"<": [{"var":"dialysis.kt_v.latest"}, 1.0]},{">": [{"var":"vital_signs.systolic_bp_morning.latest"}, 180]}]}"#,
5,
"critical",
"透析充分性严重不足且血压极高,需紧急评估透析方案",
27,
),
];
for &(idx, name, category, cond, score, severity, suggestion, sort) in rules {
let id = format!("c0000000-0000-0000-0000-{:012}", idx);
let sql = format!(
r#"INSERT INTO copilot_rules (id, tenant_id, name, category, condition_expr, score, severity, suggestion, enabled, sort_order, created_at, updated_at, version_lock)
VALUES ('{}', '{}', $1, $2, $3::jsonb, $4, $5, $6, true, $7, NOW(), NOW(), 1)"#,
id, nil_tenant
);
db.execute(sea_orm::Statement::from_sql_and_values(
sea_orm::DatabaseBackend::Postgres,
sql,
[
name.into(),
category.into(),
cond.into(),
score.into(),
severity.into(),
suggestion.into(),
sort.into(),
],
))
.await?;
}
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
db.execute(sea_orm::Statement::from_sql_and_values(
sea_orm::DatabaseBackend::Postgres,
"DELETE FROM copilot_rules WHERE id LIKE 'c0000000-0000-0000-0000-0000000000%' AND sort_order >= 20",
[],
))
.await?;
Ok(())
}
}