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 { 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() -> Router where crate::state::AiState: axum::extract::FromRef, S: Clone + Send + Sync + 'static, { Router::new() } pub fn protected_routes() -> Router where crate::state::AiState: axum::extract::FromRef, 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), ) } }