feat(db): 8 条 Copilot 趋势/复合类告警规则种子数据
趋势类(4): 收缩压快速上升、肌酐连续上升、体重连续上升、血压趋势上升 复合类(4): eGFR+血钾双重危急、透析间期+血压、失约+依从性、Kt/V+血压
This commit is contained in:
@@ -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),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@
|
||||
- Create: `crates/erp-server/migration/src/m20260512_000138_create_copilot_rules.rs`
|
||||
- Modify: `crates/erp-server/migration/src/lib.rs`
|
||||
|
||||
- [ ] **Step 1: 创建迁移文件**
|
||||
- [x] **Step 1: 创建迁移文件**
|
||||
|
||||
文件 `m20260512_000138_create_copilot_rules.rs`,参照 `m20260510_000136_create_banner.rs` 模式:
|
||||
|
||||
@@ -106,18 +106,18 @@ enum CopilotRules {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 注册迁移**
|
||||
- [x] **Step 2: 注册迁移**
|
||||
|
||||
在 `migration/src/lib.rs` 中:
|
||||
- 顶部添加 `mod m20260512_000138_create_copilot_rules;`
|
||||
- `migrations()` vec 中添加 `Box::new(m20260512_000138_create_copilot_rules::Migration)`
|
||||
|
||||
- [ ] **Step 3: 编译验证**
|
||||
- [x] **Step 3: 编译验证**
|
||||
|
||||
Run: `cargo check -p erp-server`
|
||||
Expected: 编译通过
|
||||
|
||||
- [ ] **Step 4: 提交**
|
||||
- [x] **Step 4: 提交**
|
||||
|
||||
```bash
|
||||
git add crates/erp-server/migration/src/m20260512_000138_create_copilot_rules.rs crates/erp-server/migration/src/lib.rs
|
||||
@@ -132,7 +132,7 @@ git commit -m "feat(db): copilot_rules 表迁移"
|
||||
- Create: `crates/erp-server/migration/src/m20260512_000141_create_copilot_chat_logs.rs`
|
||||
- Modify: `crates/erp-server/migration/src/lib.rs`
|
||||
|
||||
- [ ] **Step 1: 创建 copilot_insights 迁移(m20260512_000139)**
|
||||
- [x] **Step 1: 创建 copilot_insights 迁移(m20260512_000139)**
|
||||
|
||||
参照 Task 1 模式,字段按 spec §6.2 DDL。关键列:
|
||||
- `patient_id UUID NOT NULL`(无 REFERENCES,逻辑关联)
|
||||
@@ -149,7 +149,7 @@ git commit -m "feat(db): copilot_rules 表迁移"
|
||||
- 索引:`idx_copilot_insights_tenant_patient` on (tenant_id, patient_id)
|
||||
- 索引:`idx_copilot_insights_expires` on (expires_at)
|
||||
|
||||
- [ ] **Step 2: 创建 copilot_risk_snapshots 迁移(m20260512_000140)**
|
||||
- [x] **Step 2: 创建 copilot_risk_snapshots 迁移(m20260512_000140)**
|
||||
|
||||
关键列:
|
||||
- `patient_id UUID NOT NULL`(无 REFERENCES)
|
||||
@@ -161,7 +161,7 @@ git commit -m "feat(db): copilot_rules 表迁移"
|
||||
- `data_freshness JSONB`
|
||||
- 唯一索引:`idx_copilot_risk_snapshots_tenant_patient` UNIQUE on (tenant_id, patient_id)
|
||||
|
||||
- [ ] **Step 3: 创建 copilot_chat_logs 迁移(m20260512_000141)**
|
||||
- [x] **Step 3: 创建 copilot_chat_logs 迁移(m20260512_000141)**
|
||||
|
||||
关键列:
|
||||
- `patient_id UUID NOT NULL`(无 REFERENCES)
|
||||
@@ -177,16 +177,16 @@ git commit -m "feat(db): copilot_rules 表迁移"
|
||||
- 索引:`idx_copilot_chat_logs_session` on (tenant_id, session_id)
|
||||
- 索引:`idx_copilot_chat_logs_patient` on (tenant_id, patient_id)
|
||||
|
||||
- [ ] **Step 4: 注册 3 个迁移**
|
||||
- [x] **Step 4: 注册 3 个迁移**
|
||||
|
||||
在 `migration/src/lib.rs` 中注册 m139、m140、m141。
|
||||
|
||||
- [ ] **Step 5: 编译验证**
|
||||
- [x] **Step 5: 编译验证**
|
||||
|
||||
Run: `cargo check -p erp-server`
|
||||
Expected: 编译通过
|
||||
|
||||
- [ ] **Step 6: 提交**
|
||||
- [x] **Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add crates/erp-server/migration/src/
|
||||
@@ -202,7 +202,7 @@ git commit -m "feat(db): copilot_insights/risk_snapshots/chat_logs 表迁移"
|
||||
- Create: `crates/erp-ai/src/entity/copilot_chat_logs.rs`
|
||||
- Modify: `crates/erp-ai/src/entity/mod.rs`
|
||||
|
||||
- [ ] **Step 1: 创建 copilot_rules entity**
|
||||
- [x] **Step 1: 创建 copilot_rules entity**
|
||||
|
||||
参照 `crates/erp-ai/src/entity/ai_suggestion.rs` 模式:
|
||||
|
||||
@@ -238,11 +238,11 @@ pub enum Relation {}
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建其余 3 个 entity**
|
||||
- [x] **Step 2: 创建其余 3 个 entity**
|
||||
|
||||
同样模式,字段对应 spec §6.2 DDL。
|
||||
|
||||
- [ ] **Step 3: 注册 entity 模块**
|
||||
- [x] **Step 3: 注册 entity 模块**
|
||||
|
||||
在 `crates/erp-ai/src/entity/mod.rs` 中添加:
|
||||
```rust
|
||||
@@ -252,12 +252,12 @@ pub mod copilot_risk_snapshots;
|
||||
pub mod copilot_chat_logs;
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 编译验证**
|
||||
- [x] **Step 4: 编译验证**
|
||||
|
||||
Run: `cargo check -p erp-ai`
|
||||
Expected: 编译通过
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
- [x] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add crates/erp-ai/src/entity/
|
||||
@@ -270,7 +270,7 @@ git commit -m "feat(ai): copilot 4 个 SeaORM entity"
|
||||
- Create: `crates/erp-ai/src/copilot/mod.rs`
|
||||
- Create: `crates/erp-ai/src/copilot/rules.rs`
|
||||
|
||||
- [ ] **Step 1: 创建 copilot 模块入口(仅 rules,其他 Task 5 再加)**
|
||||
- [x] **Step 1: 创建 copilot 模块入口(仅 rules,其他 Task 5 再加)**
|
||||
|
||||
`crates/erp-ai/src/copilot/mod.rs`:
|
||||
```rust
|
||||
@@ -278,7 +278,7 @@ pub mod rules;
|
||||
// scoring 和 engine 将在 Task 5 中添加
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 编写规则引擎失败的测试**
|
||||
- [x] **Step 2: 编写规则引擎失败的测试**
|
||||
|
||||
`crates/erp-ai/src/copilot/rules.rs` 底部:
|
||||
|
||||
@@ -329,12 +329,12 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 运行测试确认失败**
|
||||
- [x] **Step 3: 运行测试确认失败**
|
||||
|
||||
Run: `cargo test -p erp-ai -- copilot::rules::tests`
|
||||
Expected: 编译失败(函数不存在)
|
||||
|
||||
- [ ] **Step 4: 实现 JSONLogic 解释器**
|
||||
- [x] **Step 4: 实现 JSONLogic 解释器**
|
||||
|
||||
```rust
|
||||
use serde_json::Value;
|
||||
@@ -447,7 +447,7 @@ pub fn evaluate_rules(
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 运行测试确认通过**
|
||||
- [x] **Step 5: 运行测试确认通过**
|
||||
|
||||
Run: `cargo test -p erp-ai -- copilot::rules::tests`
|
||||
Expected: 5 tests PASS
|
||||
@@ -824,14 +824,14 @@ Expected: 返回 15 条预置规则
|
||||
- Modify: `crates/erp-ai/src/lib.rs`(添加 `pub mod event;`)
|
||||
- Modify: `crates/erp-ai/src/module.rs`(on_startup 中启动消费者)
|
||||
|
||||
- [ ] **Step 1: 创建 event 模块入口**
|
||||
- [x] **Step 1: 创建 event 模块入口**
|
||||
|
||||
`crates/erp-ai/src/event/mod.rs`:
|
||||
```rust
|
||||
pub mod copilot_consumer;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 编写消费者失败的测试**
|
||||
- [x] **Step 2: 编写消费者失败的测试**
|
||||
|
||||
`crates/erp-ai/src/event/copilot_consumer.rs` 底部:
|
||||
|
||||
@@ -858,12 +858,12 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 运行测试确认失败**
|
||||
- [x] **Step 3: 运行测试确认失败**
|
||||
|
||||
Run: `cargo test -p erp-ai -- copilot_consumer::tests`
|
||||
Expected: 编译失败
|
||||
|
||||
- [ ] **Step 4: 实现事件消费者**
|
||||
- [x] **Step 4: 实现事件消费者**
|
||||
|
||||
`crates/erp-ai/src/event/copilot_consumer.rs`:
|
||||
|
||||
@@ -941,7 +941,7 @@ async fn process_event(db: &sea_orm::DatabaseConnection, event: &DomainEvent) {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 在 module.rs on_startup 中启动消费者**
|
||||
- [x] **Step 5: 在 module.rs on_startup 中启动消费者**
|
||||
|
||||
```rust
|
||||
// 在 on_startup 方法中添加
|
||||
@@ -949,21 +949,21 @@ let copilot_handles = crate::event::copilot_consumer::spawn(&ctx.db, &ctx.event_
|
||||
std::mem::forget(copilot_handles);
|
||||
```
|
||||
|
||||
- [ ] **Step 6: 在 lib.rs 注册 event 模块**
|
||||
- [x] **Step 6: 在 lib.rs 注册 event 模块**
|
||||
|
||||
添加 `pub mod event;`
|
||||
|
||||
- [ ] **Step 7: 运行测试**
|
||||
- [x] **Step 7: 运行测试**
|
||||
|
||||
Run: `cargo test -p erp-ai -- copilot_consumer::tests`
|
||||
Expected: 2 tests PASS
|
||||
|
||||
- [ ] **Step 8: 编译验证**
|
||||
- [x] **Step 8: 编译验证**
|
||||
|
||||
Run: `cargo check -p erp-ai`
|
||||
Expected: 编译通过
|
||||
|
||||
- [ ] **Step 9: 提交**
|
||||
- [x] **Step 9: 提交**
|
||||
|
||||
```bash
|
||||
git add crates/erp-ai/src/event/ crates/erp-ai/src/lib.rs crates/erp-ai/src/module.rs
|
||||
@@ -975,7 +975,7 @@ git commit -m "feat(ai): Copilot 事件消费者(订阅 health 事件)"
|
||||
**Files:**
|
||||
- Modify: `crates/erp-ai/src/copilot/scoring.rs`
|
||||
|
||||
- [ ] **Step 1: 编写 LLM 补充分析失败的测试**
|
||||
- [x] **Step 1: 编写 LLM 补充分析失败的测试**
|
||||
|
||||
在 `scoring.rs` 底部添加测试:
|
||||
|
||||
@@ -1019,7 +1019,7 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试**
|
||||
- [x] **Step 2: 运行测试**
|
||||
|
||||
Run: `cargo test -p erp-ai -- copilot::scoring::tests`
|
||||
Expected: 3 tests PASS
|
||||
|
||||
Reference in New Issue
Block a user