fix:修复确认弹窗自定义内容问题

This commit is contained in:
lvxiaojiao 2023-06-29 20:27:06 +08:00
parent ce50db6d25
commit 80243b84db
13 changed files with 203 additions and 88 deletions

View File

@ -683,51 +683,13 @@ run action ajax
| ----------- | -------- | ------ | --------------- | | ----------- | -------- | ------ | --------------- |
| componentId | `string` | - | 指定抽屉组件 id | | componentId | `string` | - | 指定抽屉组件 id |
### 打开对话框 ### 打开确认弹窗
通过配置`actionType: 'alert'`或`actionType: 'confirm'`打开不同对话框,该动作分别需实现 env.alert: (msg: string) => void 和 env.confirm: (msg: string, title?: string) => boolean | Promise<boolean> 通过配置`actionType: 'confirmDialog'`打开确认对话框。确认对话框弹出后,如果选择取消操作,将不会执行该动作后面的动作。如下面的例子,点击确认之后将弹出`toast`提示,点击取消则不会提示
#### 提示对话框 **普通文本内容**
```schema 动作需要实现 env.confirm: (msg: string, title?: string) => boolean | Promise<boolean>
{
type: 'page',
data: {
msg: '去吃饭了'
},
body: [
{
type: 'button',
label: '提示对话框(模态)',
level: 'primary',
onEvent: {
click: {
actions: [
{
actionType: 'alert',
args: {
title: '提示',
msg: '<a href="http://www.baidu.com" target="_blank">${msg}~</a>'
}
}
]
}
}
}
]
}
```
**动作属性args**
> `< 1.8.0 及以下版本`,以下属性与 args 同级。
| 属性名 | 类型 | 默认值 | 说明 |
| ------ | -------- | -------- | -------------- |
| title | `string` | 系统提示 | 对话框标题 |
| msg | `string` | - | 对话框提示内容 |
#### 确认对话框
```schema ```schema
{ {
@ -746,10 +708,16 @@ run action ajax
actions: [ actions: [
{ {
actionType: 'confirmDialog', actionType: 'confirmDialog',
args: { dialog: {
title: '${title}', title: '${title}',
msg: '<span style="color:red">${msg}</span>' msg: '<span style="color:red">${msg}</span>'
} }
},
{
actionType: 'toast',
args: {
msg: '确认ok啦'
}
} }
] ]
} }
@ -759,14 +727,120 @@ run action ajax
} }
``` ```
**动作属性args** **自定义弹窗内容**
> `< 1.8.0 及以下版本`,以下属性与 args 同级 可以通过`body`像配置弹窗一样配置确认弹窗的内容
| 属性名 | 类型 | 默认值 | 说明 | ```schema
| ------ | -------- | ------ | -------------- | {
| title | `string` | - | 对话框标题 | type: 'page',
| msg | `string` | - | 对话框提示内容 | data: {
title: '操作确认',
msg: '确认提交吗?'
},
body: [
{
type: 'button',
label: '自定义确认对话框(模态)',
level: 'primary',
onEvent: {
click: {
actions: [
{
actionType: 'confirmDialog',
dialog: {
type: 'dialog',
title: '${title}',
confirmText: '确认',
cancelText: '取消',
confirmBtnLevel: 'primary',
data: {
'&': '$$',
title: '确认'
},
body: [
{
"type": "form",
"initApi": "/api/mock2/form/initData",
"title": "编辑用户信息",
"body": [
{
"type": "input-text",
"name": "name",
"label": "姓名"
},
{
"type": "input-text",
"name": "email",
"label": "邮箱"
},
{
type: 'tpl',
tpl: '${msg}'
}
]
}
]
}
},
{
actionType: 'toast',
args: {
msg: '确认ok啦'
}
}
]
}
}
}
]
}
```
**动作属性**
| 属性名 | 类型 | 默认值 | 说明 |
| ------ | ----------------------------- | ------ | ------------------------------------------------------------------- |
| dialog | {msg:`string`}/`DialogObject` | - | 指定弹框内容。自定义弹窗内容可参考[Dialog](../../components/dialog) |
### 提示对话框
通过配置`actionType: 'alert'`打开提示对话框,该对话框只有确认按钮。该动作需要实现 env.alert: (msg: string) => void。
```schema
{
type: 'page',
data: {
msg: '去吃饭了'
},
body: [
{
type: 'button',
label: '提示对话框(模态)',
level: 'primary',
onEvent: {
click: {
actions: [
{
actionType: 'alert',
dialog: {
title: '提示',
msg: '<a href="http://www.baidu.com" target="_blank">${msg}~</a>'
}
}
]
}
}
}
]
}
```
**动作属性**
| 属性名 | 类型 | 默认值 | 说明 |
| ------ | -------------------------------- | ---------------------------- | ---------- |
| dialog | {title:`string`<br>msg:`string`} | {title: '系统提示', msg: ''} | 对话框配置 |
### 跳转链接 ### 跳转链接

