Merge pull request #7033 from hsm-lv/feat-action

feat:状态控制动作支持动态标识&补充combo行内联动demo Close #6972
This commit is contained in:
hsm-lv 2023-05-30 15:11:30 +08:00 committed by GitHub
commit fac5ae4080
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 268 additions and 72 deletions

View File

@ -1059,9 +1059,191 @@ combo 还有一个作用是增加层级,比如返回的数据是一个深层
}
```
#### 修改列表嵌套结构的行记录的字段
#### 行记录内表单项联动
下面的示例中combo 内包含一个表格编辑框,即 combo 数据是一个列表结构它的记录中嵌套了另一个列表结构inpu-table。想要实现【修改】操作只更新所在 combo 行记录中的 input-table 中对应的行记录。通过`componentName`来指定所需更新的字段名,它将帮你定位到当前操作行;
在 combo 中行记录内表单项联动需要指定`componentName`为需要联动的表单项名称,以下示例中,当选择指定行内第一个下拉框的值时,将对应的修改所在行内第二个下拉框的值。
```schema: scope="body"
{
"type": "form",
"debug": true,
"data": {
"combo": [
{
"select_1": "A",
"select_2": "c"
},
{
"select_1": "A",
"select_2": "d"
}
]
},
"mode": "horizontal",
"api": "/api/mock2/form/saveForm",
"body": [
{
"type": "combo",
"label": "组合输入",
"name": "combo",
"multiple": true,
"addable": true,
"removable": true,
"removableMode": "icon",
"addBtn": {
"label": "新增",
"icon": "fa fa-plus",
"level": "primary",
"size": "sm",
"onEvent": {
"click": {
"weight": 0,
"actions": [
]
}
}
},
"items": [
{
"type": "select",
"label": "选项${index}",
"name": "select_1",
"options": [
{
"label": "选项A",
"value": "A"
},
{
"label": "选项B",
"value": "B"
}
],
"multiple": false,
"onEvent": {
"change": {
"actions": [
{
"componentName": "select_2",
"args": {
"value": "${IF(event.data.value==='A','c','d')}"
},
"actionType": "setValue"
}
]
}
}
},
{
"type": "select",
"name": "select_2",
"placeholder": "选项",
"options": [
{
"label": "C",
"value": "c"
},
{
"label": "D",
"value": "d"
}
]
}
]
}
]
}
```
通过[状态控制动作](../../concepts/event-action#控制状态)来联动时比较特殊,需要配置动态的`componentId`或`componentName`,一般使用`index`索引来区分指定的表单项。例如下面的示例中,每行的第一个下拉框的选择来决定所在行记录中的第二个下拉框是否显示。
```schema: scope="body"
{
"type": "form",
"debug": true,
"data": {
"combo": [
{
"select_1": "A",
"select_2": "c"
},
{
"select_1": "A",
"select_2": "d"
}
]
},
"mode": "horizontal",
"api": "/api/mock2/form/saveForm",
"body": [
{
"type": "combo",
"label": "组合输入",
"name": "combo",
"multiple": true,
"addable": true,
"removable": true,
"removableMode": "icon",
"addBtn": {
"label": "新增",
"icon": "fa fa-plus",
"level": "primary",
"size": "sm"
},
"items": [
{
"type": "select",
"label": "选项${index}",
"name": "select_1",
"options": [
{
"label": "选项A",
"value": "A"
},
{
"label": "选项B",
"value": "B"
}
],
"multiple": false,
"onEvent": {
"change": {
"actions": [
{
"componentId": "select_2_${index}",
"args": {
"value": "${IF(event.data.value==='A',true,false)}"
},
"actionType": "visibility"
}
]
}
}
},
{
"type": "select",
"name": "select_2",
"id": "select_2_${index}",
"placeholder": "选项",
"options": [
{
"label": "C",
"value": "c"
},
{
"label": "D",
"value": "c"
}
]
}
]
}
]
}
```
#### 嵌套结构中行记录内表单项联动
这里所说的是列表结构数据的嵌套。下面的示例中combo 内包含一个表格编辑框,即 combo 数据是一个列表结构它的记录中嵌套了另一个列表结构input-table。想要实现 input-table 内行记录【修改】操作只更新所在行记录中的表单项。通过`componentName`来指定所需更新的字段名,它将帮你定位到当前操作行。
```schema: scope="body"
{

View File

@ -1378,11 +1378,11 @@ run action ajax
| ----------- | -------- | ------ | --------------------- |
| componentId | `string` | - | 指定刷新的目标组件 id |
### 显示与隐藏
### 控制状态
> 1.8.0 及以上版本
通过配置`actionType: 'show'`或`'hidden'`实现对指定组件的显示和隐藏,且显隐动作的控制高于组件显隐属性的设置
通过配置`actionType: 'show'`或`'hidden'`或`'enabled'`或`'disabled'`或`'static'`或`'nostatic'`实现对指定组件的显示、隐藏、启用、禁用,仅支持实现了对应状态控制功能的数据`输入类`组件
```schema
{
@ -1390,15 +1390,15 @@ run action ajax
body: [
{
type: 'button',
label: '显示',
label: '显示表单',
level: 'primary',
className: 'mr-2',
className: 'mr-2 mb-2',
onEvent: {
click: {
actions: [
{
actionType: 'show',
componentId: 'input-text_001'
componentId: 'form_disable'
}
]
}
@ -1406,51 +1406,24 @@ run action ajax
},
{
type: 'button',
label: '隐藏',
label: '隐藏表单',
level: 'primary',
className: 'mr-2 mb-2',
onEvent: {
click: {
actions: [
{
actionType: 'hidden',
componentId: 'input-text_001'
componentId: 'form_disable'
}
]
}
}
},
{
type: 'input-text',
label: '愿望',
className: 'mt-2',
id: 'input-text_001',
mode: 'horizontal',
hidden: true
}
]
}
```
**其他属性**
| 属性名 | 类型 | 默认值 | 说明 |
| ----------- | -------- | ------ | --------------------------- |
| componentId | `string` | - | 指定显示或隐藏的目标组件 id |
### 控制状态
> 1.8.0 及以上版本
通过配置`actionType: 'enabled'`或`actionType: 'disabled'`实现对指定组件的启用和禁用,仅支持实现了状态控制功能的数据`输入类`组件。
```schema
{
type: 'page',
body: [
{
type: 'button',
id: 'b_dis',
label: '禁用',
label: '禁用表单',
level: 'primary',
className: 'mr-2 mb-2',
disabled: true,
@ -1467,9 +1440,9 @@ run action ajax
},
{
type: 'button',
label: '启用',
label: '启用表单',
level: 'primary',
className: 'mb-2',
className: 'mr-2 mb-2',
onEvent: {
click: {
actions: [
@ -1481,23 +1454,57 @@ run action ajax
}
}
},
{
type: 'button',
label: '静态展示表单',
level: 'primary',
className: 'mr-2 mb-2',
onEvent: {
click: {
actions: [
{
actionType: 'static',
componentId: 'form_disable'
}
]
}
}
},
{
type: 'button',
label: '非静态展示表单',
level: 'primary',
className: 'mr-2 mb-2',
onEvent: {
click: {
actions: [
{
actionType: 'nonstatic',
componentId: 'form_disable'
}
]
}
}
},
{
type: 'form',
id: 'form_disable',
title: '表单',
body: [
{
"type": "input-text",
"name": "text",
"label": "输入框",
"mode": "horizontal",
"value": "text"
},
{
type: 'group',
body: [
{
type: 'button',
className: 'ml-2',
label: '我的状态变了'
},
{
type: 'button',
className: 'ml-2',
label: '禁用上面的按钮',
label: '禁用【禁用】',
level: 'primary',
onEvent: {
click: {
@ -1513,7 +1520,7 @@ run action ajax
{
type: 'button',
className: 'ml-2',
label: '启用用上面的按钮',
label: '启用【禁用】',
level: 'primary',
onEvent: {
click: {
@ -1536,9 +1543,9 @@ run action ajax
**其他属性**
| 属性名 | 类型 | 默认值 | 说明 |
| ----------- | -------- | ------ | --------------------------- |
| componentId | `string` | - | 指定启用或禁用的目标组件 id |
| 属性名 | 类型 | 默认值 | 说明 |
| ----------- | -------- | ------ | ------------------------------------ |
| componentId | `string` | - | 指定启用/禁用/显示/隐藏的目标组件 id |
### 更新数据

View File

@ -23,6 +23,7 @@ import {reaction} from 'mobx';
import {resolveVariableAndFilter} from './utils/tpl-builtin';
import {buildStyle} from './utils/style';
import {StatusScopedProps} from './StatusScoped';
import {filter} from './utils/tpl';
interface SchemaRendererProps
extends Partial<Omit<RendererProps, 'statusStore'>>,
@ -89,10 +90,20 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
// 监听statusStore更新
this.reaction = reaction(
() =>
`${props.statusStore.visibleState[props.schema.id || props.$path]}${
props.statusStore.disableState[props.schema.id || props.$path]
}${props.statusStore.staticState[props.schema.id || props.$path]}`,
() => {
const id = filter(props.schema.id, props.data);
const name = filter(props.schema.name, props.data);
return `${
props.statusStore.visibleState[id] ??
props.statusStore.visibleState[name]
}${
props.statusStore.disableState[id] ??
props.statusStore.disableState[name]
}${
props.statusStore.staticState[id] ??
props.statusStore.staticState[name]
}`;
},
() => this.forceUpdate()
);
}
@ -280,14 +291,16 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
: {};
// 控制显隐
const id = filter(schema.id, rest.data);
const name = filter(schema.name, rest.data);
const visible = isAlive(statusStore)
? statusStore.visibleState[schema.id || $path]
? statusStore.visibleState[id] ?? statusStore.visibleState[name]
: undefined;
const disable = isAlive(statusStore)
? statusStore.disableState[schema.id || $path]
? statusStore.disableState[id] ?? statusStore.disableState[name]
: undefined;
const isStatic = isAlive(statusStore)
? statusStore.staticState[schema.id || $path]
? statusStore.staticState[id] ?? statusStore.staticState[name]
: undefined;
if (

View File

@ -59,13 +59,10 @@ export class CmptAction implements RendererAction {
action.actionType === 'visibility'
? action.args?.value
: action.actionType === 'show';
return renderer.props.statusStore.setVisible(
action.componentId!,
visibility as any
);
return renderer.props.statusStore.setVisible(key!, visibility as any);
} else if (['static', 'nonstatic'].includes(action.actionType)) {
return renderer.props.statusStore.setStatic(
action.componentId!,
key!,
action.actionType === 'static'
);
} else if (
@ -75,10 +72,7 @@ export class CmptAction implements RendererAction {
action.actionType === 'usability'
? !action.args?.value
: action.actionType === 'disabled';
return renderer.props.statusStore.setDisable(
action.componentId!,
usability
);
return renderer.props.statusStore.setDisable(key!, usability);
}
if (action.actionType === 'setValue') {

View File

@ -9,24 +9,24 @@ export const StatusStore = types
})
.actions(self => ({
setVisible(id: string, value?: boolean) {
setVisible(key: string, value?: boolean) {
const state = {
...self.visibleState,
[id]: value
[key]: value
};
self.visibleState = state;
},
setDisable(id: string, value?: boolean) {
setDisable(key: string, value?: boolean) {
const state = {
...self.disableState,
[id]: value
[key]: value
};
self.disableState = state;
},
setStatic(id: string, value?: boolean) {
setStatic(key: string, value?: boolean) {
const state = {
...self.staticState,
[id]: value
[key]: value
};
self.staticState = state;
},