mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
Merge pull request #4053 from lurunze1226/feat-event-service
feat: service组件事件&动作
This commit is contained in:
commit
9110acf4d7
@ -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 | api 初始化数据 | api 初始化完成 |
|
||||
| fetchSchemaInited | schemaApi 初始化数据 | schemaApi 初始化完成 |
|
||||
|
||||
## 动作表
|
||||
|
||||
| 动作名称 | 动作配置 | 说明 |
|
||||
| -------- | -------- | ----------------------------------------------- |
|
||||
| reload | - | 重新加载,调用 api,刷新数据域数据 |
|
||||
| rebuild | - | 重新构建,调用 schemaApi,重新构建容器内 Schema |
|
||||
| setValue | - | 更新数据域数据 |
|
||||
|
@ -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'
|
||||
|
227
examples/components/EventAction/ServiceEvent.jsx
Normal file
227
examples/components/EventAction/ServiceEvent.jsx
Normal 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> "
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
@ -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';
|
||||
@ -608,6 +609,11 @@ export const examples = [
|
||||
label: '穿梭框类组件',
|
||||
path: 'examples/event/transfer',
|
||||
component: makeSchemaRenderer(TransferEventSchema)
|
||||
},
|
||||
{
|
||||
label: 'Service组件',
|
||||
path: 'examples/event/service',
|
||||
component: makeSchemaRenderer(ServiceEventSchema)
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -38,7 +38,6 @@ export default {
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'service1',
|
||||
type: 'service',
|
||||
|
18
mock/cfc/mock/number/random.js
Normal file
18
mock/cfc/mock/number/random.js
Normal 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
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
@ -5,6 +5,7 @@ import {
|
||||
ListenerContext,
|
||||
registerAction
|
||||
} from './Action';
|
||||
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
|
||||
|
||||
export interface IToastAction extends ListenerAction {
|
||||
msg: string;
|
||||
@ -31,7 +32,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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user