mirror of
				https://github.com/Tencent/tmagic-editor.git
				synced 2025-11-04 02:28:04 +08:00 
			
		
		
		
	feat(editor,form,core,schema): 事件支持触发代码块
This commit is contained in:
		
							parent
							
								
									cfd2a6eee3
								
							
						
					
					
						commit
						39468f3b95
					
				@ -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({
 | 
			
		||||
 | 
			
		||||
@ -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 });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -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');
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
  }));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										117
									
								
								packages/editor/src/fields/CodeSelectCol.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								packages/editor/src/fields/CodeSelectCol.vue
									
									
									
									
									
										Normal 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) => {
 | 
			
		||||
    // 通过下拉框选择的codeId变化后修正model的值,避免写入其他codeId的params
 | 
			
		||||
    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 onchange在watch之前触发
 | 
			
		||||
watch(
 | 
			
		||||
  () => props.model.codeId,
 | 
			
		||||
  (codeId: Id) => {
 | 
			
		||||
    if (!codeId) return;
 | 
			
		||||
    getCodeParamsConfig(codeId);
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    immediate: true,
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										216
									
								
								packages/editor/src/fields/EventSelect.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								packages/editor/src/fields/EventSelect.vue
									
									
									
									
									
										Normal 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>
 | 
			
		||||
@ -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);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -171,7 +171,7 @@ class CodeBlock extends BaseService {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 设置编辑状态
 | 
			
		||||
   * @param {boolean} 是否可编辑
 | 
			
		||||
   * @param {boolean} status 是否可编辑
 | 
			
		||||
   * @returns {void}
 | 
			
		||||
   */
 | 
			
		||||
  public async setEditStatus(status: boolean): Promise<void> {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								packages/editor/src/theme/event.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								packages/editor/src/theme/event.scss
									
									
									
									
									
										Normal 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%;
 | 
			
		||||
}
 | 
			
		||||
@ -12,5 +12,6 @@
 | 
			
		||||
@import "./code-editor.scss";
 | 
			
		||||
@import "./icon.scss";
 | 
			
		||||
@import "./code-block.scss";
 | 
			
		||||
@import "./event.scss";
 | 
			
		||||
@import "./layout.scss";
 | 
			
		||||
@import "./breadcrumb.scss";
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
@ -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)))"
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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: [
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user