UI Schemas(UI 架构)
概览
- UI Schema 用于为资源字段提供前端呈现与表单行为的“覆盖层”配置。
- 支持多层覆盖:
DEFAULT → TENANT → ROLE → USER,后者优先级更高,按顺序进行深度合并。 - 典型场景:为某租户下的某角色或某用户定制字段的组件类型、默认值、校验与列表/表单显示行为。
结构约定(覆盖层 schemaJson)
- 顶层对象包含
fields:一个以字段名为键的映射。 - 每个字段对应一个
FieldConfig,其中包含以x-开头的 UI 属性。
示例:
{
"fields": {
"status": {
"x-component": "Select",
"x-options": ["Open", "Closed", "Pending"],
"x-default-value": "Open",
"x-label": "Status",
"x-visible": true,
"x-required": true
}
}
}
说明:
- 合并策略以键为单位对
fields.<fieldName>进行深度合并。 x-options支持两种形态:- 简单数组:如上面的
string[](常用于快速选择项); - 对象:
{ choices: Array<Choice>, defaultValue?: any, ... }(在部分模块中常用,尤其是 Select)。
- 简单数组:如上面的
字段级 UI 属性(FieldConfig)
以下为通用且已在多模块中使用的 x- 属性清单:
-
x-component:组件类型- 取值(不区分大小写,示例按首字母大写):
Text、Textarea、Number、Boolean、Select、Date、DateTime、Email、Url - 若未指定,前端可按字段数据类型推断默认组件。
- 取值(不区分大小写,示例按首字母大写):
-
x-label:自定义显示标签(string) -
x-default-value:默认值(string | number | boolean | null)- 与
x-options.defaultValue二选一即可,若同时存在,以更高优先级覆盖层的值为准。
- 与
-
x-visible:是否显示(boolean) -
x-required:是否必填(boolean)- 也可能根据模型的
isNullable === false判定必填。
- 也可能根据模型的
-
x-tooltip:提示信息(string) -
x-placeholder:占位文本(string) -
x-options:组件配置(支持两种形态)- 简单数组:
string[](快速提供选择项) - 对象:
Record<string, any>,常见字段:choices:Array<{ id: string; name: string } | string>defaultValue: 组件层面的默认值multiple:boolean(多选)- 其他组件特定的 props(如
min/max/step对 Number;日期格式对 Date/DateTime 等)。
- 简单数组:
-
x-order:排序权重(number)- 用于控制字段在列表/表单中的显示顺序。
-
x-form-hidden:在表单隐藏该字段(boolean) -
x-list-hidden:在列表/表格隐藏该字段(boolean)
校验相关(可选,按组件类型适用)
x-minLength:最小长度(number,适用于Text/Textarea/Email/Url)x-maxLength:最大长度(number,适用于Text/Textarea/Email/Url)x-min:最小值(number,适用于Number)x-max:最大值(number,适用于Number)x-email:邮箱格式校验(boolean,适用于Email)
列表筛选相关(在部分应用中使用)
x-filter-choices:列表筛选项(Array<{ id: string; name: string } | string>),用于构建筛选器选择项。
合并与优先级
- 覆盖层获取顺序:
DEFAULT → TENANT → ROLE → USER。 - 合并策略:Map 深度合并,数组/标量覆盖(后者优先)。
- 角色层支持按请求中的角色顺序进行合并,以保持预期覆盖顺序。
API(覆盖层)
- 基础路径:
/metadata/ui-schema-overlays(网关路由到后端Controller:/api/v1/ui-schema-overlays) - 支持分页与筛选:
scopeType,tenantId,scopeKey,resourceName,page,pageSize - CRUD:
GET /,GET /{id},POST /,PUT /{id},DELETE /{id} - JSON 校验:
GET /validate?json=<schemaJson>
覆盖层对象(UiSchemaOverlay)
常用字段:
scopeType:DEFAULT | TENANT | ROLE | USER(缺省为DEFAULT)scopeKey:范围键(ROLE为角色名,USER为用户ID)resourceId:实体ID(可选;若不提供可用resourceName)resourceName:实体名(可选;若不提供可用resourceId)schemaJson:覆盖层 JSON(字符串,必须是合法 JSON);为空时可由服务端根据实体字段自动生成默认 UI SchematenantId:租户ID(创建时由服务端按请求头写入)
查询覆盖层列表
- GET
/ui-schema-overlays - 权限:
admin - 请求头:
Authorization、X-Tenant-Id - 查询参数:
scopeType、scopeKey、resourceName(可选)page(从 1 开始,默认 1)、pageSize(默认 20)
创建覆盖层(可自动生成默认 schemaJson)
- POST
/ui-schema-overlays - 权限:
admin - 请求头:
Authorization、X-Tenant-Id - 规则:
resourceId或resourceName至少提供一个(用于定位实体并生成默认 UI Schema)- 当
schemaJson为空或空白时,服务端会根据实体字段生成默认 schemaJson schemaJson非空时必须是合法 JSON,否则返回INVALID_JSON
示例:
curl -X POST \
"${API_BASE}/metadata/ui-schema-overlays" \
-H "Authorization: Bearer <token>" \
-H "X-Tenant-Id: tenant-abc123" \
-H "Content-Type: application/json" \
-d '{
"scopeType": "TENANT",
"resourceName": "customers",
"schemaJson": "{ \"fields\": { \"email\": { \"x-component\": \"Email\", \"x-required\": true } } }"
}'
更新 / 删除 / 校验 JSON
- PUT
/ui-schema-overlays/{id}:更新覆盖层(需提供合法 JSON 的schemaJson) - DELETE
/ui-schema-overlays/{id}:删除覆盖层 - GET
/ui-schema-overlays/validate?json=<schemaJson>:校验 schemaJson 是否为合法 JSON(合法返回 200,否则 400)
示例
1. Select 组件(对象形态 x-options)
{
"fields": {
"category": {
"x-component": "Select",
"x-label": "分类",
"x-required": true,
"x-options": {
"choices": [
{ "id": "electronics", "name": "电子" },
{ "id": "books", "name": "图书" }
],
"multiple": false,
"defaultValue": "electronics"
}
}
}
}
2. Number 组件(包含范围与占位)
{
"fields": {
"age": {
"x-component": "Number",
"x-label": "年龄",
"x-required": true,
"x-min": 0,
"x-max": 120,
"x-placeholder": "请输入年龄"
}
}
}
3. 简单数组形态的 x-options(快速选择)
{
"fields": {
"status": {
"x-component": "Select",
"x-options": ["Open", "Closed", "Pending"],
"x-default-value": "Open"
}
}
}
兼容性与建议
x-options两种形态均受支持;若需要更丰富的 props,推荐使用对象形态。- 为提升查询性能,建议在后端为
(tenantId, scopeType, resourceName)等组合建立索引。 - 前端编辑器可按组件类型动态显示更适合的属性(如
Number的范围、Select的多选)。
统一 UiSchema DSL(列表 / 表单 / 详情等)
在覆盖层 schemaJson 之外,前端还定义了一套统一的 UiSchema DSL,用于描述资源的列表页、表单页、详情页、关联子表以及动作按钮等配置,主要类型定义见前端 /ui/web/src/ui-schema-new/types.ts。
顶层结构(UiSchema):
version:版本号(字符串,例如"1.0")id:可选,Schema 自身 IDresource:资源名(例如"orders")i18n:多语言文案字典security:安全配置roles:允许访问的角色列表permissions:权限键值对
defaults:全局默认行为perPage:默认每页条数rowClick:列表行点击行为(edit | show | expand | none)
list:列表配置(ListConfig)form:表单配置(FormConfig,包含create/edit)show:详情页配置(ShowConfig)actions:动作定义列表(ActionDef[])views:预置视图列表(ViewDef[])metrics:嵌入的指标配置(MetricDef[])
列表配置(ListConfig):
title:列表标题columns:列定义数组(ColumnDef[])source:字段名label:列标题type:类型(文本/数字/日期等,按前端约定)sortable:是否可排序width:列宽format:格式化字符串(如日期/数字格式)component:单元格组件名props:透传组件的属性
defaultSort:默认排序{ field, order }filters:筛选条件定义(FilterDef[])component:筛选控件类型(TextInput/NumberInput/BooleanInput/SelectInput/DatetimeInput/SearchInput/ReferenceInput)choices:本地枚举值(字符串/数组/对象均可)props:组件 props
filterDefaultValues:筛选默认值toolbar:工具栏动作{ actions: ActionRef[] }rowActions:行级动作列表selection:多选配置{ enabled: boolean }data:数据源配置(DataSourceDef)perPage:每页条数(如未设置则回退到defaults.perPage)rowClick:行点击行为(如未设置则回退到defaults.rowClick)
表单配置(FormConfig):
create/edit:分别对应新建/编辑页(FormPage)FormPage:title:页面标题layout:分区布局(SectionDef[])submit:提交行为配置(SubmitDef)
SectionDef:id:分区 IDtitle:分区标题cols:分区总列数(12 栅格)fields:表单字段列表(FormFieldDef[])
FormFieldDef:source:字段名label:标签component:输入组件名props:组件 propsvisibleIf:可见性表达式disabledIf:禁用表达式validate:校验规则数组(类型、文案、附加参数)optionsSource:选项来源(远程接口或本地 choices)
详情页配置(ShowConfig):
title:详情标题layout:分区布局(ShowSectionDef[])toolbar:工具栏动作related:关联子表配置(RelatedDef[])
关联子表(RelatedDef):
id:子表 IDtitle:标题resource:关联资源名target:关联字段(如外键)filter:过滤条件(JSON 或字符串模板)sort:排序配置perPage:每页条数columns:列定义data:数据源配置
动作定义(ActionDef):
id:动作 ID(供引用)label:按钮文案icon:图标名kind:动作类型(link/dialog/mutation/download/custom)if:执行条件表达式confirm:确认文案payload:请求负载模板(字符串或对象)request:请求定义(RequestDef)onSuccess/onError:成功/失败后的动作引用列表(ActionRef[])feedback:用户提示文案{ success, error }inputs:动作触发时需要采集的输入项(ActionInputDef[])client:可选的前端本地执行配置(如通过 dataProvider 更新)
请求定义(RequestDef):
url:请求地址method:HTTP 方法(默认POST)headers:请求头paramsTemplate:查询参数模板bodyTemplate:请求体模板
数据源定义(DataSourceDef):
query:url:数据查询地址method:HTTP 方法params:静态查询参数
transform:可选的转换表达式或转换器名称
一般推荐做法:
- 用 UiSchema DSL 描述整页布局、动作与数据源。
- 用 UI Schema 覆盖层 做字段粒度的细节覆写(组件类型、显示/隐藏、校验等),二者可以配合使用。