# 开发速查手册
以下是系统开发中常用的客制化注入变量、返回结果及数据格式速查。每一节只列出要点,完整说明请点击各节中的链接查看对应文档。
# 目标读者
本文档的目标读者为:本系统的开发和实施人员
# 表单 Hook
表单级的联动、默认值、校验、选项过滤等客制化,统一通过表单上的表单 Hook(formHook)和数据 Hook(dataHook)实现,注入变量与返回结果详见 表单客制化(Form Hook)。
提示
1.0 以前按字段配置的字段级联、字段搜索、字段校验、字段默认值(Field Hook)1.0 起已移除(改用表单 Hook)。
# 对象创建 Hook
详细信息请参考 对象客制化(Object Hook)。
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
object | <? extends GormEntity> | 待创建的对象实例 |
requestData | Map | 前端提交的原始数据 |
userContext | tech.muyan.api.security.MuyanAuthentication | 当前操作的用户信息 |
application | grails.core.GrailsApplication | 当前的 grails 应用上下文 |
log | Closure | 打印执行日志,内容保存到执行记录 |
hookType | tech.muyan.enums.ObjectHookType | 当前执行的客制化类型 |
# 返回结果与异常处理
创建、更新、删除类客制化的返回值只会记录到执行记录中,平台不会用返回值修改对象。需要修改数据时,在"保存前"的客制化中直接修改 object(创建)或 newObject(更新)实例,修改会随本次操作一起保存:
// BEFORE_CREATE:新客户默认信用额度
if (object.creditLimit == null) {
object.creditLimit = 10000
}
2
3
4
客制化代码可以通过抛出异常来中断操作或给出警告。平台按异常的实际类名判断,不认子类:
| 抛出的异常 | 结果 |
|---|---|
tech.muyan.exception.CustomLogicInterruptException | 操作被中断,事务回滚,异常消息作为错误显示给用户。执行记录的状态为 SUCCESS(主动中断不算执行失败) |
tech.muyan.exception.CustomLogicWarningException | 操作继续执行,异常消息作为警告显示给用户。执行记录的状态为 SUCCESS_WITH_WARNING |
| 其他任何异常(包括上面两个类的子类) | 操作被中断,事务回滚,执行记录的状态为 FAILED;显示给用户的错误消息包含原异常的类名和消息 |
// BEFORE_DELETE:已审核的单据不允许删除
if (object.status == 'APPROVED') {
throw new tech.muyan.exception.CustomLogicInterruptException("已审核的单据不能删除")
}
2
3
4
# 对象更新 Hook
详细信息请参考 对象客制化(Object Hook)。
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
oldObject | <? extends GormEntity> | 更新前的对象,在独立的 Session 中从数据库重新读取 |
newObject | <? extends GormEntity> | 按提交数据更新后的对象实例 |
requestData | Map | 前端提交的原始数据 |
userContext | tech.muyan.api.security.MuyanAuthentication | 当前操作的用户信息 |
application | grails.core.GrailsApplication | 当前的 grails 应用上下文 |
log | Closure | 打印执行日志,内容保存到执行记录 |
hookType | tech.muyan.enums.ObjectHookType | 当前执行的客制化类型 |
# 返回结果与异常处理
创建、更新、删除类客制化的返回值只会记录到执行记录中,平台不会用返回值修改对象。需要修改数据时,在"保存前"的客制化中直接修改 object(创建)或 newObject(更新)实例,修改会随本次操作一起保存:
// BEFORE_CREATE:新客户默认信用额度
if (object.creditLimit == null) {
object.creditLimit = 10000
}
2
3
4
客制化代码可以通过抛出异常来中断操作或给出警告。平台按异常的实际类名判断,不认子类:
| 抛出的异常 | 结果 |
|---|---|
tech.muyan.exception.CustomLogicInterruptException | 操作被中断,事务回滚,异常消息作为错误显示给用户。执行记录的状态为 SUCCESS(主动中断不算执行失败) |
tech.muyan.exception.CustomLogicWarningException | 操作继续执行,异常消息作为警告显示给用户。执行记录的状态为 SUCCESS_WITH_WARNING |
| 其他任何异常(包括上面两个类的子类) | 操作被中断,事务回滚,执行记录的状态为 FAILED;显示给用户的错误消息包含原异常的类名和消息 |
// BEFORE_DELETE:已审核的单据不允许删除
if (object.status == 'APPROVED') {
throw new tech.muyan.exception.CustomLogicInterruptException("已审核的单据不能删除")
}
2
3
4
# 对象删除 Hook
详细信息请参考 对象客制化(Object Hook)。
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
object | <? extends GormEntity> | 待删除的对象 |
userContext | tech.muyan.api.security.MuyanAuthentication | 当前操作的用户信息 |
application | grails.core.GrailsApplication | 当前的 grails 应用上下文 |
log | Closure | 打印执行日志,内容保存到执行记录 |
hookType | tech.muyan.enums.ObjectHookType | 当前执行的客制化类型 |
# 返回结果与异常处理
创建、更新、删除类客制化的返回值只会记录到执行记录中,平台不会用返回值修改对象。需要修改数据时,在"保存前"的客制化中直接修改 object(创建)或 newObject(更新)实例,修改会随本次操作一起保存:
// BEFORE_CREATE:新客户默认信用额度
if (object.creditLimit == null) {
object.creditLimit = 10000
}
2
3
4
客制化代码可以通过抛出异常来中断操作或给出警告。平台按异常的实际类名判断,不认子类:
| 抛出的异常 | 结果 |
|---|---|
tech.muyan.exception.CustomLogicInterruptException | 操作被中断,事务回滚,异常消息作为错误显示给用户。执行记录的状态为 SUCCESS(主动中断不算执行失败) |
tech.muyan.exception.CustomLogicWarningException | 操作继续执行,异常消息作为警告显示给用户。执行记录的状态为 SUCCESS_WITH_WARNING |
| 其他任何异常(包括上面两个类的子类) | 操作被中断,事务回滚,执行记录的状态为 FAILED;显示给用户的错误消息包含原异常的类名和消息 |
// BEFORE_DELETE:已审核的单据不允许删除
if (object.status == 'APPROVED') {
throw new tech.muyan.exception.CustomLogicInterruptException("已审核的单据不能删除")
}
2
3
4
# 动态创建权限
对象客制化类型为 CREATE 时,用于在运行时判断用户能否创建某类对象,详细信息请参考 对象权限控制。
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
objectType | Class<?> | 当前操作的对象类型 |
userContext | tech.muyan.api.security.MuyanAuthentication | 当前用户 |
application | grails.core.GrailsApplication | 当前的 grails 应用上下文 |
log | Closure<?> | 用于打印执行日志的 log 闭包 |
# 返回结果
// 允许用户创建该对象,create 必须放在 result 中
// Allow user to create this object, "create" must be wrapped in "result"
return [result: [create: true]] 2
# 动态修改和删除权限
对象客制化类型 UPDATE_DELETE 当前版本不生效:对象能否修改、删除只由领域模型的 updateRoleRequirement、deleteRoleRequirement 决定。需要在运行时判断时,可以为这两个角色要求(RoleRequirement)配置自定义逻辑(customLogic),详见 对象权限控制。
注意
内置的 USER、DEVELOPER、ADMIN 等角色要求被大量模型、表单、菜单共用,直接给它们配置自定义逻辑会影响所有引用它们的地方。请为需要运行时判断的模型新建一个专用的角色要求,再把领域模型的 updateRoleRequirement 或 deleteRoleRequirement 指向它。
角色要求的自定义逻辑注入以下变量,返回 [result: true] 表示满足要求。配置了自定义逻辑后,系统不再自动检查 hasPermissionRoles 中的角色,需要时在逻辑中自行判断:
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
object | Object | 正在判断权限的对象,可能为 null,见下方说明 |
hasPermissionRoles | List<HierarchyRole> | 该角色要求中配置的角色 |
user | tech.muyan.api.security.MuyanAuthentication | 当前用户 |
object 可能为 null
只有前端按行查询权限(POST /api/permissions/<领域模型>/,据此决定每一行是否显示「修改」「删除」按钮)时,object 才是具体的对象。后端处理修改、批量修改、删除请求(PUT、DELETE /api/data/...)时,检查的是“能否操作这类对象”,传入的 object 为 null。
因此逻辑必须先处理 object == null,否则会抛出空指针异常或返回不满足,所有修改、删除请求都会被拒绝。例如:
boolean isSales = user.authorities*.authority.contains('ROLE_SALES')
if (object == null) {
// 接口层的检查:只按角色判断
return [result: isSales]
}
// 按对象判断:已关闭的记录不显示修改、删除按钮
return [result: isSales && object.status != '已关闭']
2
3
4
5
6
7
按对象的判断目前只能控制界面上的按钮,直接调用接口仍然可以修改、删除这条记录,不能作为数据安全的保证。详见 对象权限控制。
# 定时任务核心逻辑
更多信息请参考 定时任务。
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
triggerDatetime | java.time.OffsetDateTime | 本次触发的计划时间 |
task | tech.muyan.task.DynamicTask | 当前任务,自定义参数可通过 task.parameters(JSON 字符串)读取 |
log | Closure | 打印执行日志,内容保存到执行记录 |
application | grails.core.GrailsApplication | 当前的 grails 应用上下文 |
# 返回结果
return [
//执行结果,类型为文本
//Execution result, type is text
execResult: 'OK, Result'
] 2
3
4
提示
定时任务没有启用逻辑,是否执行由任务的「是否启用」、生效时间和失效时间决定。
# Dynamic Action 显示逻辑
对象动作的启用逻辑(类型为 DYNAMIC_ACTION_ENABLE_LOGIC 的动态逻辑)决定动作对哪些记录可用。更多信息请参考 对象动作。
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
userContext | tech.muyan.api.security.MuyanAuthentication | 当前操作的用户信息 |
action | tech.muyan.dynamic.action.DynamicAction | 当前动作定义 |
form | tech.muyan.dynamic.form.DynamicForm | 动作所在的表单 |
objects | List | 待判断的记录列表 |
domainClass | tech.muyan.DomainClass | 记录的对象类型信息 |
log | Closure | 打印执行日志 |
# 返回结果
返回可用记录的 id 列表,不使用 [result: true/false] 结构:
return [
enableIds: objects.findAll { it.accountLocked }.collect { it.id }
]
2
3
- 返回结果中没有
enableIds(或为null)时,所有记录都可用。 - 启用逻辑执行时抛出异常,所有记录都不可用,错误写入后端日志。
# Dynamic Action 核心逻辑
更多信息请参考 对象动作。
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
userContext | tech.muyan.api.security.MuyanAuthentication | 当前操作的用户信息 |
action | tech.muyan.dynamic.action.DynamicAction | 当前动作定义 |
form | tech.muyan.dynamic.form.DynamicForm | 触发动作的表单 |
objects | List | 选中的记录列表。OBJECT_SINGLE 模式下也是列表,只有一个元素;CLASS_LEVEL 模式下为空列表 |
objectIds | List<Long> | 选中记录的 id 列表 |
domainClass / objectType | tech.muyan.DomainClass | 记录的对象类型信息,两个变量是同一个值 |
parameters | Map<String, Object> | 参数表单中用户填写的值,已按字段类型转换 |
rawParameters | Map<String, Object> | 参数表单中用户填写的原始值 |
searchConditions | Map | 执行时列表页面当前的搜索条件,见 按搜索条件批量处理 |
log | Closure | 打印执行日志,内容保存到执行记录的"执行日志" |
application | grails.core.GrailsApplication | 当前的 grails 应用上下文 |
# 返回结果
[
// 执行结果文字,保存到执行记录并显示给用户
// Execution result text, saved to the execution record and shown to the user
execResult: "执行的结果/Execution result",
// 类型为 tech.muyan.storage.StorageFieldValue,前端执行完成后自动下载该文件
// Type is tech.muyan.storage.StorageFieldValue, the frontend downloads it automatically
download: storageFieldValue,
// 以下字段只保存到执行记录,当前前端不使用
// Following fields are only saved to the execution record, not used by the current frontend
displayType: "markdown",
execResultInfo: "补充信息/Extra info",
redirect: "/some/page"
] 2
3
4
5
6
7
8
9
10
11
12
注意
动态逻辑引擎 OS_COMMAND(调用外部命令)在 1.0.0-beta18 中不可用:引擎执行时拿不到要运行的命令内容。
提示
动作的后处理逻辑、表单字段组的显示逻辑、向导(Wizard)的处理逻辑 1.0 起已移除。
# Widget 是否显示逻辑
更多信息请参考 仪表盘。
# 注入变量
# 返回结果
// 表示该仪表盘小组件是否启用(对象动作的启用逻辑返回 [enableIds: [...]],不使用本结构)
// Indicates whether this dashboard widget is enabled (dynamic action enable logic returns [enableIds: [...]] instead)
[result: true | false] 2
# Widget 核心逻辑
# 注入变量
与 Widget 是否显示逻辑相同。
# 返回结果
Widget 核心逻辑返回结果的结构根据 widget 类型不同而不同,请参考 仪表盘 中各类 widget 的说明。
# Webhook
接收外部系统调用的 Webhook 在「系统集成 > Webhook」中配置,详细信息请参考 系统集成。1.0 以前的传入、传出系统集成(DynamicIntegration)1.0 起已移除(改用 Webhook 或动态服务)。
# 动态服务
更多信息请参考 动态服务。
# 服务定义
| 界面显示 | 属性名 | 类型 | 说明 |
|---|---|---|---|
| Name | name | String | 服务名称,租户内唯一,创建后不可修改;调用地址中使用这个名称 |
| Logic | logic | tech.muyan.dynamic.DynamicLogic | 服务的执行逻辑,逻辑类型为 DYNAMIC_SERVICE_CORE_LOGIC |
| Active | active | Boolean | 是否激活 |
| Enable Anonymous | enableAnonymous | Boolean | 是否允许未登录调用,默认关闭 |
| Enable Log | enableLog | Boolean | 是否记录执行记录,默认关闭;只有开启后才会生成 执行记录 |
| Body Type | bodyType | 枚举 | 请求体的解析方式:JSON、XML、INPUT_STREAM;不填时按 JSON 处理 |
| Exec Records | execRecords | 该服务的执行记录 |
# 注入变量
| 变量名称 | 变量类型 | 描述 |
|---|---|---|
user | tech.muyan.api.security.MuyanAuthentication | 调用者。未登录调用时是匿名身份对象,不是 null |
method | String | 请求的 HTTP 方法,例如 GET、POST |
params | Map<String, Object> | URL 参数。只有一个值的参数直接是字符串,有多个值的参数是列表 |
body | Object | 请求体,按 Body Type 解析:JSON 为 JSON 对象,XML 为 XML 对象,INPUT_STREAM 为原始输入流 |
log | Closure<?> | 用于打印执行日志的 log 闭包,开启 Enable Log 后日志写进执行记录 |
# 动态过滤条件定义
动态过滤的条件定义格式如下所示,更多信息请参考 动态过滤。
// 下面的动态过滤条件的说明:
// 1. 状态字段等于 SUCCESS
// 2. type 是 FINDER, UPDATE 中的一个
// Below is the description of the dynamic filter conditions:
// 1. The status field is equal to SUCCESS
// 2. type is one of FINDER, UPDATE
{
// key 是列名称: status
// key is the column name: status
"status": {
// 过滤的目标列
// The target column to filter
"columnKey": "status",
// 匹配规则:等于
// Match rule: equal
"matchMode": "=",
// 匹配的目标值: SUCCESS
// Matching target value: SUCCESS
"value": "SUCCESS"
},
"type": { // key 是列名称: type
// 过滤的目标列, 与上一行的 key 相同
// The target column to filter, same as the key in the previous line
"columnKey": "type",
// 过滤的匹配规则:isOneOf (是其中某一个)
// Filter matching rule: isOneOf (is one of them)
"matchMode": "isOneOf",
// 过滤的目标值: [FINDER, UPDATE]
// Matching target value: [FINDER, UPDATE]
"value": ["FINDER", "UPDATE"]
}
} 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 动态匹配条件列表
如下列出了可在动态过滤中使用的、运行时动态渲染的匹配条件,更多信息请参考 动态过滤。
| 占位符 | 替换结果 |
|---|---|
${currentHour} | 当前小时零分零秒的时间 |
${currentDay} | 当前日期零点的时间 |
${currentWeek} | 当前星期的星期一零点 |
${currentMonth} | 当前月的第一天零点 |
${currentQuarter} | 当前季度第一天的零点 |
${currentYear} | 当前年的一月一日零点 |
${currentUserGroups} | 当前用户拥有的角色名称列表,格式为 ['ROLE_USER','ROLE_ADMIN'] |
${currentUsername} | 当前登录用户的用户名,见下方说明 |
${currentUserId} | 当前登录用户的 id,见下方说明 |
# 获取动态配置
更多详细信息请参考 系统配置。
# 前端获取配置
import { getConfig } from "@muyantech/frontend-lib";
// 调用 GET /api/config/{key},返回 { key, value },value 为字符串
const config: any = await getConfig('websocket.heartbeatInterval');
const heartbeatInterval = Number(config?.value ?? 20);
2
3
4
5
# 后台获取配置
在插件的 Service 或其他 Spring Bean 中,直接注入
tech.muyan.api.config.DynamicConfigService。在动态逻辑中,可以通过静态字段
tech.muyan.ConfigHelper.dynamicConfigService获取服务:
import tech.muyan.ConfigHelper
Integer interval = ConfigHelper.dynamicConfigService
.getByKeyOrDefault("websocket.heartbeatInterval", 20)
2
3
4
- 插件组件(实现
tech.muyan.api.MuyanPlatformComponent的类)的字段上可以使用注解@tech.muyan.api.annotations.DynamicConfig("配置 key")。插件加载时,平台通过该字段的公开 setter 写入配置值,配置变更后自动再次调用 setter 更新:
import tech.muyan.api.annotations.DynamicConfig
class HeartbeatSettings implements tech.muyan.api.MuyanPlatformComponent {
@DynamicConfig("websocket.heartbeatInterval")
Integer heartbeatInterval
}
2
3
4
5
6
# 全局配置或数据共享
在动态逻辑执行之间共享全局配置、连接或缓存数据的方法,详细信息请参考 常见问题。
当前系统提供了 tech.muyan.helper.RegistryHelper 类来进行全局共享数据的管理,可以通过
RegistryHelper.memoryGet(key)来获取缓存数据,RegistryHelper.memoryPut(key, value)来设置缓存数据,返回该 key 之前保存的值(之前没有则返回 null),RegistryHelper.memoryRemove(key)来移除缓存数据。
# extInfo 速查
提示
详述配置中的 xxx?: 中的 ? 表示该配置是可选的,如果不配置则使用默认值,在 extInfo 字段的内容中,不应包含 ? 字符。
# DomainClass 定义中
{
// 用户快捷搜索时,使用 name 和 label 两个字段进行搜索匹配
// When users perform quick search, use the name and label fields for search matching
"inlineSearchColumns": ["name", "label"],
// 界面上显示 Object 控件时,显示其 label 字段的值作为标识
// When displaying Object controls on the interface, show the value of its label field as identifier
"labelField": "label",
// 导入 CSV 数据时,当前 Domain 会在 DynamicLogic 和 User 之后加载
// When importing CSV data, the current Domain will be loaded after DynamicLogic and User
"loadAfter": ["DynamicLogic", "User"],
// CSV 中关联到当前 Domain 的列未指定查询字段时,按 name 字段查找
// When a CSV column referencing this Domain has no query field, look up by the name field
"queryField": "name"
} 2
3
4
5
6
7
8
9
10
11
12
13
更多信息请参考 动态领域模型。
# DomainClassField 属性定义中
{
// 适用于 Decimal 类型的字段,设置小数位数为 2
// Applicable to Decimal type fields, set the number of decimal places to 2
"scale": 2,
// 适用于 Decimal 类型的字段,设置精度为 10
// Applicable to Decimal type fields, set the precision to 10
"precision": 10,
// 指定 ENUM / ENUM_LIST 类型的字段的 Java 枚举类型定义
// Specify the Java enum type definition of the ENUM / ENUM_LIST type field
// 该枚举类的定义可以放在动态插件中
// The enum class definition can be in a dynamic plugin
"enumClass": "tech.muyan.mes.enums.WorkTaskStatusEnum",
// 对于 MAPPED_DOMAIN_OBJECT/MAPPED_DOMAIN_OBJECT_COLLECTION 类型的字段,必须要设置其反向引用字段
// For MAPPED_DOMAIN_OBJECT/MAPPED_DOMAIN_OBJECT_COLLECTION type fields, set its reverse reference field
"mappedBy": "b"
} 2
3
4
5
6
7
8
9
10
11
12
13
14
15
更多信息请参考 动态领域模型。
# Dynamic Action 定义中
{
/** 参数表单的显示方式:drawer 抽屉(默认)或 modal 弹窗 */
/** How the parameter form is shown: drawer (default) or modal */
"layout"?: "drawer" | "modal",
/** 参数表单提交按钮的文字,默认为"提交" */
/** Text of the submit button of the parameter form */
"submitButtonText"?: string,
/** 结果展示方式:toast 消息提示,inContainer 显示在弹窗/抽屉中。
没有参数表单时默认 toast,有参数表单时默认 inContainer */
/** How the result is shown: toast, or inContainer (inside the modal/drawer).
Defaults to toast without a parameter form, inContainer with one */
"resultType"?: "toast" | "inContainer",
/** 弹窗样式,当前只使用 width(layout 为 modal 时生效) */
/** Modal style, only width is used (when layout is modal) */
"style"?: { "width"?: number | string }
} 2
3
4
5
6
7
8
9
10
11
12
13
14
15
更多信息请参考 对象动作。
# Dynamic Form 定义中
更多详细信息请参考 基础表单。
# 通用属性
{
/** 表单标题。仅在表单的 label(显示名称)为空时使用;两者都为空时显示对象名称的翻译 */
/** Form title. Used only when the form's label is empty; if both are empty, the translated domain name is shown */
"domainTitle"?: string;
/** 表单内字段是否横向排列(标签与输入框在同一行) */
/** Whether fields are laid out horizontally (label and input on the same line) */
"horizontal"?: boolean;
} 2
3
4
5
6
7
# List form 属性
{
/** 数据刷新模式。当前只有 realtime 生效:列表会订阅数据变化并实时刷新;其他取值等同不设置 */
/** Data refresh mode. Only realtime takes effect: the list subscribes to data changes and refreshes in real time; other values are the same as not setting it */
"dataRefreshMode"?: "realtime";
/** 点击列表右上角「创建」按钮时使用的创建表单名称,不设置时使用该对象的 CREATE 表单 */
/** Name of the create form used by the "Create" button of the list; defaults to the CREATE form of the domain */
"createFormName"?: string;
/** 点击行内「修改」时使用的编辑表单名称,不设置时使用该对象的 UPDATE 表单 */
/** Name of the update form used by the row "Edit" link; defaults to the UPDATE form of the domain */
"updateFormName"?: string;
/** 列表上方搜索区使用的查询表单名称,不设置时使用该对象的 FINDER 表单 */
/** Name of the finder form used by the search panel; defaults to the FINDER form of the domain */
"finderFormName"?: string;
"listForm"?: {
/** 是否隐藏列表上方的搜索区 */
/** Whether to hide the search panel above the list */
"disableSearchPanel"?: boolean;
/** 默认过滤条件,格式与动态过滤的 conditions 相同;用户在搜索区输入同名条件时会覆盖这里的条件 */
/** Default filter conditions, same format as dynamic filter conditions; a search condition with the same key entered by the user overrides it */
"searchConditions"?: {
"fieldName": {
"columnKey": "fieldName",
"matchMode": "=",
"value": xxx
}
};
};
/** 行内编辑时是否按表单字段的 decides 刷新其他列(decides 当前版本不生效) */
/** Whether inline editing refreshes the columns listed in the field's decides (decides does not work in the current version) */
"enableRefreshColumn"?: boolean;
/** 操作列宽度,默认 120 */
/** Width of the operations column, default 120 */
"operationsColumnWidth"?: number;
/** 覆盖列表的按钮权限,只影响按钮是否显示,后端仍按对象权限校验;create 为 false 时隐藏「创建」按钮 */
/** Overrides list button permissions; only affects button visibility, the backend still checks domain permissions; create=false hides the "Create" button */
"permissions"?: {
"create"?: boolean;
"view"?: boolean;
"update"?: boolean;
"delete"?: boolean;
};
} 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# MasterDetail Form 属性
{
/** MASTER_DETAIL_LIST 表单当前没有可配置的 extInfo 属性。 */
/** MASTER_DETAIL_LIST forms currently have no configurable extInfo properties. */
/** 左侧固定为对象的树,右侧固定为该对象的 UPDATE / CREATE 表单。 */
/** The left side is always the object tree, the right side is always the UPDATE / CREATE form of the object. */
/** 旧版本的 detailFormType、detailField、detailUpdatable 已不再生效。 */
/** The legacy detailFormType, detailField and detailUpdatable are no longer used. */
} 2
3
4
5
6
7
# Dashboard Form 属性
{
/** DASHBOARD 表单当前没有可配置的 extInfo 属性,旧版本的 refreshInterval 已不再生效。 */
/** DASHBOARD forms currently have no configurable extInfo properties; the legacy refreshInterval is no longer used. */
} 2
3
# Dynamic Form Field 定义中
Dynamic Form Field 可用的 extInfo 与字段的类型关联,更多详细信息请参考 基础表单。
# 通用属性
所有类型的字段,其 extInfo 中均可使用的扩展属性如下
{
// 隐藏字段的标签,只显示控件本身
// Hides the field label and shows only the control
"hideLabel"?: boolean;
// 字段标签与只读值的 CSS 样式,例如 {"color": "#cf1322"}
// CSS styles of the field label and of the read-only value, e.g. {"color": "#cf1322"}
"labelStyle"?: object;
"valueStyle"?: object;
// meta 用于覆盖系统自动生成的表单字段的元数据,或者补充某一些属性,如 title, dataIndex, editable, updatable, elementType 等
// meta is used to override the metadata of automatically generated form fields or to supplement certain properties such as title, dataIndex, editable, updatable, elementType, etc.
// 在运行时,系统会将 meta 中的属性覆盖或者补充到系统自动生成的表单字段的元数据中
// At runtime, the system will override or supplement the metadata of automatically generated form fields with the properties in meta
"meta"?: {
// 字段名
// Field name
"key": string;
// 字段显示名
// Field display name
"title": string;
// 字段在表单中的名字,应该和 key 一致
// The name of the field in the form, should be the same as key
"dataIndex": string;
// 在创建表单中是否可编辑,false 时显示为只读
// Whether the field is editable in create forms; false renders it read-only
"editable"?: boolean;
// 在编辑表单中是否可编辑,false 时显示为只读
// Whether the field is editable in update forms; false renders it read-only
"updatable"?: boolean;
...
}
} 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# file 字段
type 为 file 或 tech_muyan_storage_StorageFieldValue 时,可使用如下的 json 来设定控件的相关属性
{
/** file、fileList、image、video 控件当前不读取 extInfo。 */
/** The file, fileList, image and video controls currently do not read extInfo. */
/** 旧版本的 accept、maxSizeMB、maxCount、totalMaxSizeMB 已不再生效。 */
/** The legacy accept, maxSizeMB, maxCount and totalMaxSizeMB are no longer used. */
} 2
3
4
5
# code 字段
type 为 code 时,可以通过如下的 extInfo 设定高亮语法
{
/** 代码编辑器控件显示时的高亮语法 */
/** Syntax highlighting when displaying the code editor control */
/** 不设置时使用字段的显示类型(code、json、markdown 等) */
/** Defaults to the field's display type (code, json, markdown, ...) */
"codeLanguage"?: "css" | "javascript" | "markdown" | "groovy" .....,
} 2
3
4
5
6
# object 字段
对于对象选择控件,可以使用如下的 extInfo 定义来设定其选择控件中的默认选项
{
/** 候选项的过滤条件
* 控件加载时用该条件查询前 20 条作为默认选项;输入关键字搜索时也会带上该条件
*/
/** Filter conditions of the candidate options
* Used to query the first 20 records as default options when the control loads, and also applied to keyword search
*/
"defaultOptionsCondition"?: {
"fieldName" : {
/** 匹配的值 */
/** Matching value */
"value": xxxx,
/** 匹配的字段名称, 支持 dot(.) 方式引用关联字段的某字段
* 如 organization.name 引用 organization 字段的 name
*/
/** Matching field name, supports referencing associated fields using dot (.) notation
* For example, organization.name refers to the name field of the organization
*/
"columnKey": "xxx",
/** 匹配规则 */
/** Matching rule */
"matchMode": matchMode
}
},
/** 输入关键字搜索时最多返回的候选项数量,默认 20 */
/** Maximum number of candidates returned by keyword search, default 20 */
"objectOptionsLimit"?: number,
/** 在下拉框底部显示「创建」「编辑」按钮,用于直接新建被关联的对象。当前版本只有单选控件的「创建」可用 */
/** Shows "Create" and "Edit" buttons at the bottom of the dropdown. Currently only "Create" of single-object controls works */
"enableObjectOperations"?: boolean,
/** 通过上述「创建」按钮打开的创建表单中,各字段的默认值查询条件;key 为被关联对象的对象类型字段名,取查询到的第一条 */
/** Default value conditions for the create form opened by the "Create" button; each key is an object field of the target domain, the first match is used */
"createFormDefaultValueConditions"?: {
"fieldName": { "columnKey": "xxx", "matchMode": "=", "value": xxx }
},
/** 覆盖上述创建表单中字段的属性,例如 {"owner": {"disabled": true}} */
/** Overrides field properties in that create form, e.g. {"owner": {"disabled": true}} */
"overwriteCreateFormFieldProps"?: object
} 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 一对多对象字段
type 为 array 时(一对多的对象字段),可以使用如下的 extInfo 定义来设定其关联列表的显示
{
/** 显示关联对象列表时使用的表单名称,不设置时使用关联对象的 LIST 表单 */
/** Name of the form used to display the associated objects; defaults to the LIST form of the associated domain */
"displayForm"?: "Form used to display the list of objects"
} 2
3
4
# 子表字段
// 1. 子表字段(表单字段)的 extInfo
// 1. extInfo of the sub-table form field
{
/** 子表使用的表单名称(决定子表显示哪些列),不设置时使用子对象的 LIST 表单 */
/** Name of the form rendering the sub-table (decides the columns); defaults to the LIST form of the child domain */
"displayForm"?: "UserGroup Sub Table Form For User",
/** 仅 relativeSubTable 使用:从当前对象出发的一对多字段路径,用点号分隔 */
/** Only for relativeSubTable: path of a one-to-many field starting from the current object, separated by dots */
"subTable"?: {
"relativeNamePath"?: "customer.contacts"
}
}
// 2. displayForm 指向的那个表单的 extInfo(行操作权限等写在这里,不是写在字段上)
// 2. extInfo of the form referenced by displayForm (row permissions etc. go here, not on the field)
{
"subTable"?: {
/** 是否可修改、新增、删除行;设置后覆盖默认值(默认可修改;带 mappedBy 的一对多子表要求主对象已保存才可删除,且当前不显示「创建」按钮) */
/** Whether rows can be updated, created, deleted; overrides the defaults (updatable by default; for one-to-many with mappedBy, delete requires the owner to be saved and the "Create" button is currently not shown) */
"updatable"?: true | false,
"creatable"?: true | false,
"deletable"?: true | false,
/** 是否可拖拽排序 */
/** Whether rows can be reordered by drag and drop */
"dragSort"?: true | false,
/** 为 true 时「创建」按钮放在表格底部(默认在顶部);可拖拽排序的子表中新增行也追加到末尾 */
/** When true the "Create" button is placed at the bottom (top by default); in drag-sortable sub-tables new rows are appended */
"asc"?: true | false,
/** 在操作列中提供行级对象动作,只读状态下也显示操作列 */
/** Offers row-level object actions in the operations column, which is shown even when read-only */
"enableActions"?: true | false
}
} 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
← 📜 平台历程 ❓ FAQ 常见问题 →