chore:表单校验和提交动作支持返回结果

This commit is contained in:
lvxiaojiao 2023-07-04 21:27:01 +08:00
parent d7ee9a4db8
commit 59f8a3ec2d
4 changed files with 429 additions and 15 deletions

View File

@ -1469,13 +1469,387 @@ Form 支持轮询初始化接口,步骤如下:
当前组件对外暴露以下特性动作,其他组件可以通过指定`actionType: 动作名称`、`componentId: 该组件id`来触发这些动作,动作配置可以通过`args: {动作配置项名称: xxx}`来配置具体的参数,详细请查看[事件动作](../../docs/concepts/event-action#触发其他组件的动作)。
| 动作名称 | 动作配置 | 说明 |
| --------- | ------------------------------ | -------------------------- |
| submit | - | 提交表单 |
| reset | - | 重置表单 |
| clear | - | 清空表单 |
| validate | - | 校验表单 |
| reload | - | 刷新(重新加载) |
| setValue | `value: object` 更新的表单数据 | 更新数据,对数据进行 merge |
| static | - | 表单切换为静态展示 |
| nonstatic | - | 表单切换为普通输入态 |
| 动作名称 | 动作配置 | 说明 |
| --------- | --------------------------------------------------- | -------------------------- |
| validate | `outputVar: string` 校验结果,默认为 validateResult | 校验表单 |
| submit | `outputVar: string` 提交结果,默认为 submitResult | 提交表单 |
| setValue | `value: object` 更新的表单数据 | 更新数据,对数据进行 merge |
| reload | - | 刷新(重新加载) |
| reset | - | 重置表单 |
| clear | - | 清空表单 |
| static | - | 表单切换为静态展示 |
| nonstatic | - | 表单切换为普通输入态 |
### validate
校验结果默认缓存在`${event.data.validateResult}``true`表示校验成功,`false`表示检验失败。可以通过添加`outputVar`配置来修改缓存的变量。
校验结果的结构如下:
```json
{
// 是否成功。true表示成功false表示失败
"error": true,
// 表单项报错信息。key值为该表单项的name值
"errors": {
"email": ["Email 格式不正确"],
...
},
// 提交验证的表单数据
"payload": {
"name": "amis",
"email": "amis@baidu"
}
}
```
```schema: scope="body"
[
{
"type": "button",
"label": "校验表单",
className: "mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "validate",
"componentId": "form_validate",
"outputVar": "form_validata_result",
"stopPropagation": "${event.data.form_validata_result.error}"
},
{
"actionType": "toast",
"args": {
"msg": "${event.data.form_validata_result|json}"
}
}
]
}
}
},
{
"type": "form",
"id": "form_validate",
"api": "/api/mock2/form/saveForm",
"body": [
{
"type": "input-text",
"name": "name",
"label": "姓名:",
"required": true
},
{
"name": "email",
"type": "input-text",
"label": "邮箱:",
"required": true,
"validations": {
"isEmail": true
}
}
]
}
]
```
### submit
提交结果默认缓存在`${event.data.submitResult}`,可以通过添加`outputVar`配置来修改缓存的变量。
提交结果的结构如下:
```json
{
// 是否成功。true表示成功false表示失败
"error": true,
// 错误信息。如果是校验失败则errors为表单项报错信息key值为该表单项的name值
"errors": {
...
},
// 提交的表单数据
"payload": {
"name": "amis",
"email": "amis@baidu.com"
},
// 提交请求返回的响应结果数据
"responseData": {
"id": "1"
}
}
```
```schema: scope="body"
[
{
"type": "button",
"label": "提交表单",
className: "mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "submit",
"componentId": "form_submit",
"outputVar": "form_submit_result"
},
{
"actionType": "toast",
"args": {
"msg": "提交结果:${event.data.form_submit_result|json}"
}
}
]
}
}
},
{
"type": "form",
"id": "form_submit",
"api": "/api/mock2/form/saveForm",
"body": [
{
"type": "input-text",
"name": "name",
"label": "姓名:",
"required": true
},
{
"name": "email",
"type": "input-text",
"label": "邮箱:",
"required": true,
"validations": {
"isEmail": true
}
}
]
}
]
```
### setValue
通过`setValue`来更新表单数据,其中`value`中的数据将和目标表单的数据做合并,即同名覆盖。
```schema: scope="body"
[
{
"type": "button",
"label": "修改表单数据",
className: "mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "setValue",
"componentId": "form_setvalue",
"args": {
"value": {
"name": "amis",
"email": "amis@baidu.com"
}
}
}
]
}
}
},
{
"type": "form",
"id": "form_setvalue",
"body": [
{
"type": "input-text",
"name": "name",
"label": "姓名:"
},
{
"name": "email",
"type": "input-text",
"label": "邮箱:"
}
]
}
]
```
### reload
通过`reload`来重新请求表单的初始化接口,实现表单刷新。
```schema: scope="body"
[
{
"type": "button",
"label": "刷新表单",
className: "mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "reload",
"componentId": "form_reload"
}
]
}
}
},
{
"type": "form",
"id": "form_reload",
"debug": true,
"initApi": "/api/mock2/form/initData",
"body": [
{
"type": "input-text",
"name": "name",
"label": "姓名:"
},
{
"name": "author",
"type": "input-text",
"label": "作者:"
}
]
}
]
```
### reset
通过`reset`将表单数据重置为初始数据,初始数据可以是静态数据或初始化接口返回的数据。
```schema: scope="body"
[
{
"type": "button",
"label": "重置表单",
className: "mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "reset",
"componentId": "form_reset"
}
]
}
}
},
{
"type": "form",
"id": "form_reset",
"initApi": "/api/mock2/form/initData",
"body": [
{
"type": "alert",
"body": "修改表单项的值,然后点击【重置表单】,表单数据将被重置为初始化数据"
},
{
"type": "input-text",
"name": "name",
"label": "姓名:"
},
{
"name": "author",
"type": "input-text",
"label": "作者:"
}
]
}
]
```
### clear
通过`clear`来清空表单中的表单项数据,不包含`hidden`类型、未绑定表单项的初始化数据字段。
```schema: scope="body"
[
{
"type": "button",
"label": "清空表单",
className: "mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "clear",
"componentId": "form_clear"
}
]
}
}
},
{
"type": "form",
"id": "form_clear",
"debug": true,
"initApi": "/api/mock2/form/initData",
"body": [
{
"type": "input-text",
"name": "name",
"label": "姓名:"
},
{
"name": "author",
"type": "hidden",
"label": "作者:"
}
]
}
]
```
### static 和 nonstatic
```schema: scope="body"
[
{
"type": "button",
"label": "静态模式",
"className": "mr-2 mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "static",
"componentId": "form_static"
}
]
}
}
},
{
"type": "button",
"label": "非静态模式",
"className": "mr-2 mb-2",
"onEvent": {
"click": {
"actions": [
{
"actionType": "nonstatic",
"componentId": "form_static"
}
]
}
}
},
{
"type": "form",
"id": "form_static",
"title": "表单",
"body": [
{
"type": "input-text",
"name": "text",
"label": "输入框",
"mode": "horizontal",
"value": "text"
}
]
}
]
```

View File

@ -1,4 +1,5 @@
import {RendererEvent} from '../utils/renderer-event';
import {createObject, isEmpty} from '../utils/helper';
import {
RendererAction,
ListenerAction,
@ -116,7 +117,42 @@ export class CmptAction implements RendererAction {
}
// 执行组件动作
return component?.doAction?.(action, action.args);
try {
const result = await component?.doAction?.(action, action.args, true);
if (['validate', 'submit'].includes(action.actionType)) {
event.setData(
createObject(event.data, {
[action.outputVar || `${action.actionType}Result`]: {
error:
(action.actionType as any) === 'validate' ? !result : false,
errors: component.props.store.errors,
payload: component.props.data,
responseData:
(action.actionType as any) === 'submit'
? component.props.$schema?.api
? result
: undefined
: undefined
}
})
);
}
return result;
} catch (e) {
if ((action.actionType as any) === 'submit') {
const errors = component.props.store.errors;
event.setData(
createObject(event.data, {
[action.outputVar || 'submitResult']: {
error: true,
errors: isEmpty(errors) ? e : errors,
payload: component.props.data
}
})
);
}
}
}
}

