From 05313215f51544157fdb862f99e930a345e3e65b Mon Sep 17 00:00:00 2001 From: lvxiaojiao Date: Tue, 30 May 2023 13:59:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E7=8A=B6=E6=80=81=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=8A=A8=E4=BD=9C=E6=94=AF=E6=8C=81=E5=8A=A8=E6=80=81=E6=A0=87?= =?UTF-8?q?=E8=AF=86&=E8=A1=A5=E5=85=85combo=E8=A1=8C=E5=86=85=E8=81=94?= =?UTF-8?q?=E5=8A=A8demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh-CN/components/form/combo.md | 186 ++++++++++++++++++- docs/zh-CN/concepts/event-action.md | 103 +++++----- packages/amis-core/src/SchemaRenderer.tsx | 31 +++- packages/amis-core/src/actions/CmptAction.ts | 12 +- packages/amis-core/src/store/status.ts | 12 +- 5 files changed, 272 insertions(+), 72 deletions(-) diff --git a/docs/zh-CN/components/form/combo.md b/docs/zh-CN/components/form/combo.md index 8b54b7b58..248bab157 100755 --- a/docs/zh-CN/components/form/combo.md +++ b/docs/zh-CN/components/form/combo.md @@ -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" { diff --git a/docs/zh-CN/concepts/event-action.md b/docs/zh-CN/concepts/event-action.md index 383b39237..6ff5b991b 100644 --- a/docs/zh-CN/concepts/event-action.md +++ b/docs/zh-CN/concepts/event-action.md @@ -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 | ### 更新数据 diff --git a/packages/amis-core/src/SchemaRenderer.tsx b/packages/amis-core/src/SchemaRenderer.tsx index 08139fb52..ef9a9e921 100644 --- a/packages/amis-core/src/SchemaRenderer.tsx +++ b/packages/amis-core/src/SchemaRenderer.tsx @@ -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>, @@ -89,10 +90,20 @@ export class SchemaRenderer extends React.Component { // 监听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.$path] ?? + props.statusStore.visibleState[name || props.$path] + }${ + props.statusStore.disableState[id || props.$path] ?? + props.statusStore.disableState[name || props.$path] + }${ + props.statusStore.staticState[id || props.$path] ?? + props.statusStore.staticState[name || props.$path] + }`; + }, () => this.forceUpdate() ); } @@ -280,14 +291,20 @@ export class SchemaRenderer extends React.Component { : {}; // 控制显隐 + const id = filter(schema.id, rest.data); + const name = filter(schema.name, rest.data); + console.log(id, ',', name); const visible = isAlive(statusStore) - ? statusStore.visibleState[schema.id || $path] + ? statusStore.visibleState[id || $path] ?? + statusStore.visibleState[name || $path] : undefined; const disable = isAlive(statusStore) - ? statusStore.disableState[schema.id || $path] + ? statusStore.disableState[id || $path] ?? + statusStore.disableState[name || $path] : undefined; const isStatic = isAlive(statusStore) - ? statusStore.staticState[schema.id || $path] + ? statusStore.staticState[id || $path] ?? + statusStore.staticState[name || $path] : undefined; if ( diff --git a/packages/amis-core/src/actions/CmptAction.ts b/packages/amis-core/src/actions/CmptAction.ts index d44d1e545..279a09a8b 100644 --- a/packages/amis-core/src/actions/CmptAction.ts +++ b/packages/amis-core/src/actions/CmptAction.ts @@ -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') { diff --git a/packages/amis-core/src/store/status.ts b/packages/amis-core/src/store/status.ts index cba059039..a5a26d29c 100644 --- a/packages/amis-core/src/store/status.ts +++ b/packages/amis-core/src/store/status.ts @@ -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; },