cool_core/
eps.rs

1//! EPS (Endpoint Service) 模块
2//!
3//! 对应 TypeScript 版本的 `rest/eps.ts`,用于对外提供
4//! - 模块信息
5//! - 控制器及其路由信息
6//! - 实体列信息
7//! - 分页查询配置
8//!
9//! Rust 版本暂不做自动扫描,而是提供一个可复用的数据结构和全局注册表,
10//! 由各业务模块在初始化时主动写入。
11
12use once_cell::sync::OnceCell;
13use parking_lot::RwLock;
14use serde::{Deserialize, Serialize};
15use std::collections::HashMap;
16
17/// 模块基础信息
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct ModuleInfo {
20    /// 模块名
21    pub name: String,
22    /// 描述
23    pub description: String,
24}
25
26/// 列信息
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct ColumnInfo {
29    /// 属性名(驼峰)
30    pub property_name: String,
31    /// 字段类型
32    pub r#type: String,
33    /// 长度
34    pub length: Option<u32>,
35    /// 注释
36    pub comment: Option<String>,
37    /// 是否可空
38    pub nullable: bool,
39    /// 默认值
40    pub default_value: Option<String>,
41    /// 字典标记
42    pub dict: Option<serde_json::Value>,
43    /// 原始来源(如 `a.userName`)
44    pub source: String,
45}
46
47/// 查询配置(精简版)
48///
49/// 只保留在前端和 EPS 中需要关注的部分。
50#[derive(Debug, Clone, Serialize, Deserialize, Default)]
51pub struct QueryOpInfo {
52    /// 关键字模糊查询字段
53    pub key_word_like_fields: Vec<String>,
54    /// 字段相等查询
55    pub field_eq: Vec<String>,
56    /// 字段模糊查询
57    pub field_like: Vec<String>,
58    /// 排序配置:(字段名, 是否升序)
59    pub order_by: Vec<(String, bool)>,
60}
61
62/// 路由信息
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct RouteInfo {
65    /// 请求方法:GET/POST/PUT/DELETE...
66    pub method: String,
67    /// URL 路径
68    pub path: String,
69    /// 简要说明
70    pub summary: Option<String>,
71    /// 标签
72    pub tag: Option<String>,
73    /// 是否忽略 Token 校验
74    pub ignore_token: bool,
75}
76
77/// 控制器的 EPS 信息
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct ControllerEps {
80    /// 所属模块
81    pub module: String,
82    /// 路由前缀
83    pub prefix: String,
84    /// 实体名称
85    pub entity_name: Option<String>,
86    /// 类型信息(例如列表类型说明)
87    pub r#type: Option<String>,
88    /// 类型描述
89    pub description: Option<String>,
90    /// 路由列表
91    pub api: Vec<RouteInfo>,
92    /// 实体列信息
93    pub columns: Vec<ColumnInfo>,
94    /// 分页查询配置
95    pub page_query_op: Option<QueryOpInfo>,
96    /// 分页列信息(通常基于 select/join 计算出的平铺列)
97    pub page_columns: Vec<ColumnInfo>,
98}
99
100/// EPS 数据作用域
101#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
102pub enum EpsScope {
103    /// 后台管理端
104    Admin,
105    /// App 端
106    App,
107}
108
109/// EPS 注册表
110///
111/// 与 Node 版本的 `CoolEps` 中 `admin/app/module` 三个字段的结构保持一致。
112#[derive(Default)]
113pub struct EpsRegistry {
114    admin: RwLock<HashMap<String, Vec<ControllerEps>>>,
115    app: RwLock<HashMap<String, Vec<ControllerEps>>>,
116    module: RwLock<HashMap<String, ModuleInfo>>,
117}
118
119impl EpsRegistry {
120    /// 创建新的注册表
121    pub fn new() -> Self {
122        Self::default()
123    }
124
125    /// 注册模块信息
126    pub fn register_module(&self, key: impl Into<String>, info: ModuleInfo) {
127        let mut modules = self.module.write();
128        modules.insert(key.into(), info);
129    }
130
131    /// 注册控制器 EPS 信息
132    pub fn register_controller(
133        &self,
134        scope: EpsScope,
135        module: impl Into<String>,
136        eps: ControllerEps,
137    ) {
138        let module_key = module.into();
139        let target = match scope {
140            EpsScope::Admin => &self.admin,
141            EpsScope::App => &self.app,
142        };
143        let mut map = target.write();
144        map.entry(module_key).or_default().push(eps);
145    }
146
147    /// 获取后台端的 EPS 数据(按模块分组)
148    pub fn admin_eps(&self) -> HashMap<String, Vec<ControllerEps>> {
149        self.admin.read().clone()
150    }
151
152    /// 获取 App 端的 EPS 数据(按模块分组)
153    pub fn app_eps(&self) -> HashMap<String, Vec<ControllerEps>> {
154        self.app.read().clone()
155    }
156
157    /// 获取模块基础信息
158    pub fn modules(&self) -> HashMap<String, ModuleInfo> {
159        self.module.read().clone()
160    }
161}
162
163static GLOBAL_EPS_REGISTRY: OnceCell<EpsRegistry> = OnceCell::new();
164
165/// 获取全局 EPS 注册表
166pub fn global_eps_registry() -> &'static EpsRegistry {
167    GLOBAL_EPS_REGISTRY.get_or_init(EpsRegistry::default)
168}
169
170/// EPS HTTP 处理器(可选 Web 集成)
171///
172/// 对应 TS 版本中的 `/eps` 接口,用于向前端暴露:
173/// - 模块基础信息
174/// - Admin/App 端的控制器 EPS 列表
175///
176/// 路由推荐:
177/// - GET `/admin/eps`
178/// - GET `/app/eps`
179#[cfg(feature = "web")]
180pub mod handler {
181    use super::*;
182    use salvo::prelude::*;
183    use serde_json::json;
184
185    /// 获取后台管理端 EPS 数据
186    #[handler]
187    pub async fn admin_eps(_req: &mut Request, res: &mut Response) {
188        let registry = global_eps_registry();
189        let data = json!({
190            "modules": registry.modules(),
191            "eps": registry.admin_eps(),
192        });
193        res.render(Json(data));
194    }
195
196    /// 获取 App 端 EPS 数据
197    #[handler]
198    pub async fn app_eps(_req: &mut Request, res: &mut Response) {
199        let registry = global_eps_registry();
200        let data = json!({
201            "modules": registry.modules(),
202            "eps": registry.app_eps(),
203        });
204        res.render(Json(data));
205    }
206
207    /// 构建 EPS 路由
208    ///
209    /// 示例:
210    /// ```rust,ignore
211    /// use cool_core::eps::handler::eps_router;
212    /// let router = eps_router("/admin/eps", "/app/eps");
213    /// ```
214    pub fn eps_router(admin_path: &str, app_path: &str) -> salvo::Router {
215        Router::new()
216            .push(Router::with_path(admin_path).get(admin_eps))
217            .push(Router::with_path(app_path).get(app_eps))
218    }
219}