From 479b5900c9b7059ae31325e7ddbcc7a156083538 Mon Sep 17 00:00:00 2001 From: iven Date: Sat, 25 Apr 2026 00:12:19 +0800 Subject: [PATCH] =?UTF-8?q?feat(health):=20=E6=B3=A8=E5=85=A5=E5=AE=A1?= =?UTF-8?q?=E8=AE=A1=E6=97=A5=E5=BF=97=E8=A6=86=E7=9B=96=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=86=99=E5=85=A5=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 17 个方法全覆盖:patient(4)、appointment(2)、consultation(3)、 follow_up(2)、doctor(3)、health_data(3)。使用 fire-and-forget 模式。 --- .../src/service/appointment_service.rs | 20 ++++++++++++++ .../src/service/consultation_service.rs | 20 ++++++++++++++ .../erp-health/src/service/doctor_service.rs | 22 ++++++++++++++++ .../src/service/follow_up_service.rs | 14 ++++++++++ .../src/service/health_data_service.rs | 22 ++++++++++++++++ .../erp-health/src/service/patient_service.rs | 26 +++++++++++++++++++ 6 files changed, 124 insertions(+) diff --git a/crates/erp-health/src/service/appointment_service.rs b/crates/erp-health/src/service/appointment_service.rs index 49debcf..d08957d 100644 --- a/crates/erp-health/src/service/appointment_service.rs +++ b/crates/erp-health/src/service/appointment_service.rs @@ -1,6 +1,8 @@ //! 预约排班 Service — 预约CRUD、排班管理、日历视图、原子CAS预约 use chrono::Utc; +use erp_core::audit::AuditLog; +use erp_core::audit_service; use erp_core::events::DomainEvent; use sea_orm::entity::prelude::*; use sea_orm::{ActiveValue::Set, Condition, QueryOrder, QuerySelect, TransactionTrait}; @@ -175,6 +177,12 @@ pub async fn create_appointment( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "appointment.created", "appointment") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(AppointmentResp { id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id, appointment_type: m.appointment_type, appointment_date: m.appointment_date, @@ -206,6 +214,8 @@ pub async fn update_appointment_status( let next_ver = check_version(expected_version, model.version) .map_err(|_| HealthError::VersionMismatch)?; + let old_status = model.status.clone(); + let txn = state.db.begin().await?; // 取消时释放排班名额(带下限保护) @@ -249,6 +259,16 @@ pub async fn update_appointment_status( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "appointment.status_changed", "appointment") + .with_resource_id(m.id) + .with_changes( + Some(serde_json::json!({ "status": old_status })), + Some(serde_json::json!({ "status": m.status })), + ), + &state.db, + ).await; + Ok(AppointmentResp { id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id, appointment_type: m.appointment_type, appointment_date: m.appointment_date, diff --git a/crates/erp-health/src/service/consultation_service.rs b/crates/erp-health/src/service/consultation_service.rs index 0611d90..ea595d7 100644 --- a/crates/erp-health/src/service/consultation_service.rs +++ b/crates/erp-health/src/service/consultation_service.rs @@ -1,6 +1,8 @@ //! 咨询管理 Service — 会话管理、消息收发、会话关闭、导出 use chrono::Utc; +use erp_core::audit::AuditLog; +use erp_core::audit_service; use erp_core::events::DomainEvent; use sea_orm::entity::prelude::*; use sea_orm::{ActiveValue::Set, Condition, QueryOrder, QuerySelect}; @@ -65,6 +67,12 @@ pub async fn create_session( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "consultation.opened", "consultation") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(SessionResp { id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id, consultation_type: m.consultation_type, status: m.status, @@ -154,6 +162,12 @@ pub async fn close_session( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "consultation.closed", "consultation") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(SessionResp { id: m.id, patient_id: m.patient_id, doctor_id: m.doctor_id, consultation_type: m.consultation_type, status: m.status, @@ -308,6 +322,12 @@ pub async fn create_message( return Err(HealthError::VersionMismatch); } + audit_service::record( + AuditLog::new(tenant_id, operator_id, "consultation.message_sent", "consultation") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(MessageResp { id: m.id, session_id: m.session_id, sender_id: m.sender_id, sender_role: m.sender_role, content_type: m.content_type, diff --git a/crates/erp-health/src/service/doctor_service.rs b/crates/erp-health/src/service/doctor_service.rs index 64a4adc..cf3e202 100644 --- a/crates/erp-health/src/service/doctor_service.rs +++ b/crates/erp-health/src/service/doctor_service.rs @@ -1,6 +1,8 @@ //! 医护档案 Service — CRUD use chrono::Utc; +use erp_core::audit::AuditLog; +use erp_core::audit_service; use sea_orm::entity::prelude::*; use sea_orm::{ActiveValue::Set, Condition, QueryOrder, QuerySelect}; use uuid::Uuid; @@ -95,6 +97,13 @@ pub async fn create_doctor( }; let model = active.insert(&state.db).await?; + + audit_service::record( + AuditLog::new(tenant_id, operator_id, "doctor.created", "doctor") + .with_resource_id(model.id), + &state.db, + ).await; + Ok(model_to_resp(model)) } @@ -144,6 +153,13 @@ pub async fn update_doctor( active.version = Set(next_ver); let updated = active.update(&state.db).await?; + + audit_service::record( + AuditLog::new(tenant_id, operator_id, "doctor.updated", "doctor") + .with_resource_id(updated.id), + &state.db, + ).await; + Ok(model_to_resp(updated)) } @@ -165,6 +181,12 @@ pub async fn delete_doctor( active.version = Set(next_ver); active.update(&state.db).await?; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "doctor.deleted", "doctor") + .with_resource_id(id), + &state.db, + ).await; + Ok(()) } diff --git a/crates/erp-health/src/service/follow_up_service.rs b/crates/erp-health/src/service/follow_up_service.rs index 752192c..8c9cba2 100644 --- a/crates/erp-health/src/service/follow_up_service.rs +++ b/crates/erp-health/src/service/follow_up_service.rs @@ -1,6 +1,8 @@ //! 随访管理 Service — 随访任务CRUD、随访记录、状态流转 use chrono::Utc; +use erp_core::audit::AuditLog; +use erp_core::audit_service; use erp_core::events::DomainEvent; use sea_orm::entity::prelude::*; use sea_orm::{ActiveValue::Set, QueryOrder, QuerySelect, TransactionTrait}; @@ -126,6 +128,12 @@ pub async fn create_task( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "follow_up_task.created", "follow_up_task") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(FollowUpTaskResp { id: m.id, patient_id: m.patient_id, assigned_to: m.assigned_to, follow_up_type: m.follow_up_type, planned_date: m.planned_date, @@ -295,6 +303,12 @@ pub async fn create_record( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "follow_up_record.created", "follow_up_record") + .with_resource_id(record.id), + &state.db, + ).await; + Ok(FollowUpRecordResp { id: record.id, task_id: record.task_id, executed_by: record.executed_by, executed_date: record.executed_date, result: record.result, diff --git a/crates/erp-health/src/service/health_data_service.rs b/crates/erp-health/src/service/health_data_service.rs index 03b8897..f52bfc3 100644 --- a/crates/erp-health/src/service/health_data_service.rs +++ b/crates/erp-health/src/service/health_data_service.rs @@ -1,6 +1,8 @@ //! 健康数据 Service — 体征记录、化验报告、体检记录、趋势分析 use chrono::Utc; +use erp_core::audit::AuditLog; +use erp_core::audit_service; use erp_core::events::DomainEvent; use num_traits::cast::ToPrimitive; use sea_orm::entity::prelude::*; @@ -106,6 +108,13 @@ pub async fn create_vital_signs( version: Set(1), }; let m = active.insert(&state.db).await?; + + audit_service::record( + AuditLog::new(tenant_id, operator_id, "vital_signs.created", "vital_signs") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(VitalSignsResp { id: m.id, patient_id: m.patient_id, record_date: m.record_date, systolic_bp_morning: m.systolic_bp_morning, diastolic_bp_morning: m.diastolic_bp_morning, @@ -274,6 +283,12 @@ pub async fn create_lab_report( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "lab_report.created", "lab_report") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(LabReportResp { id: m.id, patient_id: m.patient_id, report_date: m.report_date, report_type: m.report_type, indicators: m.indicators, @@ -424,6 +439,13 @@ pub async fn create_health_record( version: Set(1), }; let m = active.insert(&state.db).await?; + + audit_service::record( + AuditLog::new(tenant_id, operator_id, "health_record.created", "health_record") + .with_resource_id(m.id), + &state.db, + ).await; + Ok(HealthRecordResp { id: m.id, patient_id: m.patient_id, record_type: m.record_type, record_date: m.record_date, source: m.source, diff --git a/crates/erp-health/src/service/patient_service.rs b/crates/erp-health/src/service/patient_service.rs index 2c99df7..0c569de 100644 --- a/crates/erp-health/src/service/patient_service.rs +++ b/crates/erp-health/src/service/patient_service.rs @@ -1,6 +1,8 @@ //! 患者管理 Service — CRUD、家庭成员、标签、医生关联、健康摘要 use chrono::Utc; +use erp_core::audit::AuditLog; +use erp_core::audit_service; use erp_core::events::DomainEvent; use sea_orm::entity::prelude::*; use sea_orm::{ActiveValue::Set, Condition, QueryOrder, QuerySelect}; @@ -135,6 +137,12 @@ pub async fn create_patient( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "patient.created", "patient") + .with_resource_id(model.id), + &state.db, + ).await; + Ok(model_to_resp(model)) } @@ -220,6 +228,12 @@ pub async fn update_patient( ); state.event_bus.publish(event, &state.db).await; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "patient.updated", "patient") + .with_resource_id(updated.id), + &state.db, + ).await; + Ok(model_to_resp(updated)) } @@ -242,6 +256,12 @@ pub async fn delete_patient( active.version = Set(next_ver); active.update(&state.db).await?; + audit_service::record( + AuditLog::new(tenant_id, operator_id, "patient.deleted", "patient") + .with_resource_id(id), + &state.db, + ).await; + Ok(()) } @@ -308,6 +328,12 @@ pub async fn manage_patient_tags( rel.insert(&state.db).await?; } + audit_service::record( + AuditLog::new(tenant_id, operator_id, "patient.tags_updated", "patient") + .with_resource_id(patient_id), + &state.db, + ).await; + Ok(()) }