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 |
### 打开对话框
### 打开确认弹窗
通过配置`actionType: 'alert'`或`actionType: 'confirm'`打开不同对话框,该动作分别需实现 env.alert: (msg: string) => void 和 env.confirm: (msg: string, title?: string) => boolean | Promise<boolean>
通过配置`actionType: 'confirmDialog'`打开确认对话框。确认对话框弹出后,如果选择取消操作,将不会执行该动作后面的动作。如下面的例子,点击确认之后将弹出`toast`提示,点击取消则不会提示
#### 提示对话框
**普通文本内容**
```schema
{
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` | - | 对话框提示内容 |
#### 确认对话框
动作需要实现 env.confirm: (msg: string, title?: string) => boolean | Promise&lt;boolean&gt;
```schema
{
@ -746,10 +708,16 @@ run action ajax
actions: [
{
actionType: 'confirmDialog',
args: {
dialog: {
title: '${title}',
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
{
type: 'page',
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啦'
}
}
]
}
}
}
]
}
```
**动作属性**
| 属性名 | 类型 | 默认值 | 说明 |
| ------ | -------- | ------ | -------------- |
| title | `string` | - | 对话框标题 |
| msg | `string` | - | 对话框提示内容 |
| ------ | ----------------------------- | ------ | ------------------------------------------------------------------- |
| 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);
} else if (action.actionType === 'dialog') {
store.setCurrentAction(action);
store.openDialog(ctx, undefined, undefined, delegate);
store.openDialog(ctx, undefined, action.callback, delegate);
} else if (action.actionType === 'drawer') {
store.setCurrentAction(action);
store.openDrawer(ctx, undefined, undefined, delegate);

View File

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

View File

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

View File

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

View File

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

View File

@ -1214,7 +1214,7 @@ export const updateComponentContext = (variables: any[]) => {
...child,
label:
index === 0
? `当前数据域${child.label ? '(' + child.label + ')' : ''}`
? `当前${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: '弹框内容',
mode: 'horizontal',
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 length = store.items.length;
stopAutoRefreshWhenModalIsOpen && clearTimeout(this.timer);
store.openDialog(ctx, {
store.openDialog(
ctx,
{
hasNext: idx < length - 1,
nextIndex: idx + 1,
hasPrev: idx > 0,
prevIndex: idx - 1,
index: idx
});
},
action.callback
);
} else if (action.actionType === 'ajax') {
store.setCurrentAction(action);
const data = ctx;

View File

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

View File

@ -832,7 +832,7 @@ export class DrawerRenderer extends Drawer {
store.openDrawer(data);
} else if (action.actionType === 'dialog') {
store.setCurrentAction(action);
store.openDialog(data);
store.openDialog(data, undefined, action.callback);
} else if (action.actionType === 'reload') {
store.setCurrentAction(action);
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') {
store.setCurrentAction(action);
store.openDialog(ctx, undefined, undefined, delegate);
store.openDialog(ctx, undefined, action.callback, delegate);
} else if (action.actionType === 'drawer') {
store.setCurrentAction(action);
store.openDrawer(ctx, undefined, undefined, delegate);

View File

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