feat(plugin): P2-P4 插件平台演进 — 通用服务 + 质量保障 + 市场
P2 平台通用服务: - manifest 扩展: settings/numbering/templates/trigger_events/importable/exportable 声明 - 插件配置 UI: PluginSettingsForm 自动表单 + 后端校验 + 详情抽屉 Settings 标签页 - 编号规则: Host API numbering-generate + PostgreSQL 序列 + manifest 绑定 - 触发事件: data_service create/update/delete 自动发布 DomainEvent - WIT 接口: 新增 numbering-generate/setting-get Host API P3 质量保障: - plugin_validator.rs: 安全扫描(WASM大小/实体数量/字段校验) + 复杂度评分 - 运行时监控指标: RuntimeMetrics (错误率/响应时间/Fuel/内存) - 性能基准: BenchmarkResult 阈值定义 - 上传时自动安全扫描 + /validate API 端点 P4 插件市场: - 数据库迁移: plugin_market_entries + plugin_market_reviews 表 - 前端 PluginMarket 页面: 分类浏览/搜索/详情/评分 - 路由注册: /plugins/market 测试: 269 全通过 (71 erp-plugin + 41 auth + 57 config + 34 core + 50 message + 16 workflow)
This commit is contained in:
@@ -39,6 +39,7 @@ mod m20260418_000036_add_data_scope_to_role_permissions;
|
||||
mod m20260419_000037_create_user_departments;
|
||||
mod m20260419_000038_fix_crm_permission_codes;
|
||||
mod m20260419_000039_entity_registry_columns;
|
||||
mod m20260419_000040_plugin_market;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
@@ -85,6 +86,7 @@ impl MigratorTrait for Migrator {
|
||||
Box::new(m20260419_000037_create_user_departments::Migration),
|
||||
Box::new(m20260419_000038_fix_crm_permission_codes::Migration),
|
||||
Box::new(m20260419_000039_entity_registry_columns::Migration),
|
||||
Box::new(m20260419_000040_plugin_market::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
/// 插件市场目录表 — P4 插件市场基础设施
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Alias::new("plugin_market_entries"))
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("id"))
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(Alias::new("plugin_id")).string().not_null())
|
||||
.col(ColumnDef::new(Alias::new("name")).string().not_null())
|
||||
.col(ColumnDef::new(Alias::new("version")).string().not_null())
|
||||
.col(ColumnDef::new(Alias::new("description")).text())
|
||||
.col(ColumnDef::new(Alias::new("author")).string())
|
||||
.col(ColumnDef::new(Alias::new("category")).string()) // 行业分类
|
||||
.col(ColumnDef::new(Alias::new("tags")).json()) // 标签列表
|
||||
.col(ColumnDef::new(Alias::new("icon_url")).string())
|
||||
.col(ColumnDef::new(Alias::new("screenshots")).json()) // 截图 URL 列表
|
||||
.col(ColumnDef::new(Alias::new("wasm_binary")).binary().not_null())
|
||||
.col(ColumnDef::new(Alias::new("manifest_toml")).text().not_null())
|
||||
.col(ColumnDef::new(Alias::new("wasm_hash")).string().not_null())
|
||||
.col(ColumnDef::new(Alias::new("min_platform_version")).string())
|
||||
.col(ColumnDef::new(Alias::new("status"))
|
||||
.string()
|
||||
.not_null()
|
||||
.default("published")) // published | suspended
|
||||
.col(ColumnDef::new(Alias::new("download_count")).integer().not_null().default(0))
|
||||
.col(ColumnDef::new(Alias::new("rating_avg")).decimal().not_null().default(0.0))
|
||||
.col(ColumnDef::new(Alias::new("rating_count")).integer().not_null().default(0))
|
||||
.col(ColumnDef::new(Alias::new("changelog")).text()) // 版本更新日志
|
||||
.col(ColumnDef::new(Alias::new("created_at"))
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()))
|
||||
.col(ColumnDef::new(Alias::new("updated_at"))
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()))
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 插件市场评论/评分表
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Alias::new("plugin_market_reviews"))
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Alias::new("id"))
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(Alias::new("tenant_id")).uuid().not_null())
|
||||
.col(ColumnDef::new(Alias::new("user_id")).uuid().not_null())
|
||||
.col(ColumnDef::new(Alias::new("market_entry_id")).uuid().not_null())
|
||||
.col(ColumnDef::new(Alias::new("rating")).integer().not_null()) // 1-5
|
||||
.col(ColumnDef::new(Alias::new("review_text")).text())
|
||||
.col(ColumnDef::new(Alias::new("created_at"))
|
||||
.timestamp_with_time_zone()
|
||||
.not_null()
|
||||
.default(Expr::current_timestamp()))
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 唯一索引:每个用户对每个市场条目只能评一次
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.if_not_exists()
|
||||
.unique()
|
||||
.name("uq_market_review_tenant_user_entry")
|
||||
.table(Alias::new("plugin_market_reviews"))
|
||||
.col(Alias::new("tenant_id"))
|
||||
.col(Alias::new("user_id"))
|
||||
.col(Alias::new("market_entry_id"))
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Alias::new("plugin_market_reviews")).to_owned())
|
||||
.await?;
|
||||
manager
|
||||
.drop_table(Table::drop().table(Alias::new("plugin_market_entries")).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user