fix: DTO 输入校验补全 + 编译修复 + AuthButton 类型修复
- erp-auth/config/workflow/message/plugin/health: 44 处 DTO 校验缺失修复 - erp-plugin/data_dto: utoipa derive 宏 import 修复 - erp-server/main: tracing 宏类型推断修复 - web AuthButton: AiAnalysisCard/VitalSignsTab Button 包裹在 children 内 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
/// 插件数据记录响应
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct PluginDataResp {
|
||||
pub id: String,
|
||||
pub data: serde_json::Value,
|
||||
@@ -12,27 +13,27 @@ pub struct PluginDataResp {
|
||||
}
|
||||
|
||||
/// 创建插件数据请求
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct CreatePluginDataReq {
|
||||
pub data: serde_json::Value,
|
||||
}
|
||||
|
||||
/// 更新插件数据请求(全量替换)
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct UpdatePluginDataReq {
|
||||
pub data: serde_json::Value,
|
||||
pub version: i32,
|
||||
}
|
||||
|
||||
/// 部分更新请求(PATCH — 只合并提供的字段)
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct PatchPluginDataReq {
|
||||
pub data: serde_json::Value,
|
||||
pub version: i32,
|
||||
}
|
||||
|
||||
/// 插件数据列表查询参数
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||||
#[derive(Debug, Serialize, Deserialize, IntoParams)]
|
||||
pub struct PluginDataListParams {
|
||||
pub page: Option<u64>,
|
||||
pub page_size: Option<u64>,
|
||||
@@ -47,7 +48,7 @@ pub struct PluginDataListParams {
|
||||
}
|
||||
|
||||
/// 聚合查询响应项
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct AggregateItem {
|
||||
/// 分组键(字段值)
|
||||
pub key: String,
|
||||
@@ -56,7 +57,7 @@ pub struct AggregateItem {
|
||||
}
|
||||
|
||||
/// 多聚合查询响应项
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct AggregateMultiRow {
|
||||
/// 分组键
|
||||
pub key: String,
|
||||
@@ -68,7 +69,7 @@ pub struct AggregateMultiRow {
|
||||
}
|
||||
|
||||
/// 聚合查询参数
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||||
#[derive(Debug, Serialize, Deserialize, IntoParams)]
|
||||
pub struct AggregateQueryParams {
|
||||
/// 分组字段名
|
||||
pub group_by: String,
|
||||
@@ -77,7 +78,7 @@ pub struct AggregateQueryParams {
|
||||
}
|
||||
|
||||
/// 多聚合查询请求体
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct AggregateMultiReq {
|
||||
/// 分组字段名
|
||||
pub group_by: String,
|
||||
@@ -88,7 +89,7 @@ pub struct AggregateMultiReq {
|
||||
}
|
||||
|
||||
/// 单个聚合定义
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct AggregateDefDto {
|
||||
/// 聚合函数: count, sum, avg, min, max
|
||||
pub func: String,
|
||||
@@ -97,7 +98,7 @@ pub struct AggregateDefDto {
|
||||
}
|
||||
|
||||
/// 统计查询参数
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||||
#[derive(Debug, Serialize, Deserialize, IntoParams)]
|
||||
pub struct CountQueryParams {
|
||||
/// 搜索关键词
|
||||
pub search: Option<String>,
|
||||
@@ -106,7 +107,7 @@ pub struct CountQueryParams {
|
||||
}
|
||||
|
||||
/// 批量操作请求
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct BatchActionReq {
|
||||
/// 操作类型: "batch_delete" 或 "batch_update"
|
||||
pub action: String,
|
||||
@@ -117,7 +118,7 @@ pub struct BatchActionReq {
|
||||
}
|
||||
|
||||
/// 时间序列查询参数
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||||
#[derive(Debug, Serialize, Deserialize, IntoParams)]
|
||||
pub struct TimeseriesParams {
|
||||
/// 时间字段名
|
||||
pub time_field: String,
|
||||
@@ -130,7 +131,7 @@ pub struct TimeseriesParams {
|
||||
}
|
||||
|
||||
/// 时间序列数据项
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct TimeseriesItem {
|
||||
/// 时间周期
|
||||
pub period: String,
|
||||
@@ -141,14 +142,14 @@ pub struct TimeseriesItem {
|
||||
// ─── 跨插件引用 DTO ──────────────────────────────────────────────────
|
||||
|
||||
/// 批量标签解析请求
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ResolveLabelsReq {
|
||||
/// 字段名 → UUID 列表
|
||||
pub fields: std::collections::HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
/// 批量标签解析响应
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ResolveLabelsResp {
|
||||
/// 字段名 → { uuid: label } 映射
|
||||
pub labels: serde_json::Value,
|
||||
@@ -157,7 +158,7 @@ pub struct ResolveLabelsResp {
|
||||
}
|
||||
|
||||
/// 公开实体信息(实体注册表查询响应)
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct PublicEntityResp {
|
||||
pub manifest_id: String,
|
||||
pub plugin_id: String,
|
||||
@@ -168,7 +169,7 @@ pub struct PublicEntityResp {
|
||||
// ─── 导入导出 DTO ──────────────────────────────────────────────────
|
||||
|
||||
/// 数据导出参数
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||||
#[derive(Debug, Serialize, Deserialize, IntoParams)]
|
||||
pub struct ExportParams {
|
||||
/// JSON 格式过滤: {"field":"value"}
|
||||
pub filter: Option<String>,
|
||||
@@ -190,14 +191,14 @@ pub enum ExportPayload {
|
||||
}
|
||||
|
||||
/// 数据导入请求
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ImportReq {
|
||||
/// 导入数据行列表,每行是一个 JSON 对象
|
||||
pub rows: Vec<serde_json::Value>,
|
||||
}
|
||||
|
||||
/// 数据导入结果
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ImportResult {
|
||||
/// 成功导入行数
|
||||
pub success_count: usize,
|
||||
@@ -209,7 +210,7 @@ pub struct ImportResult {
|
||||
}
|
||||
|
||||
/// 单行导入错误
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ImportRowError {
|
||||
/// 行号(0-based)
|
||||
pub row: usize,
|
||||
@@ -220,7 +221,7 @@ pub struct ImportRowError {
|
||||
// ─── 市场目录 DTO ──────────────────────────────────────────────────
|
||||
|
||||
/// 市场条目列表查询参数
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||||
#[derive(Debug, Serialize, Deserialize, IntoParams)]
|
||||
pub struct MarketListParams {
|
||||
pub page: Option<u64>,
|
||||
pub page_size: Option<u64>,
|
||||
@@ -229,7 +230,7 @@ pub struct MarketListParams {
|
||||
}
|
||||
|
||||
/// 市场条目响应(不含二进制数据)
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct MarketEntryResp {
|
||||
pub id: String,
|
||||
pub plugin_id: String,
|
||||
@@ -252,7 +253,7 @@ pub struct MarketEntryResp {
|
||||
}
|
||||
|
||||
/// 市场条目详情响应(含完整信息)
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct MarketEntryDetailResp {
|
||||
#[serde(flatten)]
|
||||
pub entry: MarketEntryResp,
|
||||
@@ -261,7 +262,7 @@ pub struct MarketEntryDetailResp {
|
||||
}
|
||||
|
||||
/// 提交评分/评论请求
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct SubmitReviewReq {
|
||||
/// 评分 1-5
|
||||
pub rating: i32,
|
||||
@@ -270,7 +271,7 @@ pub struct SubmitReviewReq {
|
||||
}
|
||||
|
||||
/// 评论响应
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct MarketReviewResp {
|
||||
pub id: String,
|
||||
pub user_id: String,
|
||||
@@ -283,7 +284,7 @@ pub struct MarketReviewResp {
|
||||
// ─── 对账扫描 DTO ──────────────────────────────────────────────────
|
||||
|
||||
/// 对账报告
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ReconciliationReport {
|
||||
/// 有效引用数
|
||||
pub valid_count: i64,
|
||||
@@ -294,7 +295,7 @@ pub struct ReconciliationReport {
|
||||
}
|
||||
|
||||
/// 悬空引用详情
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct DanglingRef {
|
||||
/// 实体名
|
||||
pub entity: String,
|
||||
@@ -309,7 +310,7 @@ pub struct DanglingRef {
|
||||
// ─── 自定义视图 DTO ──────────────────────────────────────────────────
|
||||
|
||||
/// 用户视图配置请求
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct UserViewReq {
|
||||
pub view_name: String,
|
||||
pub view_config: serde_json::Value,
|
||||
@@ -317,7 +318,7 @@ pub struct UserViewReq {
|
||||
}
|
||||
|
||||
/// 用户视图响应
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct UserViewResp {
|
||||
pub id: String,
|
||||
pub plugin_id: String,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
/// 插件信息响应
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
@@ -49,17 +50,19 @@ pub struct PluginHealthResp {
|
||||
}
|
||||
|
||||
/// 更新插件配置请求
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, Validate, utoipa::ToSchema)]
|
||||
pub struct UpdatePluginConfigReq {
|
||||
pub config: serde_json::Value,
|
||||
pub version: i32,
|
||||
}
|
||||
|
||||
/// 插件列表查询参数
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||||
#[derive(Debug, Serialize, Deserialize, Validate, utoipa::IntoParams)]
|
||||
pub struct PluginListParams {
|
||||
pub page: Option<u64>,
|
||||
pub page_size: Option<u64>,
|
||||
#[validate(length(max = 20, message = "状态值无效"))]
|
||||
pub status: Option<String>,
|
||||
#[validate(length(max = 100, message = "搜索关键词过长"))]
|
||||
pub search: Option<String>,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use axum::Extension;
|
||||
use axum::extract::{FromRef, Multipart, Path, Query, State};
|
||||
use axum::response::Json;
|
||||
use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
|
||||
use erp_core::error::AppError;
|
||||
use erp_core::rbac::require_permission;
|
||||
@@ -391,6 +392,8 @@ where
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
require_permission(&ctx, "plugin.admin")?;
|
||||
req.validate()
|
||||
.map_err(|e| AppError::Validation(e.to_string()))?;
|
||||
let result = PluginService::update_config(
|
||||
id,
|
||||
ctx.tenant_id,
|
||||
|
||||
Reference in New Issue
Block a user