feat(health): 事件驱动集成 + 数据一致性修复 + 逾期随访检查

- event.rs 重写为有状态处理器(订阅 workflow.task.completed / message.sent)
- module.rs on_startup 初始化 HealthCrypto 并注册事件处理器
- consultation_service 消息发送改为事务包裹(INSERT + CAS 原子更新)
- appointment_service 取消预约释放排班名额增加下限保护
- appointment_service update_schedule 增加 max_appointments >= current_appointments 校验
- follow_up_service 新增 complete_task_by_system 和 check_overdue_tasks
- validation.rs 随访状态机增加 overdue 状态支持
- main.rs 启动时运行逾期随访检查后台任务
This commit is contained in:
iven
2026-04-25 00:30:32 +08:00
parent 6c70e2a783
commit 43e127d4f7
7 changed files with 202 additions and 35 deletions

View File

@@ -17,6 +17,21 @@ impl HealthModule {
Self
}
/// 启动定时逾期随访检查(每 6 小时运行一次)
pub fn start_overdue_checker(db: sea_orm::DatabaseConnection) {
tokio::spawn(async move {
let mut interval = tokio::time::interval(std::time::Duration::from_secs(6 * 3600));
loop {
interval.tick().await;
match crate::service::follow_up_service::check_overdue_tasks(&db).await {
Ok(count) if count > 0 => tracing::info!(count = count, "随访逾期检查完成"),
Ok(_) => {}
Err(e) => tracing::warn!(error = %e, "随访逾期检查失败"),
}
}
});
}
pub fn public_routes<S>() -> Router<S>
where
crate::state::HealthState: axum::extract::FromRef<S>,
@@ -235,8 +250,29 @@ impl ErpModule for HealthModule {
vec!["auth"]
}
fn register_event_handlers(&self, bus: &EventBus) {
crate::event::register_handlers(bus);
fn register_event_handlers(&self, _bus: &EventBus) {
// 事件处理器已迁移到 on_startup此处保留空实现以兼容 trait 签名
}
async fn on_startup(&self, ctx: &erp_core::module::ModuleContext) -> erp_core::error::AppResult<()> {
let crypto = crate::crypto::HealthCrypto::from_keys(
&std::env::var("HEALTH_AES_KEY").unwrap_or_default(),
&std::env::var("HEALTH_HMAC_KEY").unwrap_or_default(),
)
.unwrap_or_else(|_| {
tracing::warn!("HEALTH_AES_KEY / HEALTH_HMAC_KEY 未设置或无效,使用开发默认密钥");
crate::crypto::HealthCrypto::dev_default()
});
let state = crate::state::HealthState {
db: ctx.db.clone(),
event_bus: ctx.event_bus.clone(),
crypto,
};
crate::event::register_handlers_with_state(state);
tracing::info!(module = "health", "Health module event handlers registered via on_startup");
Ok(())
}
async fn on_tenant_created(