fix(plugin): 修复插件 schema API、动态表 JSONB 和 SQL 注入防护

- get_schema 端点同时返回 entities 和 ui 页面配置,修复前端无法生成动态菜单的问题
- 动态表 INSERT/UPDATE 添加 ::jsonb 类型转换,修复 PostgreSQL 类型推断错误
- JSONB 索引创建改为非致命(warn 跳过),避免索引冲突阻断安装流程
- 权限注册/注销改用参数化查询,消除 SQL 注入风险
- DDL 语句改用 execute_unprepared,避免不必要的安全检查开销
- clear_plugin 支持已上传状态的清理
- 添加关键步骤 tracing 日志便于排查安装问题
This commit is contained in:
iven
2026-04-16 23:42:40 +08:00
parent b482230a07
commit 3483395f5e
6 changed files with 225 additions and 176 deletions

View File

@@ -54,7 +54,7 @@ display_name = "客户"
[[schema.entities.fields]]
name = "code"
field_type = "String"
field_type = "string"
required = true
display_name = "客户编码"
unique = true
@@ -62,14 +62,14 @@ display_name = "客户"
[[schema.entities.fields]]
name = "name"
field_type = "String"
field_type = "string"
required = true
display_name = "客户名称"
searchable = true
[[schema.entities.fields]]
name = "customer_type"
field_type = "String"
field_type = "string"
required = true
display_name = "客户类型"
ui_widget = "select"
@@ -81,19 +81,19 @@ display_name = "客户"
[[schema.entities.fields]]
name = "industry"
field_type = "String"
field_type = "string"
display_name = "行业"
filterable = true
[[schema.entities.fields]]
name = "region"
field_type = "String"
field_type = "string"
display_name = "地区"
filterable = true
[[schema.entities.fields]]
name = "source"
field_type = "String"
field_type = "string"
display_name = "来源"
ui_widget = "select"
options = [
@@ -106,7 +106,7 @@ display_name = "客户"
[[schema.entities.fields]]
name = "level"
field_type = "String"
field_type = "string"
display_name = "等级"
ui_widget = "select"
filterable = true
@@ -119,7 +119,7 @@ display_name = "客户"
[[schema.entities.fields]]
name = "status"
field_type = "String"
field_type = "string"
required = true
display_name = "状态"
ui_widget = "select"
@@ -132,34 +132,34 @@ display_name = "客户"
[[schema.entities.fields]]
name = "credit_code"
field_type = "String"
field_type = "string"
display_name = "统一社会信用代码"
visible_when = "customer_type == 'enterprise'"
[[schema.entities.fields]]
name = "id_number"
field_type = "String"
field_type = "string"
display_name = "身份证号"
visible_when = "customer_type == 'personal'"
[[schema.entities.fields]]
name = "parent_id"
field_type = "Uuid"
field_type = "uuid"
display_name = "上级客户"
[[schema.entities.fields]]
name = "website"
field_type = "String"
field_type = "string"
display_name = "网站"
[[schema.entities.fields]]
name = "address"
field_type = "String"
field_type = "string"
display_name = "地址"
[[schema.entities.fields]]
name = "remark"
field_type = "String"
field_type = "string"
display_name = "备注"
ui_widget = "textarea"
@@ -169,50 +169,50 @@ display_name = "联系人"
[[schema.entities.fields]]
name = "customer_id"
field_type = "Uuid"
field_type = "uuid"
required = true
display_name = "所属客户"
[[schema.entities.fields]]
name = "name"
field_type = "String"
field_type = "string"
required = true
display_name = "姓名"
searchable = true
[[schema.entities.fields]]
name = "position"
field_type = "String"
field_type = "string"
display_name = "职务"
[[schema.entities.fields]]
name = "department"
field_type = "String"
field_type = "string"
display_name = "部门"
[[schema.entities.fields]]
name = "phone"
field_type = "String"
field_type = "string"
display_name = "手机号"
[[schema.entities.fields]]
name = "email"
field_type = "String"
field_type = "string"
display_name = "邮箱"
[[schema.entities.fields]]
name = "wechat"
field_type = "String"
field_type = "string"
display_name = "微信号"
[[schema.entities.fields]]
name = "is_primary"
field_type = "Boolean"
field_type = "boolean"
display_name = "主联系人"
[[schema.entities.fields]]
name = "remark"
field_type = "String"
field_type = "string"
display_name = "备注"
[[schema.entities]]
@@ -221,18 +221,18 @@ display_name = "沟通记录"
[[schema.entities.fields]]
name = "customer_id"
field_type = "Uuid"
field_type = "uuid"
required = true
display_name = "关联客户"
[[schema.entities.fields]]
name = "contact_id"
field_type = "Uuid"
field_type = "uuid"
display_name = "关联联系人"
[[schema.entities.fields]]
name = "type"
field_type = "String"
field_type = "string"
required = true
display_name = "类型"
ui_widget = "select"
@@ -247,28 +247,28 @@ display_name = "沟通记录"
[[schema.entities.fields]]
name = "subject"
field_type = "String"
field_type = "string"
required = true
display_name = "主题"
searchable = true
[[schema.entities.fields]]
name = "content"
field_type = "String"
field_type = "string"
required = true
display_name = "内容"
ui_widget = "textarea"
[[schema.entities.fields]]
name = "occurred_at"
field_type = "DateTime"
field_type = "date_time"
required = true
display_name = "沟通时间"
sortable = true
[[schema.entities.fields]]
name = "next_follow_up"
field_type = "Date"
field_type = "date"
display_name = "下次跟进日期"
[[schema.entities]]
@@ -277,20 +277,20 @@ display_name = "客户标签"
[[schema.entities.fields]]
name = "customer_id"
field_type = "Uuid"
field_type = "uuid"
required = true
display_name = "关联客户"
[[schema.entities.fields]]
name = "tag_name"
field_type = "String"
field_type = "string"
required = true
display_name = "标签名称"
searchable = true
[[schema.entities.fields]]
name = "tag_category"
field_type = "String"
field_type = "string"
display_name = "标签分类"
ui_widget = "select"
options = [
@@ -306,19 +306,19 @@ display_name = "客户关系"
[[schema.entities.fields]]
name = "from_customer_id"
field_type = "Uuid"
field_type = "uuid"
required = true
display_name = "源客户"
[[schema.entities.fields]]
name = "to_customer_id"
field_type = "Uuid"
field_type = "uuid"
required = true
display_name = "目标客户"
[[schema.entities.fields]]
name = "relationship_type"
field_type = "String"
field_type = "string"
required = true
display_name = "关系类型"
ui_widget = "select"
@@ -333,7 +333,7 @@ display_name = "客户关系"
[[schema.entities.fields]]
name = "description"
field_type = "String"
field_type = "string"
display_name = "关系描述"
# ── 页面声明 ──