Files
hms/crates/erp-ai/src/module.rs
iven 876308596a
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
feat(ai): 补全 Prompt CRUD + 分析历史 + 用量统计 handler 和路由
- 替换 list_analysis/get_analysis 空壳为真实查询
- 新增 list_prompts/create_prompt/activate_prompt/rollback_prompt
- 新增 usage_overview/usage_by_type
- 注册 6 个新路由到 AiModule
2026-04-25 23:21:11 +08:00

133 lines
4.1 KiB
Rust

use async_trait::async_trait;
use axum::Router;
use erp_core::module::{ErpModule, ModuleType, PermissionDescriptor};
use std::any::Any;
pub struct AiModule;
#[async_trait]
impl ErpModule for AiModule {
fn name(&self) -> &str {
"ai"
}
fn module_type(&self) -> ModuleType {
ModuleType::Builtin
}
fn dependencies(&self) -> Vec<&str> {
vec!["health"]
}
fn permissions(&self) -> Vec<PermissionDescriptor> {
vec![
PermissionDescriptor {
code: "ai.analysis.list".into(),
name: "查看分析历史".into(),
description: "查看 AI 分析结果历史记录".into(),
module: "ai".into(),
},
PermissionDescriptor {
code: "ai.analysis.manage".into(),
name: "请求分析".into(),
description: "发起 AI 分析请求".into(),
module: "ai".into(),
},
PermissionDescriptor {
code: "ai.prompt.list".into(),
name: "查看 Prompt".into(),
description: "查看 AI Prompt 模板列表".into(),
module: "ai".into(),
},
PermissionDescriptor {
code: "ai.prompt.manage".into(),
name: "管理 Prompt".into(),
description: "创建/编辑/激活/回滚 Prompt 模板".into(),
module: "ai".into(),
},
PermissionDescriptor {
code: "ai.usage.list".into(),
name: "查看用量".into(),
description: "查看 AI 用量统计".into(),
module: "ai".into(),
},
PermissionDescriptor {
code: "ai.provider.manage".into(),
name: "管理提供商".into(),
description: "管理 AI 提供商配置".into(),
module: "ai".into(),
},
]
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl AiModule {
pub fn public_routes<S>() -> Router<S>
where
crate::state::AiState: axum::extract::FromRef<S>,
S: Clone + Send + Sync + 'static,
{
Router::new()
}
pub fn protected_routes<S>() -> Router<S>
where
crate::state::AiState: axum::extract::FromRef<S>,
S: Clone + Send + Sync + 'static,
{
Router::new()
.route(
"/ai/analyze/lab-report",
axum::routing::post(crate::handler::stream_lab_report),
)
.route(
"/ai/analyze/trends",
axum::routing::post(crate::handler::stream_trends),
)
.route(
"/ai/analyze/checkup-plan",
axum::routing::post(crate::handler::stream_checkup_plan),
)
.route(
"/ai/analyze/report-summary",
axum::routing::post(crate::handler::stream_report_summary),
)
.route(
"/ai/analysis/history",
axum::routing::get(crate::handler::list_analysis),
)
.route(
"/ai/analysis/{id}",
axum::routing::get(crate::handler::get_analysis),
)
.route(
"/ai/prompts",
axum::routing::get(crate::handler::list_prompts),
)
.route(
"/ai/prompts",
axum::routing::post(crate::handler::create_prompt),
)
.route(
"/ai/prompts/{id}/activate",
axum::routing::post(crate::handler::activate_prompt),
)
.route(
"/ai/prompts/{id}/rollback",
axum::routing::post(crate::handler::rollback_prompt),
)
.route(
"/ai/usage/overview",
axum::routing::get(crate::handler::usage_overview),
)
.route(
"/ai/usage/by-type",
axum::routing::get(crate::handler::usage_by_type),
)
}
}