View File

@ -160,7 +160,7 @@ export class RootRenderer extends React.Component<RootRendererProps> {
window.open(mailto); window.open(mailto);
} else if (action.actionType === 'dialog') { } else if (action.actionType === 'dialog') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDialog(ctx, undefined, undefined, delegate); store.openDialog(ctx, undefined, action.callback, delegate);
} else if (action.actionType === 'drawer') { } else if (action.actionType === 'drawer') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDrawer(ctx, undefined, undefined, delegate); store.openDrawer(ctx, undefined, undefined, delegate);

View File

@ -24,7 +24,7 @@ export interface ListenerAction {
description?: string; // 事件描述actionType: broadcast description?: string; // 事件描述actionType: broadcast
componentId?: string; // 组件ID用于直接执行指定组件的动作指定多个组件时使用英文逗号分隔 componentId?: string; // 组件ID用于直接执行指定组件的动作指定多个组件时使用英文逗号分隔
componentName?: string; // 组件Name用于直接执行指定组件的动作指定多个组件时使用英文逗号分隔 componentName?: string; // 组件Name用于直接执行指定组件的动作指定多个组件时使用英文逗号分隔
args?: Record<string, any>; // 动作配置,可以配置数据映射 args?: Record<string, any>; // 动作配置,可以配置数据映射。注意存在schema配置的动作都不能放在args里面避免数据域不同导致的解析错误问题
data?: Record<string, any> | null; // 动作数据参数,可以配置数据映射 data?: Record<string, any> | null; // 动作数据参数,可以配置数据映射
dataMergeMode?: 'merge' | 'override'; // 参数模式,合并或者覆盖 dataMergeMode?: 'merge' | 'override'; // 参数模式,合并或者覆盖
outputVar?: string; // 输出数据变量名 outputVar?: string; // 输出数据变量名
@ -132,7 +132,7 @@ const getOmitActionProp = (type: string) => {
omitList = ['drawer']; omitList = ['drawer'];
break; break;
case 'confirmDialog': case 'confirmDialog':
omitList = ['confirmDialog']; omitList = ['dialog'];
break; break;
case 'reload': case 'reload':
omitList = ['resetPage']; omitList = ['resetPage'];

View File

@ -6,10 +6,13 @@ import {
ListenerContext, ListenerContext,
registerAction registerAction
} from './Action'; } from './Action';
import {render} from '../index'; import {createObject, filter, render} from '../index';
import {reject} from 'lodash';
export interface IAlertAction extends ListenerAction { export interface IAlertAction extends ListenerAction {
actionType: 'alert'; actionType: 'alert';
dialog?: Schema;
// 兼容历史,保留。为了和其他弹窗保持一致
args: { args: {
msg: string; msg: string;
[propName: string]: any; [propName: string]: any;
@ -27,14 +30,17 @@ export interface IConfirmAction extends ListenerAction {
export interface IDialogAction extends ListenerAction { export interface IDialogAction extends ListenerAction {
actionType: 'dialog'; actionType: 'dialog';
// 兼容历史保留。不建议用args
args: { args: {
dialog: SchemaNode; dialog: SchemaNode;
}; };
dialog?: SchemaNode; // 兼容历史 dialog?: SchemaNode;
} }
export interface IConfirmDialogAction extends ListenerAction { export interface IConfirmDialogAction extends ListenerAction {
actionType: 'confirmDialog'; actionType: 'confirmDialog';
dialog?: Schema;
// 兼容历史保留。不建议用args
args: { args: {
msg: string; msg: string;
title: string; title: string;
@ -70,7 +76,7 @@ export class DialogAction implements RendererAction {
event, event,
{ {
actionType: 'dialog', actionType: 'dialog',
dialog: action.args?.dialog || action.dialog, dialog: action.dialog ?? action.args?.dialog,
reload: 'none' reload: 'none'
}, },
action.data action.data
@ -121,7 +127,10 @@ export class AlertAction implements RendererAction {
renderer: ListenerContext, renderer: ListenerContext,
event: RendererEvent<any> event: RendererEvent<any>
) { ) {
event.context.env.alert?.(action.args?.msg, action.args?.title); event.context.env.alert?.(
filter(action.dialog?.msg, event.data) ?? action.args?.msg,
filter(action.dialog?.title, event.data) ?? action.args?.title
);
} }
} }
@ -134,22 +143,49 @@ export class ConfirmAction implements RendererAction {
renderer: ListenerContext, renderer: ListenerContext,
event: RendererEvent<any> event: RendererEvent<any>
) { ) {
let content = action.args?.body const type = action.dialog?.type ?? (action.args as any)?.type;
? render(action.args.body)
: action.args.msg; if (!type) {
const confirmed = await event.context.env.confirm?.(
filter(action.dialog?.msg, event.data) || action.args?.msg,
filter(action.dialog?.title, event.data) || action.args?.title,
{
closeOnEsc:
filter(action.dialog?.closeOnEsc, event.data) ||
action.args?.closeOnEsc,
size: filter(action.dialog?.size, event.data) || action.args?.size,
confirmText:
filter(action.dialog?.confirmText, event.data) ||
action.args?.confirmText,
cancelText:
filter(action.dialog?.cancelText, event.data) ||
action.args?.cancelText,
confirmBtnLevel:
filter(action.dialog?.confirmBtnLevel, event.data) ||
action.args?.confirmBtnLevel,
cancelBtnLevel:
filter(action.dialog?.cancelBtnLevel, event.data) ||
action.args?.cancelBtnLevel
}
);
return confirmed;
}
// 自定义弹窗内容
const confirmed = await new Promise((resolve, reject) => {
renderer.props.onAction?.(
event,
{
actionType: 'dialog',
dialog: action.dialog ?? action.args,
reload: 'none',
callback: (result: boolean) => resolve(result)
},
action.data
);
});
const confirmed = await event.context.env.confirm?.(
content,
action.args.title,
{
closeOnEsc: action.args.closeOnEsc,
size: action.args.size,
confirmText: action.args.confirmText,
cancelText: action.args.cancelText,
confirmBtnLevel: action.args.confirmBtnLevel,
cancelBtnLevel: action.args.cancelBtnLevel
}
);
return confirmed; return confirmed;
} }
} }

View File

@ -9,10 +9,11 @@ import {
export interface IDrawerAction extends ListenerAction { export interface IDrawerAction extends ListenerAction {
actionType: 'drawer'; actionType: 'drawer';
// 兼容历史保留。不建议用args
args: { args: {
drawer: SchemaNode; drawer: SchemaNode;
}; };
drawer?: SchemaNode; // 兼容历史 drawer?: SchemaNode;
} }
/** /**
@ -32,7 +33,7 @@ export class DrawerAction implements RendererAction {
event, event,
{ {
actionType: 'drawer', actionType: 'drawer',
drawer: action.args?.drawer || action.drawer, drawer: action.drawer ?? action.args?.drawer,
reload: 'none' reload: 'none'
}, },
action.data action.data

View File

@ -1133,7 +1133,7 @@ export default class Form extends React.Component<FormProps, object> {
action.target && action.target &&
this.reloadTarget(filterTarget(action.target, values), values); this.reloadTarget(filterTarget(action.target, values), values);
} else if (action.actionType === 'dialog') { } else if (action.actionType === 'dialog') {
store.openDialog(data); store.openDialog(data, undefined, action.callback);
} else if (action.actionType === 'drawer') { } else if (action.actionType === 'drawer') {
store.openDrawer(data); store.openDrawer(data);
} else if (isEffectiveApi(action.api || api, values)) { } else if (isEffectiveApi(action.api || api, values)) {
@ -1259,7 +1259,7 @@ export default class Form extends React.Component<FormProps, object> {
this.validate(true); this.validate(true);
} else if (action.actionType === 'dialog') { } else if (action.actionType === 'dialog') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDialog(data); store.openDialog(data, undefined, action.callback);
} else if (action.actionType === 'drawer') { } else if (action.actionType === 'drawer') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDrawer(data); store.openDrawer(data);

View File

@ -1214,7 +1214,7 @@ export const updateComponentContext = (variables: any[]) => {
...child, ...child,
label: label:
index === 0 index === 0
? `当前数据域${child.label ? '(' + child.label + ')' : ''}` ? `当前${child.label ? '(' + child.label + ')' : ''}`
: `${index}${child.label ? '(' + child.label + ')' : ''}` : `${index}${child.label ? '(' + child.label + ')' : ''}`
})) }))
}); });

View File

@ -485,7 +485,7 @@ export const ACTION_TYPE_TREE = (manager: any): RendererPluginAction[] => {
) )
}, },
{ {
name: 'args', name: 'dialog',
label: '弹框内容', label: '弹框内容',
mode: 'horizontal', mode: 'horizontal',
required: true, required: true,

View File

@ -693,13 +693,17 @@ export default class CRUD extends React.Component<CRUDProps, any> {
const idx: number = (ctx as any).index; const idx: number = (ctx as any).index;
const length = store.items.length; const length = store.items.length;
stopAutoRefreshWhenModalIsOpen && clearTimeout(this.timer); stopAutoRefreshWhenModalIsOpen && clearTimeout(this.timer);
store.openDialog(ctx, { store.openDialog(
hasNext: idx < length - 1, ctx,
nextIndex: idx + 1, {
hasPrev: idx > 0, hasNext: idx < length - 1,
prevIndex: idx - 1, nextIndex: idx + 1,
index: idx hasPrev: idx > 0,
}); prevIndex: idx - 1,
index: idx
},
action.callback
);
} else if (action.actionType === 'ajax') { } else if (action.actionType === 'ajax') {
store.setCurrentAction(action); store.setCurrentAction(action);
const data = ctx; const data = ctx;

View File

@ -899,7 +899,7 @@ export class DialogRenderer extends Dialog {
} }
} else if (action.actionType === 'dialog') { } else if (action.actionType === 'dialog') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDialog(data); store.openDialog(data, undefined, action.callback);
} else if (action.actionType === 'drawer') { } else if (action.actionType === 'drawer') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDrawer(data); store.openDrawer(data);

View File

@ -832,7 +832,7 @@ export class DrawerRenderer extends Drawer {
store.openDrawer(data); store.openDrawer(data);
} else if (action.actionType === 'dialog') { } else if (action.actionType === 'dialog') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDialog(data); store.openDialog(data, undefined, action.callback);
} else if (action.actionType === 'reload') { } else if (action.actionType === 'reload') {
store.setCurrentAction(action); store.setCurrentAction(action);
action.target && scoped.reload(action.target, data); action.target && scoped.reload(action.target, data);

View File

@ -484,7 +484,7 @@ export default class Page extends React.Component<PageProps> {
if (action.actionType === 'dialog') { if (action.actionType === 'dialog') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDialog(ctx, undefined, undefined, delegate); store.openDialog(ctx, undefined, action.callback, delegate);
} else if (action.actionType === 'drawer') { } else if (action.actionType === 'drawer') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDrawer(ctx, undefined, undefined, delegate); store.openDrawer(ctx, undefined, undefined, delegate);

View File

@ -650,7 +650,7 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
this.form.reset(); this.form.reset();
} else if (action.actionType === 'dialog') { } else if (action.actionType === 'dialog') {
store.setCurrentAction(action); store.setCurrentAction(action);
store.openDialog(data); store.openDialog(data, undefined, action.callback);
} else if (action.actionType === 'ajax') { } else if (action.actionType === 'ajax') {
if (!action.api) { if (!action.api) {
return env.alert(`当 actionType 为 ajax 时,请设置 api 属性`); return env.alert(`当 actionType 为 ajax 时,请设置 api 属性`);