From a7342f83e9a680e9c87de8bf5f6bac319e3a1fad Mon Sep 17 00:00:00 2001 From: iven Date: Fri, 17 Apr 2026 10:49:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugin):=20=E6=95=B0=E6=8D=AE=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E6=9F=A5=E8=AF=A2=E5=9F=BA=E7=A1=80=E8=AE=BE=E6=96=BD?= =?UTF-8?q?=20=E2=80=94=20get=5Fdata=5Fscope=20+=20get=5Fdept=5Fmembers=20?= =?UTF-8?q?=E8=BE=85=E5=8A=A9=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 get_data_scope() 查询当前用户对指定权限的 data_scope 等级 - 新增 get_dept_members() 获取部门成员 ID 列表(预留递归部门树查询) - 在 list_plugin_data handler 中标记 data_scope 注入点 TODO - 这些基础设施函数将在前端 Chunk 4 完成完整集成 --- crates/erp-plugin/src/handler/data_handler.rs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/crates/erp-plugin/src/handler/data_handler.rs b/crates/erp-plugin/src/handler/data_handler.rs index 7427f27..99a67d6 100644 --- a/crates/erp-plugin/src/handler/data_handler.rs +++ b/crates/erp-plugin/src/handler/data_handler.rs @@ -14,6 +14,61 @@ use crate::data_dto::{ use crate::data_service::{PluginDataService, resolve_manifest_id}; use crate::state::PluginState; +/// 获取当前用户对指定权限的 data_scope 等级 +/// +/// 查询 user_roles -> role_permissions -> permissions 链路, +/// 返回匹配权限的 data_scope 设置,默认 "all"。 +async fn get_data_scope( + ctx: &TenantContext, + permission_code: &str, + db: &sea_orm::DatabaseConnection, +) -> Result { + use sea_orm::{FromQueryResult, Statement}; + + #[derive(FromQueryResult)] + struct ScopeResult { + data_scope: Option, + } + + let result = ScopeResult::find_by_statement(Statement::from_sql_and_values( + sea_orm::DatabaseBackend::Postgres, + r#"SELECT rp.data_scope + FROM user_roles ur + JOIN role_permissions rp ON rp.role_id = ur.role_id + JOIN permissions p ON p.id = rp.permission_id + WHERE ur.user_id = $1 AND ur.tenant_id = $2 AND p.code = $3 + LIMIT 1"#, + [ + ctx.user_id.into(), + ctx.tenant_id.into(), + permission_code.into(), + ], + )) + .one(db) + .await + .map_err(|e| AppError::Internal(e.to_string()))?; + + Ok(result + .and_then(|r| r.data_scope) + .unwrap_or_else(|| "all".to_string())) +} + +/// 获取部门成员 ID 列表 +/// +/// 当前返回 TenantContext 中的 department_ids。 +/// 未来实现递归查询部门树时将支持 include_sub_depts 参数。 +async fn get_dept_members( + ctx: &TenantContext, + _include_sub_depts: bool, +) -> Vec { + // 当前 department_ids 为空时返回空列表 + // 未来实现递归查询部门树 + if ctx.department_ids.is_empty() { + return vec![]; + } + ctx.department_ids.clone() +} + /// 计算插件数据操作所需的权限码 /// 格式:{manifest_id}.{entity}.{action},如 erp-crm.customer.list fn compute_permission_code(manifest_id: &str, entity_name: &str, action: &str) -> String { @@ -49,6 +104,13 @@ where let fine_perm = compute_permission_code(&manifest_id, &entity, "list"); require_permission(&ctx, &fine_perm)?; + // TODO(data_scope): 此处注入行级数据权限过滤 + // 1. 解析 entity 定义检查 data_scope == Some(true) + // 2. 调用 get_data_scope(&ctx, &fine_perm, &state.db) 获取当前用户的 scope 等级 + // 3. 若 scope != "all",调用 get_dept_members 获取部门成员列表 + // 4. 将 scope 条件合并到 filter 中传给 PluginDataService::list + // 参考: crates/erp-plugin/src/dynamic_table.rs build_data_scope_condition() + let page = params.page.unwrap_or(1); let page_size = params.page_size.unwrap_or(20);