feat(editor,form,core,schema): 事件支持触发代码块

This commit is contained in:
parisma 2023-03-29 15:01:34 +08:00 committed by roymondchen
parent cfd2a6eee3
commit 39468f3b95
16 changed files with 563 additions and 86 deletions

View File

@ -18,7 +18,18 @@
import { EventEmitter } from 'events';
import type { CodeBlockDSL, EventItemConfig, Id, MApp } from '@tmagic/schema';
import { has, isEmpty } from 'lodash-es';
import {
ActionType,
CodeBlockDSL,
CodeItemConfig,
CompItemConfig,
DeprecatedEventConfig,
EventConfig,
Id,
MApp,
} from '@tmagic/schema';
import Env from './Env';
import { bindCommonEventListener, isCommonMethod, triggerCommonMethod } from './events';
@ -37,7 +48,7 @@ interface AppOptionsConfig {
}
interface EventCache {
eventConfig: EventItemConfig;
eventConfig: CompItemConfig | DeprecatedEventConfig;
fromCpt: any;
args: any[];
}
@ -221,10 +232,10 @@ class App extends EventEmitter {
}
}
public bindEvent(event: EventItemConfig, id: string) {
public bindEvent(event: EventConfig | DeprecatedEventConfig, id: string) {
const { name } = event;
this.on(`${name}_${id}`, (fromCpt: Node, ...args) => {
this.eventHandler(event, fromCpt, args);
this.on(`${name}_${id}`, async (fromCpt: Node, ...args) => {
await this.eventHandler(event, fromCpt, args);
});
}
@ -235,11 +246,53 @@ class App extends EventEmitter {
return super.emit(name, node, ...args);
}
public eventHandler(eventConfig: EventItemConfig, fromCpt: any, args: any[]) {
/**
*
* @param eventConfig
* @param fromCpt
* @param args
*/
public async eventHandler(eventConfig: EventConfig | DeprecatedEventConfig, fromCpt: any, args: any[]) {
if (has(eventConfig, 'actions')) {
// EventConfig类型
const { actions } = eventConfig as EventConfig;
for (const actionItem of actions) {
if (actionItem.actionType === ActionType.COMP) {
// 组件动作
await this.compActionHandler(actionItem as CompItemConfig, fromCpt, args);
} else if (actionItem.actionType === ActionType.CODE) {
// 执行代码块
await this.codeActionHandler(actionItem as CodeItemConfig);
}
}
} else {
// 兼容DeprecatedEventConfig类型 组件动作
await this.compActionHandler(eventConfig as DeprecatedEventConfig, fromCpt, args);
}
}
/**
*
* @param eventConfig
* @returns void
*/
public async codeActionHandler(eventConfig: CodeItemConfig) {
const { codeId = '', params = {} } = eventConfig;
if (!codeId || isEmpty(this.codeDsl)) return;
if (this.codeDsl![codeId] && typeof this.codeDsl![codeId]?.content === 'function') {
await this.codeDsl![codeId].content({ app: this, params });
}
}
/**
*
* @param eventConfig
* @returns void
*/
public async compActionHandler(eventConfig: CompItemConfig | DeprecatedEventConfig, fromCpt: any, args: any[]) {
if (!this.page) throw new Error('当前没有页面');
const { method: methodName, to } = eventConfig;
const toNode = this.page.getNode(to);
if (!toNode) throw `ID为${to}的组件不存在`;
@ -249,7 +302,7 @@ class App extends EventEmitter {
if (toNode.instance) {
if (typeof toNode.instance[methodName] === 'function') {
toNode.instance[methodName](fromCpt, ...args);
await toNode.instance[methodName](fromCpt, ...args);
}
} else {
this.addEventToMap({

View File

@ -20,7 +20,7 @@ import { EventEmitter } from 'events';
import { isEmpty } from 'lodash-es';
import { EventItemConfig, HookType, MComponent, MContainer, MPage } from '@tmagic/schema';
import { DeprecatedEventConfig, EventConfig, HookType, MComponent, MContainer, MPage } from '@tmagic/schema';
import type App from './App';
import type Page from './Page';
@ -37,7 +37,7 @@ class Node extends EventEmitter {
public style?: {
[key: string]: any;
};
public events?: EventItemConfig[];
public events?: DeprecatedEventConfig[] | EventConfig[];
public instance?: any;
public page?: Page;
public parent?: Node;
@ -86,7 +86,7 @@ class Node extends EventEmitter {
const eventConfigQueue = this.app.eventQueueMap[instance.config.id] || [];
for (let eventConfig = eventConfigQueue.shift(); eventConfig; eventConfig = eventConfigQueue.shift()) {
this.app.eventHandler(eventConfig.eventConfig, eventConfig.fromCpt, eventConfig.args);
this.app.compActionHandler(eventConfig.eventConfig, eventConfig.fromCpt, eventConfig.args);
}
await this.runCodeBlock('mounted');
@ -99,11 +99,11 @@ class Node extends EventEmitter {
await this.data[hook](this);
return;
}
if (this.data[hook]?.hookType !== HookType.CODE || !this.app.codeDsl || isEmpty(this.app?.codeDsl)) return;
if (this.data[hook]?.hookType !== HookType.CODE || isEmpty(this.app.codeDsl)) return;
for (const item of this.data[hook].hookData) {
const { codeId, params = {} } = item;
if (this.app.codeDsl[codeId] && typeof this.app?.codeDsl[codeId]?.content === 'function') {
await this.app.codeDsl[codeId].content({ app: this.app, params });
if (this.app.codeDsl![codeId] && typeof this.app.codeDsl![codeId]?.content === 'function') {
await this.app.codeDsl![codeId].content({ app: this.app, params });
}
}
}

View File

@ -25,6 +25,7 @@
</template>
<script lang="ts" setup name="MEditorCodeDraftEditor">
import { computed, inject, ref, watchEffect } from 'vue';
import type { Action } from 'element-plus';
import type * as monaco from 'monaco-editor';
import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
@ -109,18 +110,21 @@ const close = async (): Promise<void> => {
if (codeDraft) {
tMagicMessageBox
.confirm('您有代码修改未保存,是否保存后再关闭?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonText: '保存并关闭',
cancelButtonText: '直接关闭',
type: 'warning',
distinguishCancelAndClose: true,
})
.then(async () => {
//
saveAndClose();
})
.catch(() => {
// 稿
services?.codeBlockService.removeCodeDraft(props.id);
emit('close');
.catch((action: Action) => {
if (action === 'cancel') {
// 稿
services?.codeBlockService.removeCodeDraft(props.id);
emit('close');
}
});
} else {
emit('close');

View File

@ -1,5 +1,5 @@
<template>
<div class="m-fields-code-select">
<div class="m-fields-code-select" :class="config.className">
<m-form-table
:config="tableConfig"
:model="model[name]"
@ -11,7 +11,7 @@
>
<template #operateCol="{ scope }">
<Icon
v-if="scope.row.codeId"
v-if="scope.row.codeId && config.editable"
:icon="editable ? Edit : View"
class="edit-icon"
@click="editCode(scope.row.codeId)"
@ -35,15 +35,25 @@ const services = inject<Services>('services');
const mForm = inject<FormState>('mForm');
const emit = defineEmits(['change']);
const props = defineProps<{
config: {
tableConfig?: TableConfig;
};
model: any;
prop: string;
name: string;
size: 'mini' | 'small' | 'medium';
}>();
const props = withDefaults(
defineProps<{
config: {
tableConfig?: TableConfig;
className?: string;
editable?: boolean;
};
model: any;
prop: string;
name: string;
size: 'small' | 'default' | 'large';
}>(),
{
config: () => ({
editable: true,
}),
},
);
const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
const tableConfig = computed<FormItem>(() => {
@ -80,7 +90,7 @@ const tableConfig = computed<FormItem>(() => {
itemsFunction: (row: HookData) => {
const paramsConfig = getParamsConfig(row.codeId);
// 使createValues
if (isEmpty(row.params) || !row.params) {
if (!row.params || isEmpty(row.params)) {
createValues(mForm, paramsConfig, {}, row.params);
}
return paramsConfig;
@ -124,6 +134,7 @@ const getParamsConfig = (codeId: Id): CodeParamStatement[] => {
return paramStatements.map((paramState: CodeParamStatement) => ({
labelWidth: '100px',
text: paramState.name,
inline: true,
...paramState,
}));
};

View File

@ -0,0 +1,117 @@
<template>
<div class="m-fields-code-select-col">
<!-- 代码块下拉框 -->
<m-form-container :config="selectConfig" :model="model" @change="onParamsChangeHandler"></m-form-container>
<!-- 参数填写框 -->
<m-form-container :config="codeParamsConfig" :model="model" @change="onParamsChangeHandler"></m-form-container>
</div>
</template>
<script lang="ts" setup name="MEditorCodeSelectCol">
import { computed, defineEmits, defineProps, inject, ref, watch } from 'vue';
import { isEmpty, map } from 'lodash-es';
import { createValues, FieldsetConfig, FormState } from '@tmagic/form';
import { Id } from '@tmagic/schema';
import { CodeParamStatement, Services } from '../type';
const services = inject<Services>('services');
const mForm = inject<FormState>('mForm');
const emit = defineEmits(['change']);
const props = withDefaults(
defineProps<{
config: any;
model: any;
prop: string;
name: string;
size: 'small' | 'default' | 'large';
}>(),
{},
);
const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
const codeParamsConfig = ref<FieldsetConfig>({
type: 'fieldset',
items: [],
legend: '参数',
labelWidth: '70px',
name: 'params',
display: false,
});
const selectConfig = {
type: 'select',
text: '代码块',
name: 'codeId',
labelWidth: '70px',
options: () => {
if (codeDsl.value) {
return map(codeDsl.value, (value, key) => ({
text: `${value.name}${key}`,
label: `${value.name}${key}`,
value: key,
}));
}
return [];
},
onChange: (formState: any, codeId: Id, { model }: any) => {
// codeIdmodelcodeIdparams
model.params = {};
},
};
/**
* 根据代码块id获取代码块参数配置
* @param codeId 代码块ID
*/
const getParamItemsConfig = (codeId: Id): CodeParamStatement[] => {
if (!codeDsl.value) return [];
const paramStatements = codeDsl.value[codeId]?.params;
if (isEmpty(paramStatements)) return [];
return paramStatements.map((paramState: CodeParamStatement) => ({
labelWidth: '100px',
text: paramState.name,
...paramState,
}));
};
/**
* 根据代码块id获取参数fieldset表单配置
* @param codeId 代码块ID
*/
const getCodeParamsConfig = (codeId: Id) => {
const paramsConfig = getParamItemsConfig(codeId);
// 使createValues
if (!props.model.params || isEmpty(props.model.params)) {
props.model.params = {};
createValues(mForm, paramsConfig, {}, props.model.params);
}
codeParamsConfig.value = {
type: 'fieldset',
items: paramsConfig,
legend: '参数',
labelWidth: '70px',
name: 'params',
display: !isEmpty(paramsConfig),
};
};
/**
* 参数值修改更新
*/
const onParamsChangeHandler = () => {
emit('change', props.model);
};
//
// TODO onchangewatch
watch(
() => props.model.codeId,
(codeId: Id) => {
if (!codeId) return;
getCodeParamsConfig(codeId);
},
{
immediate: true,
},
);
</script>

View File

@ -0,0 +1,216 @@
<template>
<div class="m-fields-event-select">
<m-form-container
v-if="isOldVersion"
ref="eventForm"
:size="props.size"
:model="model"
:config="tableConfig"
@change="onChangeHandler"
></m-form-container>
<div v-else class="fullWidth">
<TMagicButton class="create-button" type="primary" size="small" @click="addEvent()">添加事件</TMagicButton>
<m-form-panel
v-for="(cardItem, index) in model[name]"
:key="index"
:config="actionsConfig"
:model="cardItem"
@change="onChangeHandler"
>
<template #header>
<m-form-container
class="fullWidth"
:config="eventNameConfig"
:model="cardItem"
@change="onChangeHandler"
></m-form-container>
<TMagicButton style="color: #f56c6c" text :icon="Delete" @click="removeEvent(index)"></TMagicButton>
</template>
</m-form-panel>
</div>
</div>
</template>
<script lang="ts" setup name="MEditorEventSelect">
import { computed, defineProps, inject } from 'vue';
import { Delete } from '@element-plus/icons-vue';
import { has } from 'lodash-es';
import { TMagicButton } from '@tmagic/design';
import { FormState } from '@tmagic/form';
import { ActionType } from '@tmagic/schema';
import { EventSelectConfig, Services } from '../type';
const services = inject<Services>('services');
const props = defineProps<{
config: EventSelectConfig;
model: any;
prop: string;
name: string;
size: 'small' | 'default' | 'large';
}>();
const emit = defineEmits(['change']);
//
const eventNameConfig = computed(() => {
const defaultEventNameConfig = {
name: 'name',
text: '事件',
type: 'select',
labelWidth: '40px',
options: (mForm: FormState, { formValue }: any) =>
services?.eventsService.getEvent(formValue.type).map((option: any) => ({
text: option.label,
value: option.value,
})),
};
return { ...defaultEventNameConfig, ...props.config.eventNameConfig };
});
//
const actionTypeConfig = computed(() => {
const defaultActionTypeConfig = {
name: 'actionType',
text: '联动类型',
labelWidth: '70px',
type: 'select',
defaultValue: ActionType.COMP,
options: () => [
{
text: '组件',
label: '组件',
value: ActionType.COMP,
},
{
text: '代码',
label: '代码',
value: ActionType.CODE,
},
],
};
return { ...defaultActionTypeConfig, ...props.config.actionTypeConfig };
});
//
const targetCompConfig = computed(() => {
const defaultTargetCompConfig = {
name: 'to',
text: '联动组件',
labelWidth: '70px',
type: 'ui-select',
display: (mForm: FormState, { model }: { model: Record<any, any> }) => model.actionType === ActionType.COMP,
};
return { ...defaultTargetCompConfig, ...props.config.targetCompConfig };
});
//
const compActionConfig = computed(() => {
const defaultCompActionConfig = {
name: 'method',
text: '动作',
labelWidth: '70px',
type: 'select',
display: (mForm: FormState, { model }: { model: Record<any, any> }) => model.actionType === ActionType.COMP,
options: (mForm: FormState, { model }: any) => {
const node = services?.editorService.getNodeById(model.to);
if (!node?.type) return [];
return services?.eventsService.getMethod(node.type).map((option: any) => ({
text: option.label,
value: option.value,
}));
},
};
return { ...defaultCompActionConfig, ...props.config.compActionConfig };
});
//
const codeActionConfig = computed(() => {
const defaultCodeActionConfig = {
type: 'code-select-col',
display: (mForm: FormState, { model }: { model: Record<any, any> }) => model.actionType === ActionType.CODE,
};
return { ...defaultCodeActionConfig, ...props.config.codeActionConfig };
});
//
const tableConfig = computed(() => ({
type: 'table',
name: 'events',
items: [
{
name: 'name',
label: '事件名',
type: eventNameConfig.value.type,
options: (mForm: FormState, { formValue }: any) =>
services?.eventsService.getEvent(formValue.type).map((option: any) => ({
text: option.label,
value: option.value,
})),
},
{
name: 'to',
label: '联动组件',
type: 'ui-select',
},
{
name: 'method',
label: '动作',
type: compActionConfig.value.type,
options: (mForm: FormState, { model }: any) => {
const node = services?.editorService.getNodeById(model.to);
if (!node?.type) return [];
return services?.eventsService.getMethod(node.type).map((option: any) => ({
text: option.label,
value: option.value,
}));
},
},
],
}));
//
const actionsConfig = computed(() => ({
items: [
{
type: 'group-list',
name: 'actions',
enableToggleMode: false,
items: [actionTypeConfig.value, targetCompConfig.value, compActionConfig.value, codeActionConfig.value],
},
],
}));
//
const isOldVersion = computed(() => {
if (props.model[props.name].length === 0) return false;
return !has(props.model[props.name][0], 'actions');
});
//
const addEvent = () => {
const defaultEvent = {
name: '',
actions: [],
};
if (!props.model[props.name]) {
props.model[props.name] = [];
}
props.model[props.name].push(defaultEvent);
onChangeHandler();
};
//
const removeEvent = (index: number) => {
if (!props.name) return;
props.model[props.name].splice(index, 1);
onChangeHandler();
};
const onChangeHandler = () => {
emit('change', props.model);
};
</script>

View File

@ -20,6 +20,8 @@ import { App } from 'vue';
import Code from './fields/Code.vue';
import CodeLink from './fields/CodeLink.vue';
import CodeSelect from './fields/CodeSelect.vue';
import CodeSelectCol from './fields/CodeSelectCol.vue';
import EventSelect from './fields/EventSelect.vue';
import uiSelect from './fields/UISelect.vue';
import CodeEditor from './layouts/CodeEditor.vue';
import { setConfig } from './utils/config';
@ -44,6 +46,8 @@ export { default as depService } from './services/dep';
export { default as ComponentListPanel } from './layouts/sidebar/ComponentListPanel.vue';
export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue';
export { default as CodeSelect } from './fields/CodeSelect.vue';
export { default as CodeSelectCol } from './fields/CodeSelectCol.vue';
export { default as EventSelect } from './fields/EventSelect.vue';
export { default as CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
export { default as PropsPanel } from './layouts/PropsPanel.vue';
export { default as ToolButton } from './components/ToolButton.vue';
@ -68,5 +72,7 @@ export default {
app.component('m-fields-vs-code', Code);
app.component('magic-code-editor', CodeEditor);
app.component('m-fields-code-select', CodeSelect);
app.component('m-fields-code-select-col', CodeSelectCol);
app.component('m-fields-event-select', EventSelect);
},
};

View File

@ -171,7 +171,7 @@ class CodeBlock extends BaseService {
/**
*
* @param {boolean}
* @param {boolean} status
* @returns {void}
*/
public async setEditStatus(status: boolean): Promise<void> {

View File

@ -0,0 +1,24 @@
.m-fields-event-select {
width: 100%;
.fullWidth {
width: 100%;
}
.m-form-panel .el-card__body {
padding: 10px 25px;
}
.event-select-code {
margin-left: 20px;
width: auto;
}
.m-form-panel {
margin: 10px 0px;
}
.el-card.is-always-shadow {
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.12);
}
}
.m-fields-code-select-col {
width: 100%;
}

View File

@ -12,5 +12,6 @@
@import "./code-editor.scss";
@import "./icon.scss";
@import "./code-block.scss";
@import "./event.scss";
@import "./layout.scss";
@import "./breadcrumb.scss";

View File

@ -18,7 +18,7 @@
import type { Component } from 'vue';
import type { FormConfig } from '@tmagic/form';
import type { FormConfig, FormItem } from '@tmagic/form';
import type { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
import type StageCore from '@tmagic/stage';
import type {
@ -410,3 +410,18 @@ export interface HistoryState {
canRedo: boolean;
canUndo: boolean;
}
export interface EventSelectConfig {
name: string;
type: 'event-select';
/** 事件名称表单配置 */
eventNameConfig?: FormItem;
/** 动作类型配置 */
actionTypeConfig?: FormItem;
/** 联动组件配置 */
targetCompConfig?: FormItem;
/** 联动组件动作配置 */
compActionConfig?: FormItem;
/** 联动代码配置 */
codeActionConfig?: FormItem;
}

View File

@ -18,9 +18,6 @@
import { FormConfig, FormState } from '@tmagic/form';
import editorService from '../services/editor';
import eventsService from '../services/events';
/**
*
* @param config
@ -183,39 +180,8 @@ export const fillConfig = (config: FormConfig = []) => [
title: '事件',
items: [
{
type: 'table',
name: 'events',
items: [
{
name: 'name',
label: '事件名',
type: 'select',
options: (mForm: FormState, { formValue }: any) =>
eventsService.getEvent(formValue.type).map((option) => ({
text: option.label,
value: option.value,
})),
},
{
name: 'to',
label: '联动组件',
type: 'ui-select',
},
{
name: 'method',
label: '动作',
type: 'select',
options: (mForm: FormState, { model }: any) => {
const node = editorService.getNodeById(model.to);
if (!node?.type) return [];
return eventsService.getMethod(node.type).map((option) => ({
text: option.label,
value: option.value,
}));
},
},
],
type: 'event-select',
},
],
},

View File

@ -1,11 +1,9 @@
<template>
<div class="m-fields-group-list-item">
<div>
<TMagicIcon style="margin-right: 7px" @click="expandHandler"
><CaretBottom v-if="expand" /><CaretRight v-else
/></TMagicIcon>
<TMagicButton text :disabled="disabled" @click="expandHandler">{{ title }}</TMagicButton>
<TMagicButton text :disabled="disabled" :icon="expand ? CaretBottom : CaretRight" @click="expandHandler">{{
title
}}</TMagicButton>
<TMagicButton
v-show="showDelete(parseInt(String(index)))"

View File

@ -5,11 +5,11 @@
:body-style="{ display: expand ? 'block' : 'none' }"
>
<template #header>
<div class="clearfix">
<a href="javascript:" style="width: 100%; display: block" @click="expand = !expand">
<TMagicIcon><CaretBottom v-if="expand" /><CaretRight v-else /></TMagicIcon> {{ filter(config.title) }}
<span v-if="config && config.extra" v-html="config.extra" class="m-form-tip"></span>
</a>
<div style="width: 100%; display: flex; align-items: center">
<TMagicButton style="padding: 0" text :icon="expand ? CaretBottom : CaretRight" @click="expand = !expand">
</TMagicButton>
<span v-if="config && config.extra" v-html="config.extra" class="m-form-tip"></span>
<slot name="header">{{ filter(config.title) }}</slot>
</div>
</template>
@ -61,7 +61,7 @@
import { computed, inject, ref } from 'vue';
import { CaretBottom, CaretRight } from '@element-plus/icons-vue';
import { TMagicCard, TMagicIcon } from '@tmagic/design';
import { TMagicButton, TMagicCard } from '@tmagic/design';
import { FormState, PanelConfig } from '../schema';
import { filterFunction } from '../utils/form';
@ -73,7 +73,7 @@ const props = defineProps<{
lastValues?: any;
isCompare?: boolean;
config: PanelConfig;
name: string;
name?: string;
labelWidth?: string;
prop?: string;
size?: string;

View File

@ -24,15 +24,51 @@ export enum NodeType {
export type Id = string | number;
export interface EventItemConfig {
// 事件联动的动作类型
export enum ActionType {
/** 联动组件 */
COMP = 'comp',
/** 联动代码 */
CODE = 'code',
}
/** 事件类型(已废弃,后续不建议继续使用) */
export interface DeprecatedEventConfig {
/** 待触发的事件名称 */
name: string;
/** 被选中组件ID */
to: Id;
/** 被选中组件名称 */
name: string;
/** 触发事件后执行被选中组件的方法 */
method: string;
}
export interface EventConfig {
/** 待触发的事件名称 */
name: string;
/** 动作响应配置 */
actions: EventActionItem[];
}
export interface CodeItemConfig {
/** 动作类型 */
actionType: ActionType;
/** 代码ID */
codeId: Id;
/** 代码参数 */
params?: object;
}
export interface CompItemConfig {
/** 动作类型 */
actionType: ActionType;
/** 被选中组件ID */
to: Id;
/** 触发事件后执行被选中组件的方法 */
method: string;
}
export type EventActionItem = CompItemConfig | CodeItemConfig;
export interface MComponent {
/** 组件ID默认为${type}_${number}}形式, 如page_123 */
id: Id;
@ -43,7 +79,7 @@ export interface MComponent {
/** 组件根Dom上的class */
className?: string;
/* 关联事件集合 */
events?: EventItemConfig[];
events?: EventConfig[] | DeprecatedEventConfig[];
/** 组件根Dom的style */
style?: {
[key: string]: any;

View File

@ -28,9 +28,11 @@ export default {
params: [
{
name: 'age',
type: 'number',
},
{
name: 'studentName',
type: 'text',
},
],
},
@ -64,7 +66,35 @@ export default {
fontSize: '',
fontWeight: '',
},
events: [],
events: [
{
name: 'magic:common:events:click', // 事件名
actions: [
{
actionType: 'code', // 联动动作类型
codeId: 'code_5336', // 代码块id
params: {
age: 12,
}, // 参数
},
{
actionType: 'comp',
to: 'overlay_2159', // 联动组件id
method: 'openOverlay', // 联动组件方法
},
],
},
{
name: 'magic:common:events:click', // 事件名
actions: [
{
actionType: 'code', // 联动动作类型
codeId: 'code_5316', // 代码块id
params: {},
},
],
},
],
created: {
hookType: 'code',
hookData: [