use axum::Router; use uuid::Uuid; use erp_core::error::AppResult; use erp_core::events::EventBus; use erp_core::module::{ErpModule, PermissionDescriptor}; use crate::handler::{ appointment_handler, article_handler, consultation_handler, doctor_handler, follow_up_handler, health_data_handler, patient_handler, }; pub struct HealthModule; impl HealthModule { pub fn new() -> Self { Self } pub fn public_routes() -> Router where crate::state::HealthState: axum::extract::FromRef, S: Clone + Send + Sync + 'static, { Router::new() } pub fn protected_routes() -> Router where crate::state::HealthState: axum::extract::FromRef, S: Clone + Send + Sync + 'static, { Router::new() // 患者管理 .route( "/health/patients", axum::routing::get(patient_handler::list_patients) .post(patient_handler::create_patient), ) .route( "/health/patients/{id}", axum::routing::get(patient_handler::get_patient) .put(patient_handler::update_patient) .delete(patient_handler::delete_patient), ) .route( "/health/patients/{id}/tags", axum::routing::post(patient_handler::manage_patient_tags), ) .route( "/health/patients/{id}/health-summary", axum::routing::get(patient_handler::get_health_summary), ) .route( "/health/patients/{id}/family-members", axum::routing::get(patient_handler::list_family_members) .post(patient_handler::create_family_member), ) .route( "/health/patients/{id}/family-members/{fid}", axum::routing::put(patient_handler::update_family_member) .delete(patient_handler::delete_family_member), ) .route( "/health/patients/{id}/doctors", axum::routing::post(patient_handler::assign_doctor), ) .route( "/health/patients/{id}/doctors/{did}", axum::routing::delete(patient_handler::remove_doctor), ) // 健康数据 .route( "/health/patients/{id}/vital-signs", axum::routing::get(health_data_handler::list_vital_signs) .post(health_data_handler::create_vital_signs), ) .route( "/health/patients/{id}/vital-signs/{vid}", axum::routing::put(health_data_handler::update_vital_signs) .delete(health_data_handler::delete_vital_signs), ) .route( "/health/patients/{id}/lab-reports", axum::routing::get(health_data_handler::list_lab_reports) .post(health_data_handler::create_lab_report), ) .route( "/health/patients/{id}/lab-reports/{rid}", axum::routing::put(health_data_handler::update_lab_report) .delete(health_data_handler::delete_lab_report), ) .route( "/health/patients/{id}/health-records", axum::routing::get(health_data_handler::list_health_records) .post(health_data_handler::create_health_record), ) .route( "/health/patients/{id}/health-records/{rid}", axum::routing::put(health_data_handler::update_health_record) .delete(health_data_handler::delete_health_record), ) .route( "/health/patients/{id}/trends", axum::routing::get(health_data_handler::list_trends), ) .route( "/health/patients/{id}/trends/generate", axum::routing::post(health_data_handler::generate_trend), ) .route( "/health/patients/{id}/trends/{indicator}", axum::routing::get(health_data_handler::get_indicator_timeseries), ) // 小程序趋势查询(通过 JWT user_id 关联 patient,无需传 patient_id) .route( "/health/vital-signs/trend", axum::routing::get(health_data_handler::get_mini_trend), ) // 小程序今日体征摘要 .route( "/health/vital-signs/today", axum::routing::get(health_data_handler::get_mini_today), ) // 预约排班 .route( "/health/appointments", axum::routing::get(appointment_handler::list_appointments) .post(appointment_handler::create_appointment), ) .route( "/health/appointments/{id}/status", axum::routing::put(appointment_handler::update_appointment_status), ) .route( "/health/doctor-schedules", axum::routing::get(appointment_handler::list_schedules) .post(appointment_handler::create_schedule), ) .route( "/health/doctor-schedules/{id}", axum::routing::put(appointment_handler::update_schedule), ) .route( "/health/doctor-schedules/calendar", axum::routing::get(appointment_handler::calendar_view), ) // 随访管理 .route( "/health/follow-up-tasks", axum::routing::get(follow_up_handler::list_tasks) .post(follow_up_handler::create_task), ) .route( "/health/follow-up-tasks/{id}", axum::routing::put(follow_up_handler::update_task) .delete(follow_up_handler::delete_task), ) .route( "/health/follow-up-tasks/{id}/records", axum::routing::post(follow_up_handler::create_record), ) .route( "/health/follow-up-records", axum::routing::get(follow_up_handler::list_records), ) // 咨询管理 .route( "/health/consultation-sessions", axum::routing::get(consultation_handler::list_sessions) .post(consultation_handler::create_session), ) .route( "/health/consultation-sessions/{id}/messages", axum::routing::get(consultation_handler::list_messages), ) .route( "/health/consultation-sessions/{id}/close", axum::routing::put(consultation_handler::close_session), ) .route( "/health/consultation-messages", axum::routing::post(consultation_handler::create_message), ) .route( "/health/consultation-sessions/export", axum::routing::get(consultation_handler::export_sessions), ) // 医护管理 .route( "/health/doctors", axum::routing::get(doctor_handler::list_doctors) .post(doctor_handler::create_doctor), ) .route( "/health/doctors/{id}", axum::routing::get(doctor_handler::get_doctor) .put(doctor_handler::update_doctor) .delete(doctor_handler::delete_doctor), ) // 健康资讯 .route( "/health/articles", axum::routing::get(article_handler::list_articles), ) .route( "/health/articles/{id}", axum::routing::get(article_handler::get_article), ) } } impl Default for HealthModule { fn default() -> Self { Self::new() } } #[async_trait::async_trait] impl ErpModule for HealthModule { fn name(&self) -> &str { "health" } fn version(&self) -> &str { env!("CARGO_PKG_VERSION") } fn dependencies(&self) -> Vec<&str> { vec!["auth"] } fn register_event_handlers(&self, bus: &EventBus) { crate::event::register_handlers(bus); } async fn on_tenant_created( &self, tenant_id: Uuid, db: &sea_orm::DatabaseConnection, _event_bus: &EventBus, ) -> AppResult<()> { crate::service::seed::seed_tenant_health(db, tenant_id) .await .map_err(|e| erp_core::error::AppError::Internal(e.to_string()))?; tracing::info!(tenant_id = %tenant_id, "Health module tenant initialized"); Ok(()) } async fn on_tenant_deleted( &self, tenant_id: Uuid, db: &sea_orm::DatabaseConnection, ) -> AppResult<()> { crate::service::seed::soft_delete_tenant_data(db, tenant_id) .await .map_err(|e| erp_core::error::AppError::Internal(e.to_string()))?; tracing::info!(tenant_id = %tenant_id, "Health module tenant data soft-deleted"); Ok(()) } fn permissions(&self) -> Vec { vec![ PermissionDescriptor { code: "health.patient.list".into(), name: "查看患者列表".into(), description: "查看和搜索患者列表、详情".into(), module: "health".into(), }, PermissionDescriptor { code: "health.patient.manage".into(), name: "管理患者".into(), description: "创建、编辑、删除患者".into(), module: "health".into(), }, PermissionDescriptor { code: "health.health-data.list".into(), name: "查看健康数据".into(), description: "查看体检记录、监测数据、化验报告".into(), module: "health".into(), }, PermissionDescriptor { code: "health.health-data.manage".into(), name: "管理健康数据".into(), description: "录入、编辑、删除健康数据".into(), module: "health".into(), }, PermissionDescriptor { code: "health.appointment.list".into(), name: "查看预约".into(), description: "查看预约列表和排班".into(), module: "health".into(), }, PermissionDescriptor { code: "health.appointment.manage".into(), name: "管理预约".into(), description: "创建、确认、取消预约".into(), module: "health".into(), }, PermissionDescriptor { code: "health.follow-up.list".into(), name: "查看随访".into(), description: "查看随访任务和记录".into(), module: "health".into(), }, PermissionDescriptor { code: "health.follow-up.manage".into(), name: "管理随访".into(), description: "创建、分配、完成随访任务".into(), module: "health".into(), }, PermissionDescriptor { code: "health.consultation.list".into(), name: "查看咨询".into(), description: "查看咨询会话和消息记录".into(), module: "health".into(), }, PermissionDescriptor { code: "health.consultation.manage".into(), name: "管理咨询".into(), description: "关闭会话、导出记录".into(), module: "health".into(), }, PermissionDescriptor { code: "health.doctor.list".into(), name: "查看医护".into(), description: "查看医护列表和详情".into(), module: "health".into(), }, PermissionDescriptor { code: "health.doctor.manage".into(), name: "管理医护".into(), description: "创建、编辑医护档案、排班".into(), module: "health".into(), }, PermissionDescriptor { code: "health.articles.list".into(), name: "查看资讯".into(), description: "查看健康资讯文章列表和详情".into(), module: "health".into(), }, PermissionDescriptor { code: "health.articles.manage".into(), name: "管理资讯".into(), description: "创建、编辑、删除健康资讯文章".into(), module: "health".into(), }, ] } fn as_any(&self) -> &dyn std::any::Any { self } }