View File

@ -1202,7 +1202,7 @@ export default class Form extends React.Component<FormProps, object> {
}
}
// return values;
return createObject(store.data, response);
});
} else {
// type为submit但是没有配api以及target时只派发事件
@ -1256,7 +1256,7 @@ export default class Form extends React.Component<FormProps, object> {
store.clear(onReset);
} else if (action.actionType === 'validate') {
store.setCurrentAction(action);
this.validate(true);
return this.validate(true);
} else if (action.actionType === 'dialog') {
store.setCurrentAction(action);
store.openDialog(data, undefined, action.callback);

View File

@ -1,7 +1,7 @@
import {ListenerAction, ListenerContext, runActions} from '../actions/Action';
import {RendererProps} from '../factory';
import {IScopedContext} from '../Scoped';
import {createObject} from './object';
import {createObject, extendObject} from './object';
import debounce from 'lodash/debounce';
export interface debounceConfig {
@ -65,7 +65,7 @@ export function createRendererEvent<T extends RendererEventContext>(
context: T
): RendererEvent<T> {
const rendererEvent = {
context,
context: extendObject({pristineData: context.data}, context),
type,
prevented: false,
stoped: false,
@ -81,6 +81,10 @@ export function createRendererEvent<T extends RendererEventContext>(
return rendererEvent.context.data;
},
get pristineData() {
return rendererEvent.context.pristineData;
},
setData(data: any) {
rendererEvent.context.data = data;
}