feat(plugin): 集成过滤查询/排序/搜索到 REST API,添加数据校验和 searchable 索引

- data_dto: PluginDataListParams 新增 filter/sort_by/sort_order
- data_service: list 方法支持 filter/search/sort 参数,自动提取 searchable 字段
- data_service: create/update 添加 required 字段校验
- data_service: 新增 resolve_entity_fields 和 validate_data 辅助函数
- data_handler: 权限检查从硬编码改为动态计算 plugin_id.entity.action
- dynamic_table: searchable 字段自动创建 B-tree 索引
This commit is contained in:
iven
2026-04-16 12:31:53 +08:00
parent 472bf244d8
commit 0ad77693f4
4 changed files with 151 additions and 18 deletions

View File

@@ -11,6 +11,16 @@ use crate::data_dto::{CreatePluginDataReq, PluginDataListParams, PluginDataResp,
use crate::data_service::PluginDataService;
use crate::state::PluginState;
/// 计算插件数据操作所需的权限码
/// 格式:{plugin_id}.{entity}.{action},如 crm.customer.list
fn compute_permission_code(plugin_id: &str, entity_name: &str, action: &str) -> String {
let action_suffix = match action {
"list" | "get" => "list",
_ => "manage",
};
format!("{}.{}.{}", plugin_id, entity_name, action_suffix)
}
#[utoipa::path(
get,
path = "/api/v1/plugins/{plugin_id}/{entity}",
@@ -32,11 +42,21 @@ where
PluginState: FromRef<S>,
S: Clone + Send + Sync + 'static,
{
require_permission(&ctx, "plugin.list")?;
// 动态权限检查:先尝试精细权限,回退到通用权限
let fine_perm = compute_permission_code(&plugin_id.to_string(), &entity, "list");
if require_permission(&ctx, &fine_perm).is_err() {
require_permission(&ctx, "plugin.list")?;
}
let page = params.page.unwrap_or(1);
let page_size = params.page_size.unwrap_or(20);
// 解析 filter JSON
let filter: Option<serde_json::Value> = params
.filter
.as_ref()
.and_then(|f| serde_json::from_str(f).ok());
let (items, total) = PluginDataService::list(
plugin_id,
&entity,
@@ -44,6 +64,10 @@ where
page,
page_size,
&state.db,
filter,
params.search,
params.sort_by,
params.sort_order,
)
.await?;
@@ -77,7 +101,10 @@ where
PluginState: FromRef<S>,
S: Clone + Send + Sync + 'static,
{
require_permission(&ctx, "plugin.admin")?;
let fine_perm = compute_permission_code(&plugin_id.to_string(), &entity, "create");
if require_permission(&ctx, &fine_perm).is_err() {
require_permission(&ctx, "plugin.admin")?;
}
let result = PluginDataService::create(
plugin_id,
@@ -112,7 +139,10 @@ where
PluginState: FromRef<S>,
S: Clone + Send + Sync + 'static,
{
require_permission(&ctx, "plugin.list")?;
let fine_perm = compute_permission_code(&plugin_id.to_string(), &entity, "get");
if require_permission(&ctx, &fine_perm).is_err() {
require_permission(&ctx, "plugin.list")?;
}
let result =
PluginDataService::get_by_id(plugin_id, &entity, id, ctx.tenant_id, &state.db).await?;
@@ -141,7 +171,10 @@ where
PluginState: FromRef<S>,
S: Clone + Send + Sync + 'static,
{
require_permission(&ctx, "plugin.admin")?;
let fine_perm = compute_permission_code(&plugin_id.to_string(), &entity, "update");
if require_permission(&ctx, &fine_perm).is_err() {
require_permission(&ctx, "plugin.admin")?;
}
let result = PluginDataService::update(
plugin_id,
@@ -178,7 +211,10 @@ where
PluginState: FromRef<S>,
S: Clone + Send + Sync + 'static,
{
require_permission(&ctx, "plugin.admin")?;
let fine_perm = compute_permission_code(&plugin_id.to_string(), &entity, "delete");
if require_permission(&ctx, &fine_perm).is_err() {
require_permission(&ctx, "plugin.admin")?;
}
PluginDataService::delete(
plugin_id,