- erp-health: article/banner/consultation/media 服务层优化 - erp-ai: analysis/insight/prompt 服务增强 - erp-auth: auth/role/token 服务改进 - erp-workflow: executor 执行引擎修复 - erp-plugin: 服务层改进 - 新增媒体上传文件样例
132 lines
4.5 KiB
Rust
132 lines
4.5 KiB
Rust
use crate::entity::copilot_insights;
|
|
use erp_core::error::AppResult;
|
|
use sea_orm::{
|
|
ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, Set,
|
|
};
|
|
use uuid::Uuid;
|
|
|
|
pub struct InsightService;
|
|
|
|
impl InsightService {
|
|
/// 创建洞察记录
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub async fn create_insight(
|
|
db: &sea_orm::DatabaseConnection,
|
|
tenant_id: Uuid,
|
|
patient_id: Uuid,
|
|
insight_type: String,
|
|
source: String,
|
|
severity: Option<String>,
|
|
title: String,
|
|
content: serde_json::Value,
|
|
rule_matches: Option<serde_json::Value>,
|
|
expires_hours: i64,
|
|
created_by: Option<Uuid>,
|
|
) -> AppResult<Uuid> {
|
|
let id = Uuid::now_v7();
|
|
let now = chrono::Utc::now();
|
|
let model = copilot_insights::ActiveModel {
|
|
id: Set(id),
|
|
tenant_id: Set(tenant_id),
|
|
patient_id: Set(patient_id),
|
|
insight_type: Set(insight_type),
|
|
source: Set(source),
|
|
severity: Set(severity),
|
|
title: Set(title),
|
|
content: Set(content),
|
|
rule_matches: Set(rule_matches),
|
|
llm_supplement: Set(None),
|
|
expires_at: Set(now + chrono::Duration::hours(expires_hours)),
|
|
is_read: Set(false),
|
|
is_dismissed: Set(false),
|
|
created_at: Set(now),
|
|
updated_at: Set(now),
|
|
created_by: Set(created_by),
|
|
updated_by: Set(created_by),
|
|
deleted_at: Set(None),
|
|
version_lock: Set(1),
|
|
};
|
|
model.insert(db).await?;
|
|
Ok(id)
|
|
}
|
|
|
|
/// 分页查询洞察列表
|
|
pub async fn list_insights(
|
|
db: &sea_orm::DatabaseConnection,
|
|
tenant_id: Uuid,
|
|
patient_id: Option<Uuid>,
|
|
insight_type: Option<String>,
|
|
severity: Option<String>,
|
|
page: u64,
|
|
page_size: u64,
|
|
) -> AppResult<(Vec<copilot_insights::Model>, u64)> {
|
|
let mut query = copilot_insights::Entity::find()
|
|
.filter(copilot_insights::Column::TenantId.eq(tenant_id))
|
|
.filter(copilot_insights::Column::DeletedAt.is_null())
|
|
.filter(copilot_insights::Column::IsDismissed.eq(false));
|
|
|
|
if let Some(pid) = patient_id {
|
|
query = query.filter(copilot_insights::Column::PatientId.eq(pid));
|
|
}
|
|
if let Some(ref t) = insight_type {
|
|
query = query.filter(copilot_insights::Column::InsightType.eq(t.as_str()));
|
|
}
|
|
if let Some(ref s) = severity {
|
|
query = query.filter(copilot_insights::Column::Severity.eq(s.as_str()));
|
|
}
|
|
|
|
let total = query.clone().count(db).await?;
|
|
let items = query
|
|
.order_by_desc(copilot_insights::Column::CreatedAt)
|
|
.paginate(db, page_size)
|
|
.fetch_page(page.saturating_sub(1))
|
|
.await?;
|
|
|
|
Ok((items, total))
|
|
}
|
|
|
|
/// 标记洞察已处理
|
|
pub async fn dismiss_insight(
|
|
db: &sea_orm::DatabaseConnection,
|
|
tenant_id: Uuid,
|
|
insight_id: Uuid,
|
|
updated_by: Option<Uuid>,
|
|
) -> AppResult<()> {
|
|
let model = copilot_insights::Entity::find()
|
|
.filter(copilot_insights::Column::Id.eq(insight_id))
|
|
.filter(copilot_insights::Column::TenantId.eq(tenant_id))
|
|
.filter(copilot_insights::Column::DeletedAt.is_null())
|
|
.one(db)
|
|
.await?
|
|
.ok_or_else(|| erp_core::error::AppError::NotFound("洞察记录".into()))?;
|
|
|
|
let mut active: copilot_insights::ActiveModel = model.into();
|
|
active.is_dismissed = Set(true);
|
|
active.updated_at = Set(chrono::Utc::now());
|
|
active.updated_by = Set(updated_by);
|
|
active.version_lock = Set(active.version_lock.unwrap() + 1);
|
|
active.update(db).await?;
|
|
Ok(())
|
|
}
|
|
|
|
/// 清理过期洞察
|
|
pub async fn cleanup_expired(db: &sea_orm::DatabaseConnection) -> AppResult<u64> {
|
|
let now = chrono::Utc::now();
|
|
let expired = copilot_insights::Entity::find()
|
|
.filter(copilot_insights::Column::ExpiresAt.lte(now))
|
|
.filter(copilot_insights::Column::DeletedAt.is_null())
|
|
.all(db)
|
|
.await?;
|
|
|
|
let count = expired.len() as u64;
|
|
for model in expired {
|
|
let mut active: copilot_insights::ActiveModel = model.into();
|
|
active.deleted_at = Set(Some(now));
|
|
active.updated_at = Set(now);
|
|
active.version_lock = Set(active.version_lock.unwrap() + 1);
|
|
active.update(db).await?;
|
|
}
|
|
Ok(count)
|
|
}
|
|
}
|