diff --git a/packages/core/src/App.ts b/packages/core/src/App.ts index ecbec4b1..974e28fb 100644 --- a/packages/core/src/App.ts +++ b/packages/core/src/App.ts @@ -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({ diff --git a/packages/core/src/Node.ts b/packages/core/src/Node.ts index 1f4ad788..1bccc1fc 100644 --- a/packages/core/src/Node.ts +++ b/packages/core/src/Node.ts @@ -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 }); } } } diff --git a/packages/editor/src/components/CodeDraftEditor.vue b/packages/editor/src/components/CodeDraftEditor.vue index 72cff041..b85f7ac4 100644 --- a/packages/editor/src/components/CodeDraftEditor.vue +++ b/packages/editor/src/components/CodeDraftEditor.vue @@ -25,6 +25,7 @@ diff --git a/packages/editor/src/fields/EventSelect.vue b/packages/editor/src/fields/EventSelect.vue new file mode 100644 index 00000000..689a38a2 --- /dev/null +++ b/packages/editor/src/fields/EventSelect.vue @@ -0,0 +1,216 @@ + + + diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index b5ec9a4e..18bffa53 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -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); }, }; diff --git a/packages/editor/src/services/codeBlock.ts b/packages/editor/src/services/codeBlock.ts index 2e02bbba..ce2aadaf 100644 --- a/packages/editor/src/services/codeBlock.ts +++ b/packages/editor/src/services/codeBlock.ts @@ -171,7 +171,7 @@ class CodeBlock extends BaseService { /** * 设置编辑状态 - * @param {boolean} 是否可编辑 + * @param {boolean} status 是否可编辑 * @returns {void} */ public async setEditStatus(status: boolean): Promise { diff --git a/packages/editor/src/theme/event.scss b/packages/editor/src/theme/event.scss new file mode 100644 index 00000000..aee5bf71 --- /dev/null +++ b/packages/editor/src/theme/event.scss @@ -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%; +} diff --git a/packages/editor/src/theme/theme.scss b/packages/editor/src/theme/theme.scss index 083faa04..dbad8718 100644 --- a/packages/editor/src/theme/theme.scss +++ b/packages/editor/src/theme/theme.scss @@ -12,5 +12,6 @@ @import "./code-editor.scss"; @import "./icon.scss"; @import "./code-block.scss"; +@import "./event.scss"; @import "./layout.scss"; @import "./breadcrumb.scss"; diff --git a/packages/editor/src/type.ts b/packages/editor/src/type.ts index 43a4e933..43cf2960 100644 --- a/packages/editor/src/type.ts +++ b/packages/editor/src/type.ts @@ -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; +} diff --git a/packages/editor/src/utils/props.ts b/packages/editor/src/utils/props.ts index 0b8a4b23..98cd42a7 100644 --- a/packages/editor/src/utils/props.ts +++ b/packages/editor/src/utils/props.ts @@ -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', }, ], }, diff --git a/packages/form/src/containers/GroupListItem.vue b/packages/form/src/containers/GroupListItem.vue index 4d474d63..4cc74c48 100644 --- a/packages/form/src/containers/GroupListItem.vue +++ b/packages/form/src/containers/GroupListItem.vue @@ -1,11 +1,9 @@