功能修复: 1. 患者创建空名称验证:后端添加 name.trim().is_empty() 检查 2. 仪表盘统计容错:单个查询失败返回零值而非 500 3. FHIR 路由修复:从 /fhir 移到 /api/v1/fhir 保持一致 4. 冻结模块后端中间件:新增 frozen_module_middleware 拦截冻结路径 5. 积分端点权限码:health.health-data.list → health.points.list 6. 角色权限迁移:护士补充 devices.list,运营补充 points.list/manage 7. 测试结果文档:R01-R05 角色测试 + T00/T10 结果归档 Clippy 全 workspace 清零(14→0 errors): - erp-core: 修复 empty doc line、collapsible if、redundant closure 等 9 处 - erp-health: 修复 too_many_arguments、unused var、unnecessary parens 等 58 处 - erp-ai: 修复 dead_code、unused import 等 11 处 - erp-plugin: 修复 too_many_arguments、wildcard pattern 等 11 处 - erp-server-migration: 修复 enum_variant_names 5 处 - erp-auth/config/workflow/message: 各 1-3 处 工程改进: - lint-staged 配置迁移到 .lintstagedrc.js(函数式避免文件列表传给 clippy) - cargo fmt 统一格式化
201 lines
7.2 KiB
Rust
201 lines
7.2 KiB
Rust
use async_trait::async_trait;
|
|
use axum::Router;
|
|
use axum::routing::{delete, get, post, put};
|
|
use erp_core::module::{ErpModule, PermissionDescriptor};
|
|
|
|
pub struct PluginModule;
|
|
|
|
#[async_trait]
|
|
impl ErpModule for PluginModule {
|
|
fn name(&self) -> &str {
|
|
"plugin"
|
|
}
|
|
|
|
fn dependencies(&self) -> Vec<&str> {
|
|
vec!["auth", "config"]
|
|
}
|
|
|
|
fn permissions(&self) -> Vec<PermissionDescriptor> {
|
|
vec![
|
|
PermissionDescriptor {
|
|
code: "plugin.admin".into(),
|
|
name: "插件管理".into(),
|
|
description: "管理插件全生命周期".into(),
|
|
module: "plugin".into(),
|
|
},
|
|
PermissionDescriptor {
|
|
code: "plugin.list".into(),
|
|
name: "查看插件".into(),
|
|
description: "查看插件列表".into(),
|
|
module: "plugin".into(),
|
|
},
|
|
]
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl PluginModule {
|
|
/// 插件管理路由(需要 JWT 认证)
|
|
pub fn protected_routes<S>() -> Router<S>
|
|
where
|
|
crate::state::PluginState: axum::extract::FromRef<S>,
|
|
S: Clone + Send + Sync + 'static,
|
|
{
|
|
let admin_routes = Router::new()
|
|
.route(
|
|
"/admin/plugins/upload",
|
|
post(crate::handler::plugin_handler::upload_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins",
|
|
get(crate::handler::plugin_handler::list_plugins::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}",
|
|
get(crate::handler::plugin_handler::get_plugin::<S>)
|
|
.delete(crate::handler::plugin_handler::purge_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/schema",
|
|
get(crate::handler::plugin_handler::get_plugin_schema::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/install",
|
|
post(crate::handler::plugin_handler::install_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/enable",
|
|
post(crate::handler::plugin_handler::enable_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/disable",
|
|
post(crate::handler::plugin_handler::disable_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/uninstall",
|
|
post(crate::handler::plugin_handler::uninstall_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/health",
|
|
get(crate::handler::plugin_handler::health_check_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/metrics",
|
|
get(crate::handler::plugin_handler::get_plugin_metrics::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/config",
|
|
put(crate::handler::plugin_handler::update_plugin_config::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/upgrade",
|
|
post(crate::handler::plugin_handler::upgrade_plugin::<S>),
|
|
)
|
|
.route(
|
|
"/admin/plugins/{id}/validate",
|
|
get(crate::handler::plugin_handler::validate_plugin::<S>),
|
|
);
|
|
|
|
// 插件数据 CRUD 路由
|
|
let data_routes = Router::new()
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}",
|
|
get(crate::handler::data_handler::list_plugin_data::<S>)
|
|
.post(crate::handler::data_handler::create_plugin_data::<S>),
|
|
)
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/{id}",
|
|
get(crate::handler::data_handler::get_plugin_data::<S>)
|
|
.put(crate::handler::data_handler::update_plugin_data::<S>)
|
|
.patch(crate::handler::data_handler::patch_plugin_data::<S>)
|
|
.delete(crate::handler::data_handler::delete_plugin_data::<S>),
|
|
)
|
|
// 数据统计路由
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/count",
|
|
get(crate::handler::data_handler::count_plugin_data::<S>),
|
|
)
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/aggregate",
|
|
get(crate::handler::data_handler::aggregate_plugin_data::<S>),
|
|
)
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/aggregate-multi",
|
|
post(crate::handler::data_handler::aggregate_multi_plugin_data::<S>),
|
|
)
|
|
// 批量操作路由
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/batch",
|
|
post(crate::handler::data_handler::batch_plugin_data::<S>),
|
|
)
|
|
// 时间序列路由
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/timeseries",
|
|
get(crate::handler::data_handler::get_plugin_timeseries::<S>),
|
|
)
|
|
// 跨插件引用:批量标签解析
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/resolve-labels",
|
|
post(crate::handler::data_handler::resolve_ref_labels::<S>),
|
|
)
|
|
// 数据导入导出
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/export",
|
|
get(crate::handler::data_handler::export_plugin_data::<S>),
|
|
)
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/import",
|
|
post(crate::handler::data_handler::import_plugin_data::<S>),
|
|
)
|
|
// 对账扫描
|
|
.route(
|
|
"/plugins/{plugin_id}/reconcile",
|
|
post(crate::handler::data_handler::reconcile_refs::<S>),
|
|
)
|
|
// 用户自定义视图
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/views",
|
|
get(crate::handler::data_handler::list_user_views::<S>)
|
|
.post(crate::handler::data_handler::create_user_view::<S>),
|
|
)
|
|
.route(
|
|
"/plugins/{plugin_id}/{entity}/views/{view_id}",
|
|
delete(crate::handler::data_handler::delete_user_view::<S>),
|
|
);
|
|
|
|
// 实体注册表路由
|
|
let registry_routes = Router::new().route(
|
|
"/plugin-registry/entities",
|
|
get(crate::handler::data_handler::list_public_entities::<S>),
|
|
);
|
|
|
|
// 市场路由
|
|
let market_routes = Router::new()
|
|
.route(
|
|
"/market/entries",
|
|
get(crate::handler::market_handler::list_market_entries::<S>),
|
|
)
|
|
.route(
|
|
"/market/entries/{id}",
|
|
get(crate::handler::market_handler::get_market_entry::<S>),
|
|
)
|
|
.route(
|
|
"/market/entries/{id}/install",
|
|
post(crate::handler::market_handler::install_from_market::<S>),
|
|
)
|
|
.route(
|
|
"/market/entries/{id}/reviews",
|
|
get(crate::handler::market_handler::list_market_reviews::<S>)
|
|
.post(crate::handler::market_handler::submit_market_review::<S>),
|
|
);
|
|
|
|
admin_routes
|
|
.merge(data_routes)
|
|
.merge(registry_routes)
|
|
.merge(market_routes)
|
|
}
|
|
}
|