mirror of
				https://github.com/Tencent/tmagic-editor.git
				synced 2025-11-04 10:49:51 +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 { 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 Env from './Env';
 | 
				
			||||||
import { bindCommonEventListener, isCommonMethod, triggerCommonMethod } from './events';
 | 
					import { bindCommonEventListener, isCommonMethod, triggerCommonMethod } from './events';
 | 
				
			||||||
@ -37,7 +48,7 @@ interface AppOptionsConfig {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface EventCache {
 | 
					interface EventCache {
 | 
				
			||||||
  eventConfig: EventItemConfig;
 | 
					  eventConfig: CompItemConfig | DeprecatedEventConfig;
 | 
				
			||||||
  fromCpt: any;
 | 
					  fromCpt: any;
 | 
				
			||||||
  args: 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;
 | 
					    const { name } = event;
 | 
				
			||||||
    this.on(`${name}_${id}`, (fromCpt: Node, ...args) => {
 | 
					    this.on(`${name}_${id}`, async (fromCpt: Node, ...args) => {
 | 
				
			||||||
      this.eventHandler(event, fromCpt, args);
 | 
					      await this.eventHandler(event, fromCpt, args);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -235,11 +246,53 @@ class App extends EventEmitter {
 | 
				
			|||||||
    return super.emit(name, node, ...args);
 | 
					    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('当前没有页面');
 | 
					    if (!this.page) throw new Error('当前没有页面');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { method: methodName, to } = eventConfig;
 | 
					    const { method: methodName, to } = eventConfig;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const toNode = this.page.getNode(to);
 | 
					    const toNode = this.page.getNode(to);
 | 
				
			||||||
    if (!toNode) throw `ID为${to}的组件不存在`;
 | 
					    if (!toNode) throw `ID为${to}的组件不存在`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -249,7 +302,7 @@ class App extends EventEmitter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (toNode.instance) {
 | 
					    if (toNode.instance) {
 | 
				
			||||||
      if (typeof toNode.instance[methodName] === 'function') {
 | 
					      if (typeof toNode.instance[methodName] === 'function') {
 | 
				
			||||||
        toNode.instance[methodName](fromCpt, ...args);
 | 
					        await toNode.instance[methodName](fromCpt, ...args);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.addEventToMap({
 | 
					      this.addEventToMap({
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import { EventEmitter } from 'events';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { isEmpty } from 'lodash-es';
 | 
					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 App from './App';
 | 
				
			||||||
import type Page from './Page';
 | 
					import type Page from './Page';
 | 
				
			||||||
@ -37,7 +37,7 @@ class Node extends EventEmitter {
 | 
				
			|||||||
  public style?: {
 | 
					  public style?: {
 | 
				
			||||||
    [key: string]: any;
 | 
					    [key: string]: any;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  public events?: EventItemConfig[];
 | 
					  public events?: DeprecatedEventConfig[] | EventConfig[];
 | 
				
			||||||
  public instance?: any;
 | 
					  public instance?: any;
 | 
				
			||||||
  public page?: Page;
 | 
					  public page?: Page;
 | 
				
			||||||
  public parent?: Node;
 | 
					  public parent?: Node;
 | 
				
			||||||
@ -86,7 +86,7 @@ class Node extends EventEmitter {
 | 
				
			|||||||
      const eventConfigQueue = this.app.eventQueueMap[instance.config.id] || [];
 | 
					      const eventConfigQueue = this.app.eventQueueMap[instance.config.id] || [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (let eventConfig = eventConfigQueue.shift(); eventConfig; eventConfig = eventConfigQueue.shift()) {
 | 
					      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');
 | 
					      await this.runCodeBlock('mounted');
 | 
				
			||||||
@ -99,11 +99,11 @@ class Node extends EventEmitter {
 | 
				
			|||||||
      await this.data[hook](this);
 | 
					      await this.data[hook](this);
 | 
				
			||||||
      return;
 | 
					      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) {
 | 
					    for (const item of this.data[hook].hookData) {
 | 
				
			||||||
      const { codeId, params = {} } = item;
 | 
					      const { codeId, params = {} } = item;
 | 
				
			||||||
      if (this.app.codeDsl[codeId] && typeof this.app?.codeDsl[codeId]?.content === 'function') {
 | 
					      if (this.app.codeDsl![codeId] && typeof this.app.codeDsl![codeId]?.content === 'function') {
 | 
				
			||||||
        await this.app.codeDsl[codeId].content({ app: this.app, params });
 | 
					        await this.app.codeDsl![codeId].content({ app: this.app, params });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,7 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
<script lang="ts" setup name="MEditorCodeDraftEditor">
 | 
					<script lang="ts" setup name="MEditorCodeDraftEditor">
 | 
				
			||||||
import { computed, inject, ref, watchEffect } from 'vue';
 | 
					import { computed, inject, ref, watchEffect } from 'vue';
 | 
				
			||||||
 | 
					import type { Action } from 'element-plus';
 | 
				
			||||||
import type * as monaco from 'monaco-editor';
 | 
					import type * as monaco from 'monaco-editor';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
 | 
					import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
 | 
				
			||||||
@ -109,18 +110,21 @@ const close = async (): Promise<void> => {
 | 
				
			|||||||
  if (codeDraft) {
 | 
					  if (codeDraft) {
 | 
				
			||||||
    tMagicMessageBox
 | 
					    tMagicMessageBox
 | 
				
			||||||
      .confirm('您有代码修改未保存,是否保存后再关闭?', '提示', {
 | 
					      .confirm('您有代码修改未保存,是否保存后再关闭?', '提示', {
 | 
				
			||||||
        confirmButtonText: '确认',
 | 
					        confirmButtonText: '保存并关闭',
 | 
				
			||||||
        cancelButtonText: '取消',
 | 
					        cancelButtonText: '直接关闭',
 | 
				
			||||||
        type: 'warning',
 | 
					        type: 'warning',
 | 
				
			||||||
 | 
					        distinguishCancelAndClose: true,
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .then(async () => {
 | 
					      .then(async () => {
 | 
				
			||||||
        // 保存之后再关闭
 | 
					        // 保存之后再关闭
 | 
				
			||||||
        saveAndClose();
 | 
					        saveAndClose();
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .catch(() => {
 | 
					      .catch((action: Action) => {
 | 
				
			||||||
 | 
					        if (action === 'cancel') {
 | 
				
			||||||
          // 删除草稿 直接关闭
 | 
					          // 删除草稿 直接关闭
 | 
				
			||||||
          services?.codeBlockService.removeCodeDraft(props.id);
 | 
					          services?.codeBlockService.removeCodeDraft(props.id);
 | 
				
			||||||
          emit('close');
 | 
					          emit('close');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    emit('close');
 | 
					    emit('close');
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="m-fields-code-select">
 | 
					  <div class="m-fields-code-select" :class="config.className">
 | 
				
			||||||
    <m-form-table
 | 
					    <m-form-table
 | 
				
			||||||
      :config="tableConfig"
 | 
					      :config="tableConfig"
 | 
				
			||||||
      :model="model[name]"
 | 
					      :model="model[name]"
 | 
				
			||||||
@ -11,7 +11,7 @@
 | 
				
			|||||||
    >
 | 
					    >
 | 
				
			||||||
      <template #operateCol="{ scope }">
 | 
					      <template #operateCol="{ scope }">
 | 
				
			||||||
        <Icon
 | 
					        <Icon
 | 
				
			||||||
          v-if="scope.row.codeId"
 | 
					          v-if="scope.row.codeId && config.editable"
 | 
				
			||||||
          :icon="editable ? Edit : View"
 | 
					          :icon="editable ? Edit : View"
 | 
				
			||||||
          class="edit-icon"
 | 
					          class="edit-icon"
 | 
				
			||||||
          @click="editCode(scope.row.codeId)"
 | 
					          @click="editCode(scope.row.codeId)"
 | 
				
			||||||
@ -35,15 +35,25 @@ const services = inject<Services>('services');
 | 
				
			|||||||
const mForm = inject<FormState>('mForm');
 | 
					const mForm = inject<FormState>('mForm');
 | 
				
			||||||
const emit = defineEmits(['change']);
 | 
					const emit = defineEmits(['change']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps<{
 | 
					const props = withDefaults(
 | 
				
			||||||
 | 
					  defineProps<{
 | 
				
			||||||
    config: {
 | 
					    config: {
 | 
				
			||||||
      tableConfig?: TableConfig;
 | 
					      tableConfig?: TableConfig;
 | 
				
			||||||
 | 
					      className?: string;
 | 
				
			||||||
 | 
					      editable?: boolean;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    model: any;
 | 
					    model: any;
 | 
				
			||||||
    prop: string;
 | 
					    prop: string;
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
  size: 'mini' | 'small' | 'medium';
 | 
					    size: 'small' | 'default' | 'large';
 | 
				
			||||||
}>();
 | 
					  }>(),
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    config: () => ({
 | 
				
			||||||
 | 
					      editable: true,
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
 | 
					const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const tableConfig = computed<FormItem>(() => {
 | 
					const tableConfig = computed<FormItem>(() => {
 | 
				
			||||||
@ -80,7 +90,7 @@ const tableConfig = computed<FormItem>(() => {
 | 
				
			|||||||
        itemsFunction: (row: HookData) => {
 | 
					        itemsFunction: (row: HookData) => {
 | 
				
			||||||
          const paramsConfig = getParamsConfig(row.codeId);
 | 
					          const paramsConfig = getParamsConfig(row.codeId);
 | 
				
			||||||
          // 如果参数没有填值,则使用createValues补全空值
 | 
					          // 如果参数没有填值,则使用createValues补全空值
 | 
				
			||||||
          if (isEmpty(row.params) || !row.params) {
 | 
					          if (!row.params || isEmpty(row.params)) {
 | 
				
			||||||
            createValues(mForm, paramsConfig, {}, row.params);
 | 
					            createValues(mForm, paramsConfig, {}, row.params);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          return paramsConfig;
 | 
					          return paramsConfig;
 | 
				
			||||||
@ -124,6 +134,7 @@ const getParamsConfig = (codeId: Id): CodeParamStatement[] => {
 | 
				
			|||||||
  return paramStatements.map((paramState: CodeParamStatement) => ({
 | 
					  return paramStatements.map((paramState: CodeParamStatement) => ({
 | 
				
			||||||
    labelWidth: '100px',
 | 
					    labelWidth: '100px',
 | 
				
			||||||
    text: paramState.name,
 | 
					    text: paramState.name,
 | 
				
			||||||
 | 
					    inline: true,
 | 
				
			||||||
    ...paramState,
 | 
					    ...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 Code from './fields/Code.vue';
 | 
				
			||||||
import CodeLink from './fields/CodeLink.vue';
 | 
					import CodeLink from './fields/CodeLink.vue';
 | 
				
			||||||
import CodeSelect from './fields/CodeSelect.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 uiSelect from './fields/UISelect.vue';
 | 
				
			||||||
import CodeEditor from './layouts/CodeEditor.vue';
 | 
					import CodeEditor from './layouts/CodeEditor.vue';
 | 
				
			||||||
import { setConfig } from './utils/config';
 | 
					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 ComponentListPanel } from './layouts/sidebar/ComponentListPanel.vue';
 | 
				
			||||||
export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue';
 | 
					export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue';
 | 
				
			||||||
export { default as CodeSelect } from './fields/CodeSelect.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 CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
 | 
				
			||||||
export { default as PropsPanel } from './layouts/PropsPanel.vue';
 | 
					export { default as PropsPanel } from './layouts/PropsPanel.vue';
 | 
				
			||||||
export { default as ToolButton } from './components/ToolButton.vue';
 | 
					export { default as ToolButton } from './components/ToolButton.vue';
 | 
				
			||||||
@ -68,5 +72,7 @@ export default {
 | 
				
			|||||||
    app.component('m-fields-vs-code', Code);
 | 
					    app.component('m-fields-vs-code', Code);
 | 
				
			||||||
    app.component('magic-code-editor', CodeEditor);
 | 
					    app.component('magic-code-editor', CodeEditor);
 | 
				
			||||||
    app.component('m-fields-code-select', CodeSelect);
 | 
					    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}
 | 
					   * @returns {void}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public async setEditStatus(status: boolean): Promise<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 "./code-editor.scss";
 | 
				
			||||||
@import "./icon.scss";
 | 
					@import "./icon.scss";
 | 
				
			||||||
@import "./code-block.scss";
 | 
					@import "./code-block.scss";
 | 
				
			||||||
 | 
					@import "./event.scss";
 | 
				
			||||||
@import "./layout.scss";
 | 
					@import "./layout.scss";
 | 
				
			||||||
@import "./breadcrumb.scss";
 | 
					@import "./breadcrumb.scss";
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import type { Component } from 'vue';
 | 
					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 { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
 | 
				
			||||||
import type StageCore from '@tmagic/stage';
 | 
					import type StageCore from '@tmagic/stage';
 | 
				
			||||||
import type {
 | 
					import type {
 | 
				
			||||||
@ -410,3 +410,18 @@ export interface HistoryState {
 | 
				
			|||||||
  canRedo: boolean;
 | 
					  canRedo: boolean;
 | 
				
			||||||
  canUndo: 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 { FormConfig, FormState } from '@tmagic/form';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import editorService from '../services/editor';
 | 
					 | 
				
			||||||
import eventsService from '../services/events';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 统一为组件属性表单加上事件、高级、样式配置
 | 
					 * 统一为组件属性表单加上事件、高级、样式配置
 | 
				
			||||||
 * @param config 组件属性配置
 | 
					 * @param config 组件属性配置
 | 
				
			||||||
@ -183,39 +180,8 @@ export const fillConfig = (config: FormConfig = []) => [
 | 
				
			|||||||
        title: '事件',
 | 
					        title: '事件',
 | 
				
			||||||
        items: [
 | 
					        items: [
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            type: 'table',
 | 
					 | 
				
			||||||
            name: 'events',
 | 
					            name: 'events',
 | 
				
			||||||
            items: [
 | 
					            type: 'event-select',
 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
                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,
 | 
					 | 
				
			||||||
                  }));
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,9 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="m-fields-group-list-item">
 | 
					  <div class="m-fields-group-list-item">
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <TMagicIcon style="margin-right: 7px" @click="expandHandler"
 | 
					      <TMagicButton text :disabled="disabled" :icon="expand ? CaretBottom : CaretRight" @click="expandHandler">{{
 | 
				
			||||||
        ><CaretBottom v-if="expand" /><CaretRight v-else
 | 
					        title
 | 
				
			||||||
      /></TMagicIcon>
 | 
					      }}</TMagicButton>
 | 
				
			||||||
 | 
					 | 
				
			||||||
      <TMagicButton text :disabled="disabled" @click="expandHandler">{{ title }}</TMagicButton>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <TMagicButton
 | 
					      <TMagicButton
 | 
				
			||||||
        v-show="showDelete(parseInt(String(index)))"
 | 
					        v-show="showDelete(parseInt(String(index)))"
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,11 @@
 | 
				
			|||||||
    :body-style="{ display: expand ? 'block' : 'none' }"
 | 
					    :body-style="{ display: expand ? 'block' : 'none' }"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <template #header>
 | 
					    <template #header>
 | 
				
			||||||
      <div class="clearfix">
 | 
					      <div style="width: 100%; display: flex; align-items: center">
 | 
				
			||||||
        <a href="javascript:" style="width: 100%; display: block" @click="expand = !expand">
 | 
					        <TMagicButton style="padding: 0" text :icon="expand ? CaretBottom : CaretRight" @click="expand = !expand">
 | 
				
			||||||
          <TMagicIcon><CaretBottom v-if="expand" /><CaretRight v-else /></TMagicIcon> {{ filter(config.title) }}
 | 
					        </TMagicButton>
 | 
				
			||||||
        <span v-if="config && config.extra" v-html="config.extra" class="m-form-tip"></span>
 | 
					        <span v-if="config && config.extra" v-html="config.extra" class="m-form-tip"></span>
 | 
				
			||||||
        </a>
 | 
					        <slot name="header">{{ filter(config.title) }}</slot>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -61,7 +61,7 @@
 | 
				
			|||||||
import { computed, inject, ref } from 'vue';
 | 
					import { computed, inject, ref } from 'vue';
 | 
				
			||||||
import { CaretBottom, CaretRight } from '@element-plus/icons-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 { FormState, PanelConfig } from '../schema';
 | 
				
			||||||
import { filterFunction } from '../utils/form';
 | 
					import { filterFunction } from '../utils/form';
 | 
				
			||||||
@ -73,7 +73,7 @@ const props = defineProps<{
 | 
				
			|||||||
  lastValues?: any;
 | 
					  lastValues?: any;
 | 
				
			||||||
  isCompare?: boolean;
 | 
					  isCompare?: boolean;
 | 
				
			||||||
  config: PanelConfig;
 | 
					  config: PanelConfig;
 | 
				
			||||||
  name: string;
 | 
					  name?: string;
 | 
				
			||||||
  labelWidth?: string;
 | 
					  labelWidth?: string;
 | 
				
			||||||
  prop?: string;
 | 
					  prop?: string;
 | 
				
			||||||
  size?: string;
 | 
					  size?: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -24,15 +24,51 @@ export enum NodeType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export type Id = string | number;
 | 
					export type Id = string | number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface EventItemConfig {
 | 
					// 事件联动的动作类型
 | 
				
			||||||
 | 
					export enum ActionType {
 | 
				
			||||||
 | 
					  /** 联动组件 */
 | 
				
			||||||
 | 
					  COMP = 'comp',
 | 
				
			||||||
 | 
					  /** 联动代码 */
 | 
				
			||||||
 | 
					  CODE = 'code',
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 事件类型(已废弃,后续不建议继续使用) */
 | 
				
			||||||
 | 
					export interface DeprecatedEventConfig {
 | 
				
			||||||
 | 
					  /** 待触发的事件名称 */
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
  /** 被选中组件ID */
 | 
					  /** 被选中组件ID */
 | 
				
			||||||
  to: Id;
 | 
					  to: Id;
 | 
				
			||||||
  /** 被选中组件名称 */
 | 
					 | 
				
			||||||
  name: string;
 | 
					 | 
				
			||||||
  /** 触发事件后执行被选中组件的方法 */
 | 
					  /** 触发事件后执行被选中组件的方法 */
 | 
				
			||||||
  method: 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 {
 | 
					export interface MComponent {
 | 
				
			||||||
  /** 组件ID,默认为${type}_${number}}形式, 如:page_123 */
 | 
					  /** 组件ID,默认为${type}_${number}}形式, 如:page_123 */
 | 
				
			||||||
  id: Id;
 | 
					  id: Id;
 | 
				
			||||||
@ -43,7 +79,7 @@ export interface MComponent {
 | 
				
			|||||||
  /** 组件根Dom上的class */
 | 
					  /** 组件根Dom上的class */
 | 
				
			||||||
  className?: string;
 | 
					  className?: string;
 | 
				
			||||||
  /* 关联事件集合 */
 | 
					  /* 关联事件集合 */
 | 
				
			||||||
  events?: EventItemConfig[];
 | 
					  events?: EventConfig[] | DeprecatedEventConfig[];
 | 
				
			||||||
  /** 组件根Dom的style */
 | 
					  /** 组件根Dom的style */
 | 
				
			||||||
  style?: {
 | 
					  style?: {
 | 
				
			||||||
    [key: string]: any;
 | 
					    [key: string]: any;
 | 
				
			||||||
 | 
				
			|||||||
@ -28,9 +28,11 @@ export default {
 | 
				
			|||||||
      params: [
 | 
					      params: [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          name: 'age',
 | 
					          name: 'age',
 | 
				
			||||||
 | 
					          type: 'number',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          name: 'studentName',
 | 
					          name: 'studentName',
 | 
				
			||||||
 | 
					          type: 'text',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -64,7 +66,35 @@ export default {
 | 
				
			|||||||
        fontSize: '',
 | 
					        fontSize: '',
 | 
				
			||||||
        fontWeight: '',
 | 
					        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: {
 | 
					      created: {
 | 
				
			||||||
        hookType: 'code',
 | 
					        hookType: 'code',
 | 
				
			||||||
        hookData: [
 | 
					        hookData: [
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user