3.1 配置变更通知:
- update_config 增加 EventBus 参数
- 更新成功后发布 plugin.config.updated 事件
- handler 传入 event_bus
3.2 自定义视图:
- plugin_user_views 表迁移 (id/tenant_id/user_id/plugin_id/entity/view_name/view_config/is_default)
- CRUD API: GET/POST /plugins/{id}/{entity}/views, DELETE /plugins/{id}/{entity}/views/{view_id}
- 默认视图互斥逻辑
331 lines
9.8 KiB
Rust
331 lines
9.8 KiB
Rust
use chrono::{DateTime, Utc};
|
||
use serde::{Deserialize, Serialize};
|
||
|
||
/// 插件数据记录响应
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct PluginDataResp {
|
||
pub id: String,
|
||
pub data: serde_json::Value,
|
||
pub created_at: Option<DateTime<Utc>>,
|
||
pub updated_at: Option<DateTime<Utc>>,
|
||
pub version: Option<i32>,
|
||
}
|
||
|
||
/// 创建插件数据请求
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct CreatePluginDataReq {
|
||
pub data: serde_json::Value,
|
||
}
|
||
|
||
/// 更新插件数据请求(全量替换)
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct UpdatePluginDataReq {
|
||
pub data: serde_json::Value,
|
||
pub version: i32,
|
||
}
|
||
|
||
/// 部分更新请求(PATCH — 只合并提供的字段)
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct PatchPluginDataReq {
|
||
pub data: serde_json::Value,
|
||
pub version: i32,
|
||
}
|
||
|
||
/// 插件数据列表查询参数
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||
pub struct PluginDataListParams {
|
||
pub page: Option<u64>,
|
||
pub page_size: Option<u64>,
|
||
/// Base64 编码的游标(用于 Keyset 分页)
|
||
pub cursor: Option<String>,
|
||
pub search: Option<String>,
|
||
/// JSON 格式过滤: {"field":"value"}
|
||
pub filter: Option<String>,
|
||
pub sort_by: Option<String>,
|
||
/// "asc" or "desc"
|
||
pub sort_order: Option<String>,
|
||
}
|
||
|
||
/// 聚合查询响应项
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct AggregateItem {
|
||
/// 分组键(字段值)
|
||
pub key: String,
|
||
/// 计数
|
||
pub count: i64,
|
||
}
|
||
|
||
/// 多聚合查询响应项
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct AggregateMultiRow {
|
||
/// 分组键
|
||
pub key: String,
|
||
/// 计数
|
||
pub count: i64,
|
||
/// 聚合指标: {"sum_amount": 5000.0, "avg_price": 25.5}
|
||
#[serde(default)]
|
||
pub metrics: std::collections::HashMap<String, f64>,
|
||
}
|
||
|
||
/// 聚合查询参数
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||
pub struct AggregateQueryParams {
|
||
/// 分组字段名
|
||
pub group_by: String,
|
||
/// JSON 格式过滤: {"field":"value"}
|
||
pub filter: Option<String>,
|
||
}
|
||
|
||
/// 多聚合查询请求体
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct AggregateMultiReq {
|
||
/// 分组字段名
|
||
pub group_by: String,
|
||
/// 聚合定义列表: [{"func": "sum", "field": "amount"}]
|
||
pub aggregations: Vec<AggregateDefDto>,
|
||
/// JSON 格式过滤
|
||
pub filter: Option<serde_json::Value>,
|
||
}
|
||
|
||
/// 单个聚合定义
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct AggregateDefDto {
|
||
/// 聚合函数: count, sum, avg, min, max
|
||
pub func: String,
|
||
/// 字段名
|
||
pub field: String,
|
||
}
|
||
|
||
/// 统计查询参数
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||
pub struct CountQueryParams {
|
||
/// 搜索关键词
|
||
pub search: Option<String>,
|
||
/// JSON 格式过滤: {"field":"value"}
|
||
pub filter: Option<String>,
|
||
}
|
||
|
||
/// 批量操作请求
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct BatchActionReq {
|
||
/// 操作类型: "batch_delete" 或 "batch_update"
|
||
pub action: String,
|
||
/// 记录 ID 列表(上限 100)
|
||
pub ids: Vec<String>,
|
||
/// batch_update 时的更新数据
|
||
pub data: Option<serde_json::Value>,
|
||
}
|
||
|
||
/// 时间序列查询参数
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||
pub struct TimeseriesParams {
|
||
/// 时间字段名
|
||
pub time_field: String,
|
||
/// 时间粒度: "day" / "week" / "month"
|
||
pub time_grain: String,
|
||
/// 开始日期 (ISO)
|
||
pub start: Option<String>,
|
||
/// 结束日期 (ISO)
|
||
pub end: Option<String>,
|
||
}
|
||
|
||
/// 时间序列数据项
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct TimeseriesItem {
|
||
/// 时间周期
|
||
pub period: String,
|
||
/// 计数
|
||
pub count: i64,
|
||
}
|
||
|
||
// ─── 跨插件引用 DTO ──────────────────────────────────────────────────
|
||
|
||
/// 批量标签解析请求
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct ResolveLabelsReq {
|
||
/// 字段名 → UUID 列表
|
||
pub fields: std::collections::HashMap<String, Vec<String>>,
|
||
}
|
||
|
||
/// 批量标签解析响应
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct ResolveLabelsResp {
|
||
/// 字段名 → { uuid: label } 映射
|
||
pub labels: serde_json::Value,
|
||
/// 字段名 → 目标插件元信息
|
||
pub meta: serde_json::Value,
|
||
}
|
||
|
||
/// 公开实体信息(实体注册表查询响应)
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct PublicEntityResp {
|
||
pub manifest_id: String,
|
||
pub plugin_id: String,
|
||
pub entity_name: String,
|
||
pub display_name: String,
|
||
}
|
||
|
||
// ─── 导入导出 DTO ──────────────────────────────────────────────────
|
||
|
||
/// 数据导出参数
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||
pub struct ExportParams {
|
||
/// JSON 格式过滤: {"field":"value"}
|
||
pub filter: Option<String>,
|
||
/// 搜索关键词
|
||
pub search: Option<String>,
|
||
/// 排序字段
|
||
pub sort_by: Option<String>,
|
||
/// "asc" or "desc"
|
||
pub sort_order: Option<String>,
|
||
/// 导出格式: "json" (默认) | "csv" | "xlsx"
|
||
pub format: Option<String>,
|
||
}
|
||
|
||
/// 导出结果 — 根据格式返回不同内容
|
||
pub enum ExportPayload {
|
||
Json(Vec<serde_json::Value>),
|
||
Csv(Vec<u8>),
|
||
Xlsx(Vec<u8>),
|
||
}
|
||
|
||
/// 数据导入请求
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct ImportReq {
|
||
/// 导入数据行列表,每行是一个 JSON 对象
|
||
pub rows: Vec<serde_json::Value>,
|
||
}
|
||
|
||
/// 数据导入结果
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct ImportResult {
|
||
/// 成功导入行数
|
||
pub success_count: usize,
|
||
/// 失败行数
|
||
pub error_count: usize,
|
||
/// 每行错误详情: [{ row: 0, errors: ["字段 xxx 必填"] }]
|
||
#[serde(default)]
|
||
pub errors: Vec<ImportRowError>,
|
||
}
|
||
|
||
/// 单行导入错误
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct ImportRowError {
|
||
/// 行号(0-based)
|
||
pub row: usize,
|
||
/// 错误消息列表
|
||
pub errors: Vec<String>,
|
||
}
|
||
|
||
// ─── 市场目录 DTO ──────────────────────────────────────────────────
|
||
|
||
/// 市场条目列表查询参数
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams)]
|
||
pub struct MarketListParams {
|
||
pub page: Option<u64>,
|
||
pub page_size: Option<u64>,
|
||
pub category: Option<String>,
|
||
pub search: Option<String>,
|
||
}
|
||
|
||
/// 市场条目响应(不含二进制数据)
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct MarketEntryResp {
|
||
pub id: String,
|
||
pub plugin_id: String,
|
||
pub name: String,
|
||
pub version: String,
|
||
pub description: Option<String>,
|
||
pub author: Option<String>,
|
||
pub category: Option<String>,
|
||
pub tags: Option<serde_json::Value>,
|
||
pub icon_url: Option<String>,
|
||
pub screenshots: Option<serde_json::Value>,
|
||
pub min_platform_version: Option<String>,
|
||
pub status: String,
|
||
pub download_count: i32,
|
||
pub rating_avg: f64,
|
||
pub rating_count: i32,
|
||
pub changelog: Option<String>,
|
||
pub created_at: Option<chrono::DateTime<chrono::Utc>>,
|
||
pub updated_at: Option<chrono::DateTime<chrono::Utc>>,
|
||
}
|
||
|
||
/// 市场条目详情响应(含完整信息)
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct MarketEntryDetailResp {
|
||
#[serde(flatten)]
|
||
pub entry: MarketEntryResp,
|
||
/// 依赖提示(安装时检查 manifest.dependencies)
|
||
pub dependency_warnings: Vec<String>,
|
||
}
|
||
|
||
/// 提交评分/评论请求
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct SubmitReviewReq {
|
||
/// 评分 1-5
|
||
pub rating: i32,
|
||
/// 评论内容
|
||
pub review_text: Option<String>,
|
||
}
|
||
|
||
/// 评论响应
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct MarketReviewResp {
|
||
pub id: String,
|
||
pub user_id: String,
|
||
pub market_entry_id: String,
|
||
pub rating: i32,
|
||
pub review_text: Option<String>,
|
||
pub created_at: Option<chrono::DateTime<chrono::Utc>>,
|
||
}
|
||
|
||
// ─── 对账扫描 DTO ──────────────────────────────────────────────────
|
||
|
||
/// 对账报告
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct ReconciliationReport {
|
||
/// 有效引用数
|
||
pub valid_count: i64,
|
||
/// 悬空引用数
|
||
pub dangling_count: i64,
|
||
/// 悬空引用详情
|
||
pub details: Vec<DanglingRef>,
|
||
}
|
||
|
||
/// 悬空引用详情
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct DanglingRef {
|
||
/// 实体名
|
||
pub entity: String,
|
||
/// 字段名
|
||
pub field: String,
|
||
/// 记录 ID
|
||
pub record_id: String,
|
||
/// 悬空的 UUID 值
|
||
pub dangling_value: String,
|
||
}
|
||
|
||
// ─── 自定义视图 DTO ──────────────────────────────────────────────────
|
||
|
||
/// 用户视图配置请求
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct UserViewReq {
|
||
pub view_name: String,
|
||
pub view_config: serde_json::Value,
|
||
pub is_default: Option<bool>,
|
||
}
|
||
|
||
/// 用户视图响应
|
||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||
pub struct UserViewResp {
|
||
pub id: String,
|
||
pub plugin_id: String,
|
||
pub entity_name: String,
|
||
pub view_name: String,
|
||
pub view_config: serde_json::Value,
|
||
pub is_default: bool,
|
||
pub created_at: Option<chrono::DateTime<chrono::Utc>>,
|
||
pub updated_at: Option<chrono::DateTime<chrono::Utc>>,
|
||
}
|