feat: service组件事件&动作

This commit is contained in:
lurunze1226 2022-04-14 19:12:30 +08:00
parent d9f0050259
commit ca72f0f1eb
8 changed files with 316 additions and 11 deletions

View File

@ -10,7 +10,7 @@ order: 63
amis 中部分组件,作为展示组件,自身没有**使用接口初始化数据域的能力**,例如:[Table](./table)、[Cards](./cards)、[List](./list)等,他们需要使用某些配置项,例如`source`,通过[数据映射](../../docs/concepts/data-mapping)功能,在当前的 **数据链** 中获取数据,并进行数据展示。
而`Service`组件就是专门为该类组件而生,它的功能是:**配置初始化接口,进行数据域的初始化,然后在`Service`内容器中配置子组件,这些子组件通过数据链的方法,获取`Service`所拉取到的数据**
而`Service`组件就是专门为该类组件而生,它的功能是:**配置初始化接口,进行数据域的初始化,然后在`Service`内容器中配置子组件,这些子组件通过数据链的方法,获取`Service`所拉取到的数据**
## 基本使用
@ -584,3 +584,18 @@ ws.on('connection', function connection(ws) {
| interval | `number` | | 轮询时间间隔(最低 3000) |
| silentPolling | `boolean` | `false` | 配置轮询时是否显示加载动画 |
| stopAutoRefreshWhen | [表达式](../../docs/concepts/expression) | | 配置停止轮询的条件 |
## 事件表
| 事件名称 | 事件参数 | 说明 |
| ----------------- | ---------------------- | -------------------- |
| fetchInited | `data: any` 数据域数据 | api 初始化完成 |
| fetchSchemaInited | `data: any` 数据域数据 | schemaApi 初始化完成 |
## 动作表
| 动作名称 | 动作配置 | 说明 |
| -------- | -------- | ----------------------------------------------- |
| reload | - | 重新加载,调用 api刷新数据域数据 |
| rebuild | - | 重新构建,调用 schemaApi重新构建容器内 Schema |
| setValue | - | 更新数据域数据 |

View File

@ -27,7 +27,7 @@ export default {
onEvent: {
click: {
actions: [
{
{
actionType: 'reset',
componentId: 'form-action-receiver'
}
@ -86,7 +86,7 @@ export default {
{
name: 'form-action-receiver',
id: 'form-action-receiver',
title: "表单用于接收上面按钮的动作派发form本身的事件",
title: '表单用于接收上面按钮的动作派发form本身的事件',
type: 'form',
debug: true,
api: '/api/mock2/form/saveForm',
@ -298,7 +298,7 @@ export default {
type: 'form',
debug: true,
api: '/api/mock2/form/saveForm',
title: "表单派发formItem的校验事件",
title: '表单派发formItem的校验事件',
data: {
data1: '初始化数据1',
data2: '初始化数据2'

View File

@ -0,0 +1,227 @@
export default {
type: 'page',
title: 'Service功能型容器',
regions: ['body', 'toolbar', 'header'],
body: [
{
type: 'tpl',
tpl: '事件',
inline: false,
wrapperComponent: 'h2'
},
{
type: 'tpl',
tpl: '<code>fetchInited</code> 事件',
inline: false,
wrapperComponent: 'h3'
},
{
type: 'action',
level: 'success',
label: 'fetchInited',
actionType: 'dialog',
dialog: {
title: 'fetchInited',
body: [
{
type: 'service',
name: 'service-api',
api: '/api/mock2/page/initData',
body: {
type: 'panel',
title: '$title',
body: '现在是:${date}'
},
onEvent: {
fetchInited: {
actions: [
{
actionType: 'toast',
msgType: 'success',
msg: 'API inited: <b>${date}</b>'
}
]
}
}
}
]
}
},
{
type: 'divider'
},
{
type: 'tpl',
tpl: '<code>fetchSchemaInited</code> 事件',
inline: false,
wrapperComponent: 'h3'
},
{
type: 'action',
level: 'info',
label: 'fetchSchemaInited',
actionType: 'dialog',
dialog: {
title: 'fetchSchemaInited',
body: [
{
type: 'service',
name: 'service-schema-api',
schemaApi: '/api/mock2/service/schema?type=form',
onEvent: {
fetchSchemaInited: {
actions: [
{
actionType: 'toast',
msgType: 'info',
msg: 'SchemaAPI inited: <b>title: ${title}</b>'
}
]
}
}
}
]
}
},
{
type: 'divider'
},
{
type: 'tpl',
tpl: '动作',
inline: false,
wrapperComponent: 'h2'
},
{
type: 'tpl',
tpl: '<code>reload</code> 动作',
inline: false,
wrapperComponent: 'h3'
},
{
type: 'action',
label: 'reload触发器',
level: 'primary',
className: 'mb-3',
onEvent: {
click: {
actions: [
{
actionType: 'reload',
componentId: 'service-reload'
}
]
}
}
},
{
type: 'service',
id: 'service-reload',
name: 'service-reload',
api: '/api/mock2/number/random',
body: {
type: 'panel',
title: 'reload动作',
body: '现在是:${random}'
}
},
{
type: 'divider'
},
{
type: 'tpl',
tpl: '<code>rebuild</code> 动作',
inline: false,
wrapperComponent: 'h3'
},
{
type: 'alert',
body: '请选择一种构建方式生成组件',
level: 'info',
showIcon: true,
className: 'mb-3',
visibleOn: 'this.schemaType == null'
},
{
type: 'button-group',
tiled: true,
className: 'mb-3',
buttons: ['form', 'tabs', 'crud'].map(schema => ({
type: 'action',
label: `构建${schema}`,
icon: 'fa fa-hammer',
onEvent: {
click: {
actions: [
{
actionType: 'rebuild',
componentId: 'service-rebuild',
args: {
schemaType: `${schema}`
}
}
]
}
}
}))
},
{
type: 'service',
id: 'service-rebuild',
name: 'service-rebuild',
schemaApi: {
url: '/api/mock2/service/schema?type=${schemaType}',
method: 'post',
sendOn: 'this.schemaType != null'
}
},
{
type: 'divider'
},
{
type: 'tpl',
tpl: '<code>setValue</code> 动作',
inline: false,
wrapperComponent: 'h3'
},
{
type: 'action',
label: 'setValue触发器',
level: 'primary',
className: 'mb-3',
onEvent: {
click: {
actions: [
{
actionType: 'setValue',
componentId: 'service-setvalue',
value: {language: ['🇨🇳 中国']}
}
]
}
}
},
{
type: 'service',
id: 'service-setvalue',
name: 'service-setvalue',
data: {
language: ['🇺🇸 美国']
},
body: {
type: 'panel',
title: 'setValue动作',
body: [
{
type: 'each',
name: 'language',
items: {
type: 'tpl',
tpl: "<span class='label label-default m-l-sm'><%= data.item %></span> "
}
}
]
}
}
]
};

View File

@ -86,6 +86,7 @@ import InputTreeEventSchema from './EventAction/InputTreeEvent';
import treeSelectEventSchema from './EventAction/treeSelectEvent';
import FormEventActionSchema from './EventAction/FormEvent';
import TransferEventSchema from './EventAction/TransferEvent';
import ServiceEventSchema from './EventAction/ServiceEvent';
import WizardSchema from './Wizard';
import ChartSchema from './Chart';
import EChartsEditorSchema from './ECharts';
@ -607,6 +608,11 @@ export const examples = [
label: '穿梭框类组件',
path: 'examples/event/transfer',
component: makeSchemaRenderer(TransferEventSchema)
},
{
label: 'Service组件',
path: 'examples/event/service',
component: makeSchemaRenderer(ServiceEventSchema)
}
]
},

View File

@ -38,7 +38,6 @@ export default {
}
]
},
{
name: 'service1',
type: 'service',

View File

@ -0,0 +1,18 @@
module.exports = function (req, res) {
const showError = req.query.error;
if (showError) {
return res.json({
status: 404,
msg: 'Not Found'
});
} else {
return res.json({
status: 0,
msg: '随机返回一个数字',
data: {
random: Math.random() * 1000
}
});
}
};

View File

@ -5,6 +5,7 @@ import {
ListenerContext,
registerAction
} from './Action';
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
/**
* toast
@ -15,7 +16,11 @@ export class ToastAction implements Action {
renderer: ListenerContext,
event: RendererEvent<any>
) {
event.context.env.notify?.(action.msgType || 'info', action.msg, action);
event.context.env.notify?.(
action.msgType || 'info',
resolveVariableAndFilter(action.msg, event?.data, '| raw'),
action
);
}
}

View File

@ -31,6 +31,9 @@ import {
} from '../Schema';
import {IIRendererStore} from '../store';
import type {ScopedComponentType} from '../Scoped';
import type {ListenerAction} from '../actions/Action';
/**
* Service
* https://baidu.gitee.io/amis/docs/components/service
@ -209,6 +212,32 @@ export default class Service extends React.Component<ServiceProps> {
}
}
doAction(action: ListenerAction, args: any) {
if (action?.actionType === 'rebuild') {
const {
schemaApi,
store,
dataProvider,
messages: {fetchSuccess, fetchFailed}
} = this.props;
store.updateData(args);
clearTimeout(this.timer);
if (isEffectiveApi(schemaApi, store.data)) {
store
.fetchSchema(schemaApi, store.data, {
successMessage: fetchSuccess,
errorMessage: fetchFailed
})
.then(this.afterSchemaFetch);
}
if (dataProvider) {
this.runDataProvider();
}
}
}
@autobind
initFetch() {
const {
@ -331,7 +360,10 @@ export default class Service extends React.Component<ServiceProps> {
// 初始化接口返回的是整个 response
// 保存 ajax 请求的时候返回时数据部分。
const data = result?.hasOwnProperty('ok') ? result.data : result;
const {onBulkChange} = this.props;
const {onBulkChange, dispatchEvent} = this.props;
dispatchEvent?.('fetchInited', data);
if (!isEmpty(data) && onBulkChange) {
onBulkChange(data);
}
@ -340,7 +372,10 @@ export default class Service extends React.Component<ServiceProps> {
}
afterSchemaFetch(schema: any) {
const {onBulkChange, formStore} = this.props;
const {onBulkChange, formStore, dispatchEvent} = this.props;
dispatchEvent?.('fetchSchemaInited', schema);
if (formStore && schema?.data && onBulkChange) {
onBulkChange && onBulkChange(schema.data);
}
@ -586,7 +621,7 @@ export class ServiceRenderer extends Service {
super(props);
const scoped = context;
scoped.registerComponent(this);
scoped.registerComponent(this as ScopedComponentType);
}
reload(subpath?: string, query?: any, ctx?: any, silent?: boolean) {
@ -613,7 +648,7 @@ export class ServiceRenderer extends Service {
componentWillUnmount() {
super.componentWillUnmount();
const scoped = this.context as IScopedContext;
scoped.unRegisterComponent(this);
scoped.unRegisterComponent(this as ScopedComponentType);
}
reloadTarget(target: string, data?: any) {
@ -622,6 +657,6 @@ export class ServiceRenderer extends Service {
}
setData(values: object) {
return super.afterDataFetch(values);
return this.props.store.updateData(values);
}
}