From bc6969dd09936ed6be215dcc6140adf54f2d17a7 Mon Sep 17 00:00:00 2001 From: wang-xh Date: Thu, 14 Aug 2025 01:07:57 +0000 Subject: [PATCH 1/5] =?UTF-8?q?!1856=20=E8=A7=A3=E5=86=B3=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E5=8F=91=E5=B8=83=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E5=A4=B1=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98=20*=20fi?= =?UTF-8?q?x:=20=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E8=8F=9C=E5=8D=95=E6=97=B6=E4=BC=A0=E9=80=92=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E8=A1=A8=E5=8D=95id=EF=BC=9B=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E5=AE=9A=E5=88=B6=E6=94=AF=E6=8C=81=E5=9C=A8=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E9=9D=A2=E6=9D=BF=E4=B8=AD=E5=B1=95=E7=A4=BA=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E8=A1=A8=E5=8D=95=E5=9F=BA=E7=A1=80=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=EF=BC=9B=E6=9B=BF=E6=8D=A2=E7=BB=84=E5=90=88=E5=AD=90=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=90=8E=EF=BC=8C=E6=B8=85=E9=99=A4=E5=8E=9F=E6=9C=89?= =?UTF-8?q?=E7=9A=84=E9=80=9A=E8=AE=AF=E9=85=8D=E7=BD=AE=20*=20fix:=20?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=A4=96=E9=83=A8=E5=AE=B9=E5=99=A8=E6=97=B6?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E5=88=A0=E9=99=A4=E7=BB=84=E4=BB=B6=E9=80=9A?= =?UTF-8?q?=E8=AE=AF=E9=85=8D=E7=BD=AE=20*=20fix:=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E9=80=9A=E8=AE=AF=E4=B8=AD=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9A=84=E7=BB=84=E4=BB=B6=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20*=20=E4=BF=AE=E6=94=B9=E7=BB=84=E5=90=88?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E9=80=9A=E8=AE=AF=E7=9A=84=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E6=80=A7=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/entity-tree-view.component.tsx | 18 +++---- .../components/entity-tree-view.scss | 4 ++ .../form-designer/form-designer.component.tsx | 6 +-- .../composition/form-metadata-rtc.service.tsx | 2 +- .../types/form-property-config.json | 27 ---------- .../components/types/form-property-config.ts | 52 +++++++++++++++++++ .../external-container.property-config.ts | 8 ++- .../src/components/custom/custom-property.css | 5 +- 8 files changed, 71 insertions(+), 51 deletions(-) delete mode 100644 packages/designer/src/components/types/form-property-config.json create mode 100644 packages/designer/src/components/types/form-property-config.ts diff --git a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx index 995cb1d248a..155261f009e 100644 --- a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx +++ b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx @@ -141,17 +141,6 @@ export default defineComponent({ const { openNewFieldModal } = useOpenNewField(useFormSchema, newEntityCodeList, refreshEntityTree, serializedTreeData); const { openModifyFieldModal } = useOpenModifyField(useFormSchema, designViewModelUtils, refreshEntityTree, serializedTreeData, context); - /** 低代码:刷新实体(同步视图对象) */ - function renderHeader() { - if (designerMode !== DesignerMode.PC_RTC) { - return
-
- -
-
; - } - } - return () => { return
{{ - header: renderHeader, cellTemplate: ({ cell, row }) => { const rowData = row.raw; return <> @@ -183,6 +171,12 @@ export default defineComponent({ openModifyFieldModal(event, row.raw)}>
} + {/* 低代码表单实体节点,支持刷新实体数据 */} + {designerMode !== DesignerMode.PC_RTC && rowData.nodeType === 'entity' && !rowData.parent && +
+ +
+ } ; }, diff --git a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss index d45d08b8533..9212163ba4f 100644 --- a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss +++ b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss @@ -31,4 +31,8 @@ bottom: 0; background: #fcfdff; } + + .fv-grid-row.fv-grid-row-selected .toolbar-panel { + background: #dae9ff; + } } \ No newline at end of file diff --git a/packages/designer/src/components/components/form-designer/form-designer.component.tsx b/packages/designer/src/components/components/form-designer/form-designer.component.tsx index 0da86153b53..cd493444e61 100644 --- a/packages/designer/src/components/components/form-designer/form-designer.component.tsx +++ b/packages/designer/src/components/components/form-designer/form-designer.component.tsx @@ -3,7 +3,6 @@ import { ComponentSchema, DesignerComponentInstance, FDesignerCanvas, FTabs, FTa import { FormDesignerProps, formDesignerProps } from "./form-designer.props"; import { useComponentSchemaService } from '../../composition/component-schema.service'; import MonacoEditor from '../monaco-editor/monaco-editor.component'; -import modulePropertyConfig from '../../types/form-property-config.json'; import FEntityTreeView from '../entity-tree-view/components/entity-tree-view.component'; import { afterPropeControlPropertyChangedService } from "../../composition/control-property-changed.service"; import { UseDesignViewModel, UseFormSchema, UseSchemaService } from "../../types"; @@ -15,6 +14,7 @@ import { ExternalComponentSchema } from "./components/external-component-panel/c import { UseFormCommandService } from "../../../components/types/command"; import { useFormValidation } from "../../composition/use-form-validation"; import { DesignerMode } from "../../types/designer-context"; +import { resolveFormModulePropertyConfig } from "../../../components/types/form-property-config"; export default defineComponent({ name: 'FFormDesigner', @@ -192,7 +192,7 @@ export default defineComponent({ }; }); - propertyConfigSchemaMapForDesigner['Module'] = modulePropertyConfig; + propertyConfigSchemaMapForDesigner['Module'] = resolveFormModulePropertyConfig(designerMode);; const shouldRenderExternalComponentPanel = designerMode !== DesignerMode.PC_RTC; @@ -227,7 +227,7 @@ export default defineComponent({ if (selectionSchema?.type === 'Module') { propertyName.value = 'Module'; propertyPanelInstance?.value?.updateDesignerItem(null, selectionSchema.id); - focusingSchema.value = selectionSchema; + focusingSchema.value = Object.assign({}, useFormSchema.getFormMetadataBasicInfo(), { type: 'Module' }); clearComponentSelectionStyles(); } diff --git a/packages/designer/src/components/composition/form-metadata-rtc.service.tsx b/packages/designer/src/components/composition/form-metadata-rtc.service.tsx index 8d514940771..47aa19130ef 100644 --- a/packages/designer/src/components/composition/form-metadata-rtc.service.tsx +++ b/packages/designer/src/components/composition/form-metadata-rtc.service.tsx @@ -205,7 +205,7 @@ export function useRtcFormMetadata( dim1: formBasicInfo.dimension1, dim2: formBasicInfo.dimension2, isRtc: '1', - metadataId: formBasicInfo.id, + metadataId: formBasicInfo.rtcId, menuId: menuSelectedData.value.value.id }; diff --git a/packages/designer/src/components/types/form-property-config.json b/packages/designer/src/components/types/form-property-config.json deleted file mode 100644 index c84eac0932c..00000000000 --- a/packages/designer/src/components/types/form-property-config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "title": "module", - "description": "表单元数据属性配置", - "type": "object", - "categories": { - "basic": { - "title": "基本信息", - "properties": { - "id": { - "title": "表单元数据标识", - "type": "string", - "readonly": true - }, - "code": { - "title": "表单元数据编号", - "type": "string", - "readonly": true - }, - "name": { - "title": "表单元数据名称", - "type": "string", - "readonly": true - } - } - } - } -} \ No newline at end of file diff --git a/packages/designer/src/components/types/form-property-config.ts b/packages/designer/src/components/types/form-property-config.ts new file mode 100644 index 00000000000..925108314e8 --- /dev/null +++ b/packages/designer/src/components/types/form-property-config.ts @@ -0,0 +1,52 @@ +import { DesignerMode } from "./designer-context"; + +export function resolveFormModulePropertyConfig(designerMode: DesignerMode) { + return { + "title": "module", + "description": "表单元数据属性配置", + "type": "object", + "categories": { + "rtcBasic": { + "title": "扩展表单", + "hide": designerMode !== DesignerMode.PC_RTC, + "properties": { + "rtcId": { + "title": "表单元数据标识", + "type": "string", + "readonly": true + }, + "rtcCode": { + "title": "表单元数据编号", + "type": "string", + "readonly": true + }, + "rtcName": { + "title": "表单元数据名称", + "type": "string", + "readonly": true + } + } + }, + "basic": { + "title": designerMode === DesignerMode.PC_RTC ? "基础表单" : "基本信息", + "properties": { + "id": { + "title": "表单元数据标识", + "type": "string", + "readonly": true + }, + "code": { + "title": "表单元数据编号", + "type": "string", + "readonly": true + }, + "name": { + "title": "表单元数据名称", + "type": "string", + "readonly": true + } + } + } + } + } +}; diff --git a/packages/ui-vue/components/external-container/src/property-config/external-container.property-config.ts b/packages/ui-vue/components/external-container/src/property-config/external-container.property-config.ts index 2f79d903179..fb407faff4b 100644 --- a/packages/ui-vue/components/external-container/src/property-config/external-container.property-config.ts +++ b/packages/ui-vue/components/external-container/src/property-config/external-container.property-config.ts @@ -140,15 +140,13 @@ export class ExternalContainerProperty extends BaseControlProperty { communicationIds.map(communicationId => { const communication = communications.find(item => item.id === communicationId); if (communication?.source && communication.source.formId !== propertyData.externalComponent.id) { - communication.source.formId = propertyData.externalComponent.id; - communication.source.formCode = propertyData.externalComponent.code; - communication.source.componentId = ''; - communication.source.event = ''; - + communication.needDelete = true; needNotify = true; } }); + formSchema.module.communications = formSchema.module.communications.filter(item => !item.needDelete); if (needNotify) { + propertyData.onCommunication = ''; const notifyService: any = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; notifyService.warning({ message: '切换引入表单后,请重新配置组件通讯。' }); diff --git a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.css b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.css index ffa645de94e..a9de211a06b 100644 --- a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.css +++ b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.css @@ -1,6 +1,5 @@ .f-property-editor-customize-container { - width: 65%; - float: left; - margin-left: 3%; + width: 100%; + padding-left: 3%; background: #FFFFFF; } \ No newline at end of file -- Gitee From 71adb84526fca32fccaf929a9cde20b2b974a6c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=A3=E7=BB=B4=E6=B6=9B?= Date: Thu, 14 Aug 2025 01:10:35 +0000 Subject: [PATCH 2/5] =?UTF-8?q?!1861=20fix:=20=E8=A7=A3=E5=86=B3=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E8=A1=A8=E5=8D=95=E5=85=B3=E9=97=AD=E5=90=8E=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E3=80=82=20*=20chore:=20=E7=A7=BB=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E7=9A=84console.log=20*=20fix:=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E8=A1=A8=E5=8D=95=E5=85=B3=E9=97=AD=E5=90=8E?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E3=80=82=20*=20fix:=20=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E8=A2=AB=E7=BB=84=E5=90=88=E8=A1=A8=E5=8D=95=E7=9A=84=E5=88=97?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E4=BA=8B=E4=BB=B6=E6=97=A0=E6=B3=95=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E4=BA=8B=E4=BB=B6=E9=80=9A=E4=BF=A1=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../command-services/lib/dialog.service.ts | 18 ++-- .../lib/navigation-event.service.ts | 65 +++++++++++--- .../lib/navigation-middleware.service.ts | 57 +++++++++++-- .../lib/navigation.service.ts | 8 ++ packages/devkit/lib/module/module.ts | 35 +++++++- .../data-grid-component-config-resolver.ts | 26 +++--- .../modal-closed-event-handler.ts | 85 +++++++++++++++++++ .../renderer/src/event-handler/providers.ts | 4 +- 8 files changed, 259 insertions(+), 39 deletions(-) create mode 100644 packages/renderer/src/event-handler/modal-closed-event-handler.ts diff --git a/packages/command-services/lib/dialog.service.ts b/packages/command-services/lib/dialog.service.ts index 8f05a598f4d..149d031b934 100644 --- a/packages/command-services/lib/dialog.service.ts +++ b/packages/command-services/lib/dialog.service.ts @@ -173,16 +173,14 @@ export class DialogService { resizeable: true, enableEsc: true, showMaxButton: true, - showCloseButton: true + showCloseButton: true }; // 组件实例上的配置 instanceDialogConfig = instanceDialogConfig || {}; - // 构件中的窗口配置 - const { title } = dialogConfig; - - const newLookupDialogProps = { ...defaultDialogConfig, ...instanceDialogConfig, title }; + // 构造新的配置 + const newLookupDialogProps = { ...defaultDialogConfig, ...instanceDialogConfig, ...dialogConfig }; this.stripUndefinedProps(newLookupDialogProps); return { @@ -198,11 +196,13 @@ export class DialogService { return null; } - let modalConfig = {}; if (typeof config === 'string') { - modalConfig = JSON.parse(config); - } else { - modalConfig = Object.assign({}, config); + return JSON.parse(config); + } + + const modalConfig = Object.assign({}, config); + if (Object.keys(modalConfig).length === 0) { + return null; } return modalConfig; diff --git a/packages/command-services/lib/navigation-event.service.ts b/packages/command-services/lib/navigation-event.service.ts index bb00f23b76e..08c2bd7cb90 100644 --- a/packages/command-services/lib/navigation-event.service.ts +++ b/packages/command-services/lib/navigation-event.service.ts @@ -5,20 +5,34 @@ import { CommandContext, Token } from '@farris/devkit-vue'; import { NavigationHistoryService } from './navigation-history.service'; export class NavigationEventService { + + /** + * 命令上下文 + */ public commandContext: CommandContext; + /** * 关闭后事件处理器 */ private onClosedListeners: Map void>; + /** * 关闭前处理器 */ private onClosingListeners: Map Promise>; /** - * 框架页签切换事件 + * 切换事件处理器 */ private onTabSwitchListeners: Map void>; + + /** + * 刷新事件处理器 + */ private onTabRefreshListeners: Map void>; + + /** + * 获取查询参数 + */ private get querystrings() { const params = this.querystringService.parse(window.location.hash); // 修正formToken @@ -27,6 +41,10 @@ export class NavigationEventService { } return params; } + + /** + * 构造函数 + */ constructor( private runtimeFrameworkService: RuntimeFrameworkService, private querystringService: QuerystringService, @@ -38,6 +56,10 @@ export class NavigationEventService { this.onTabRefreshListeners = new Map void>(); this.registerEvent(); } + + /** + * 向框架注册事件 + */ public registerEvent() { const options = this.querystrings; // 注册标签页切换事件 @@ -47,6 +69,10 @@ export class NavigationEventService { // 注册标签页关闭前事件 this.runtimeFrameworkService.addEventListener(TAB_EVENT.onTabClosing, (e) => this.handleTabClosingEvent(e), options); } + + /** + * 处理标签页切换事件 + */ private handleTabSwitchEvent(e: any) { if (!e) { return; @@ -65,10 +91,10 @@ export class NavigationEventService { } this.fireTabSwitchEvent(e); } + /** - * 触发tab切换事件 - * @param e e - */ + * 触发标签页切换事件 + */ private fireTabSwitchEvent(e: any) { if (!this.onTabSwitchListeners || this.onTabSwitchListeners.size < 1) { return; @@ -79,8 +105,9 @@ export class NavigationEventService { } }); } + /** - * 标签页关闭前事件 + * 处理Tab闭前事件 */ private handleTabClosingEvent(event: any) { if (!event) { @@ -101,37 +128,47 @@ export class NavigationEventService { }); } } + /** - * 触发关闭前事件 + * 触发标签页关闭前事件 */ private fireTabClosingEvent(e: any): Promise { if (!this.onClosingListeners || this.onClosingListeners.size < 1) { return Promise.resolve(true); } const listeners = Array.from(this.onClosingListeners.values()); - // const result$ = from(listeners); + // 用户拒绝 let userRejected = false; const resultPromise = listeners.reduce((promiseChain: Promise, handle) => { return promiseChain.then(chainResults => { + // 如果用户已经拒绝,则跳过后续的处理 if (userRejected) { return chainResults; } + // 处理当前的 handle,只取第一个结果 return handle(e).then(result => { + // 如果用户拒绝,则设置标志 userRejected = !result; + // 将结果添加到结果链中 return [...chainResults, result]; }); + }); }, Promise.resolve([])); + + // 如果所有用户返回true,则关闭标签页 return resultPromise.then(chainResults => { + // 检查是否所有的结果都是 true return chainResults.every((result: any) => result); }); } + /** * 标签页关闭后事件 */ @@ -151,9 +188,9 @@ export class NavigationEventService { } this.fireTabClosedEvent(e); } + /** - * 触发关闭后事件 - * @param e event + * 触发标签页关闭后事件 */ private fireTabClosedEvent(e: any) { if (!this.onClosedListeners || this.onClosedListeners.size < 1) { @@ -165,6 +202,10 @@ export class NavigationEventService { } }); } + + /** + * 触发标签页刷新事件 + */ private fireTabRefreshEvent() { if (!this.onTabRefreshListeners || this.onTabRefreshListeners.size < 1) { return; @@ -176,6 +217,7 @@ export class NavigationEventService { }); } // #endregion + /** * 注册事件监听器 * @param eventType 事件类型 onTabClosed @@ -198,6 +240,7 @@ export class NavigationEventService { } return null; } + /** * 移除事件监听器 * @param eventType 事件类型 @@ -211,6 +254,7 @@ export class NavigationEventService { } return false; } + /** * 清空事件监听器 * @param eventType 事件类型 @@ -222,8 +266,9 @@ export class NavigationEventService { this.onClosingListeners.clear(); } } + /** - * 刷新数据 + * 刷新标签页数据 */ private refresh() { this.fireTabRefreshEvent(); diff --git a/packages/command-services/lib/navigation-middleware.service.ts b/packages/command-services/lib/navigation-middleware.service.ts index 336e6dd59d8..5653a232bf3 100644 --- a/packages/command-services/lib/navigation-middleware.service.ts +++ b/packages/command-services/lib/navigation-middleware.service.ts @@ -1,4 +1,4 @@ -import { Token, ViewModel, ViewModelState } from '@farris/devkit-vue'; +import { Token, ViewModel, ViewModelState, IDisposable } from '@farris/devkit-vue'; import { NavigationService } from './navigation.service'; import { TAB_EVENT } from './types'; import { FormMessageService } from './form-message.service'; @@ -7,7 +7,16 @@ import { CancelDataService } from './data-services'; import { EntityChangeService } from './entity-change.service'; import { EndEditService } from './end-edit.service'; -export class NavigationMiddlewareService { +export class NavigationMiddlewareService implements IDisposable { + + /** + * 事件监听Token + */ + private listenerTokens: string[]; + + /** + * 构造函数 + */ constructor( private navigationService: NavigationService, private formMessageService: FormMessageService, @@ -16,16 +25,23 @@ export class NavigationMiddlewareService { private viewModel: ViewModel, private entityChangeService: EntityChangeService, private endEditService: EndEditService - ) { } + ) { + this.listenerTokens = []; + this.registerToModule(); + } + /** * 菜单关闭前 */ public onClosing() { - this.navigationService.addEventListener(TAB_EVENT.onTabClosing, (options) => { + const listenerToken = this.navigationService.addEventListener(TAB_EVENT.onTabClosing, (options) => { + + // 判断是否已经有关闭前的确认框 const isConfirming = this.viewModel.getModule().getContext().getParam('ON_CLOSING_CONFIRM') || false; if (isConfirming) { return Promise.resolve(false); } + // 检测变更前先结束编辑 this.endEditService.endEdit(); return this.entityChangeService.hasChanges().then((changed: boolean) => { @@ -34,17 +50,24 @@ export class NavigationMiddlewareService { if (options && options.beforeCloseHandle && typeof options.beforeCloseHandle === 'function') { options.beforeCloseHandle({ selectedChange: true }); } + + // 打开确认提示框 this.viewModel.getModule().getContext().setParam('ON_CLOSING_CONFIRM', true); const confirm = this.formMessageService.confirm(this.languageService.language.confirmClosing); return confirm.then((result: boolean) => { this.viewModel.getModule().getContext().setParam('ON_CLOSING_CONFIRM', false); + + // 如果用户选择了确定,执行取消并关闭Tab关闭 if (result) { return this.cancelDataService.cancel(false).then(() => true); } + + // 否则返回false,阻止Tab页关闭 return Promise.resolve(false); - } - ); + }); } else { + + // 未检测到变更,关闭Tab页 return Promise.resolve(true); } }).catch((error) => { @@ -53,7 +76,20 @@ export class NavigationMiddlewareService { }); }); }); + + if (listenerToken) { + this.listenerTokens.push(listenerToken); + } } + + /** + * 注册到模块 + */ + public registerToModule() { + const module = this.viewModel.getModule(); + module.registerDisposable(this); + } + /** * 获取tabid,如果targetId存在则直接使用targetId * @description 将用户要查看的数据id转换为运行框架需要的tabId @@ -74,4 +110,13 @@ export class NavigationMiddlewareService { } return paramId; } + + /** + * 释放监听 + */ + public dispose(): void { + this.listenerTokens.forEach((listenerToken) => { + this.navigationService.removeEventListener(TAB_EVENT.onTabClosing, listenerToken); + }) + } } \ No newline at end of file diff --git a/packages/command-services/lib/navigation.service.ts b/packages/command-services/lib/navigation.service.ts index 4d88e3b2ea7..6938793ee81 100644 --- a/packages/command-services/lib/navigation.service.ts +++ b/packages/command-services/lib/navigation.service.ts @@ -254,6 +254,14 @@ export class NavigationService { public addEventListener(eventType: string, handler: (options: any) => any): string | null { return this.navigationEventService.addEventListener(eventType, handler); } + + /** + * 删除注册的事件 + */ + public removeEventListener(eventType: string, key: string) { + this.navigationEventService.removeEventListener(eventType, key); + } + private resolveBizMetadataId(baseMetadataId: string, dim1: string, dim2: string) { if (!dim1) { dim1 = 'public'; diff --git a/packages/devkit/lib/module/module.ts b/packages/devkit/lib/module/module.ts index 104d677164f..fde67153284 100644 --- a/packages/devkit/lib/module/module.ts +++ b/packages/devkit/lib/module/module.ts @@ -1,4 +1,4 @@ -import { EventBus, Injector } from '../common/index'; +import { EventBus, IDisposable, Injector } from '../common/index'; import { Devkit, useDevkit } from '../devkit'; import { Entity, EntityState, EntityStore, UIState, UIStore, @@ -18,7 +18,7 @@ const MODULE_INJECTION_TOKEN = Symbol('Module'); /** * 模块定义 */ -class Module { +class Module implements IDisposable{ /** * 模块ID */ @@ -73,11 +73,17 @@ class Module { * 上下文 */ private context: Context; + /** * 事件总线 */ private eventBus: EventBus; + /** + * 可释放对象 + */ + private disposables: IDisposable[] + /** * 构造函数 */ @@ -93,6 +99,7 @@ class Module { this.context = new Context(); this.id = new Date().getTime().toString(); this.eventBus = new EventBus(); + this.disposables = []; } /** @@ -424,12 +431,36 @@ class Module { public getContext() { return this.context; } + + /** + * 获取模块ID + */ public getId() { return this.id; } + + /** + * 获取事件总线 + */ public getEventBus() { return this.eventBus; } + + /** + * 注册可释放对象 + */ + public registerDisposable(disposable: IDisposable): void { + this.disposables.push(disposable); + } + + /** + * 释放资源 + */ + public dispose() { + this.disposables.forEach((disposable) => { + disposable.dispose(); + }); + } } /** diff --git a/packages/renderer/src/component-config-resolver/data-grid-component-config-resolver.ts b/packages/renderer/src/component-config-resolver/data-grid-component-config-resolver.ts index 041791b7809..1da8bcb0687 100644 --- a/packages/renderer/src/component-config-resolver/data-grid-component-config-resolver.ts +++ b/packages/renderer/src/component-config-resolver/data-grid-component-config-resolver.ts @@ -94,25 +94,29 @@ export class DataGridComponentConfigResolver extends ComponentConfigResolver { */ private buildColumnCommandHandler(eventName: string, commandSchema: any, gridComponentSchema: any, viewModel: any) { const eventHandlerName = commandSchema[eventName]; - if (!eventHandlerName) { - return; - } - - if (eventHandlerName.startsWith('communication:')) { + if (!eventHandlerName || eventHandlerName.startsWith('communication:')) { // 事件通讯 return (cell: any, row: any) => { - const module = viewModel.getModule(); - const { executeCommunications } = useCommunication(module); - return executeCommunications(eventName, gridComponentSchema, { cell, rowData: row.raw }, true); + return this.executeCommunications(eventName, gridComponentSchema, { cell, rowData: row.raw }, viewModel); }; - } else { - // 执行命令 + // 执行命令后触发事件通信 return (cell: any, row: any) => { - return viewModel[eventHandlerName]({ cell, rowData: row.raw }); + return viewModel[eventHandlerName]({ cell, rowData: row.raw }).then(() => { + return this.executeCommunications(eventName, gridComponentSchema, { cell, rowData: row.raw }, viewModel); + }); }; } } + + /** + * 执行事件通信 + */ + private executeCommunications(eventName: any, gridComponentSchema: any, event: any, viewModel: any): void { + const module = viewModel.getModule(); + const { executeCommunications } = useCommunication(module); + return executeCommunications(eventName, gridComponentSchema, event, true); + } } diff --git a/packages/renderer/src/event-handler/modal-closed-event-handler.ts b/packages/renderer/src/event-handler/modal-closed-event-handler.ts new file mode 100644 index 00000000000..8867a15db14 --- /dev/null +++ b/packages/renderer/src/event-handler/modal-closed-event-handler.ts @@ -0,0 +1,85 @@ +import { Injector, Module } from "@farris/devkit-vue"; +import { EventEmitter } from "../common"; +import { FormMetadataService } from "../service"; +import { ViewEvent } from "../types"; +import { EventHandler } from "./types"; + +/** + * 弹窗关闭前事件 + */ +export class ModalClosedEventHandler implements EventHandler { + + /** + * 注册事件 + */ + constructor( + private emitter: EventEmitter, + private formMetadataService: FormMetadataService, + private module: Module, + private injector: Injector + ){} + + /** + * 注册事件监听 + */ + bind(): void { + this.emitter.on('closed', (payload: ViewEvent) => this.onClosed(payload)); + } + + /** + * 注销事件监听 + */ + dispose(): void { + this.emitter.on('closed', (payload: ViewEvent) => this.onClosed(payload)); + } + + /** + * 关闭处理 + */ + private onClosed(payload: any){ + // 只处理包含外部表单的弹窗 + const externalContainerSchema = this.getExternalContainerSchema(payload.schema); + if (!externalContainerSchema) { + return; + } + + // 释放模块相关资源 + const modalModuleId = this.getExternalModuleId(externalContainerSchema); + const modalModule = this.module.getDevkit().getModule(modalModuleId); + if (modalModule) { + modalModule.dispose(); + } + } + + /** + * 获取弹窗内部的外部容器 + * @param modalSchema + * @returns + */ + private getExternalContainerSchema(modalSchema: any) { + if (!modalSchema || modalSchema.type !== 'modal' || !Array.isArray(modalSchema.contents)) { + return false; + } + + const { contents } = modalSchema; + const externalContainerSchema = contents.find((childComponent: any) => { + return childComponent.type === 'external-container'; + }); + + return externalContainerSchema; + } + + /** + * 获取外部容器内表单的模块ID + */ + private getExternalModuleId(externalContainerSchema: any): string { + const externalContainerId = externalContainerSchema.id; + const { externalComponent } = externalContainerSchema; + const externalComponentCode = externalComponent.code; + + const externalModuleId = `${externalContainerId}-${externalComponentCode}`; + + return externalModuleId; + } + +} diff --git a/packages/renderer/src/event-handler/providers.ts b/packages/renderer/src/event-handler/providers.ts index cd26960b550..ebed75a3b50 100644 --- a/packages/renderer/src/event-handler/providers.ts +++ b/packages/renderer/src/event-handler/providers.ts @@ -12,6 +12,7 @@ import { DataGridPageSizeChangeEventHandler } from "./data-grid-page-size-change import { DataGridSelectionChangeEventHandler } from "./data-grid-selection-change-event-handler"; import { QuerySolutionConditionChangeEventHandler } from "./query-solution-condition-change-event-handler"; import { DataGridDoubleClickRowEventHandler } from './data-grid-double-click-row-event-handler'; +import { ModalClosedEventHandler } from './modal-closed-event-handler'; export const eventHanderProviders: StaticProvider[] = [ { provide: EVENT_HANDLERS_TOKEN, useClass: LookupDataMappingEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, @@ -23,5 +24,6 @@ export const eventHanderProviders: StaticProvider[] = [ { provide: EVENT_HANDLERS_TOKEN, useClass: DataGridPageSizeChangeEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, { provide: EVENT_HANDLERS_TOKEN, useClass: DataGridSelectionChangeEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, { provide: EVENT_HANDLERS_TOKEN, useClass: QuerySolutionConditionChangeEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, - { provide: EVENT_HANDLERS_TOKEN, useClass: DataGridDoubleClickRowEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true } + { provide: EVENT_HANDLERS_TOKEN, useClass: DataGridDoubleClickRowEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true }, + { provide: EVENT_HANDLERS_TOKEN, useClass: ModalClosedEventHandler, deps: [EventEmitter, FormMetadataService, Module, Injector], multi: true } ]; -- Gitee From 104bece4faf93b13af4991b6dbaeddabe6a4a1be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=A7=80=E6=89=8D?= Date: Thu, 14 Aug 2025 01:31:58 +0000 Subject: [PATCH 3/5] =?UTF-8?q?!1857=20fix:=20modal=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=8C=96=E5=85=B3=E9=97=AD=E5=90=8E=E5=86=8D?= =?UTF-8?q?=E6=AC=A1=E6=89=93=E5=BC=80=E6=97=A0=E6=B3=95=E6=8B=96=E5=8A=A8?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=20*=20fix:=20lookup=E7=BB=84=E4=BB=B6ID?= =?UTF-8?q?=E9=87=8D=E6=96=B0=E8=B5=8B=E5=80=BC=20*=20build:=20ui-vue=20?= =?UTF-8?q?=E6=89=93=E5=8C=85=E6=81=A2=E5=A4=8D=E9=BB=98=E8=AE=A4=20*=20fi?= =?UTF-8?q?x:=20=E6=97=A5=E6=9C=9F=E5=8C=BA=E9=97=B4=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E6=98=93=E7=94=A8=E6=80=A7=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20*=20fix:=20modal=E7=BB=84=E4=BB=B6=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E5=8C=96=E5=85=B3=E9=97=AD=E5=90=8E=E5=86=8D=E6=AC=A1=E6=89=93?= =?UTF-8?q?=E5=BC=80=E6=97=A0=E6=B3=95=E6=8B=96=E5=8A=A8=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../date-picker-container.component.tsx | 69 +++++++++++-------- .../date-picker/src/composition/use-date.ts | 6 +- .../dynamic-form-group.component.tsx | 1 + .../components/modal/src/modal.component.tsx | 3 + 4 files changed, 48 insertions(+), 31 deletions(-) diff --git a/packages/ui-vue/components/date-picker/src/components/date-picker-container/date-picker-container.component.tsx b/packages/ui-vue/components/date-picker/src/components/date-picker-container/date-picker-container.component.tsx index 2de34d57fe0..b9015c69dc3 100644 --- a/packages/ui-vue/components/date-picker/src/components/date-picker-container/date-picker-container.component.tsx +++ b/packages/ui-vue/components/date-picker/src/components/date-picker-container/date-picker-container.component.tsx @@ -909,31 +909,43 @@ export default defineComponent({ function onMouseLeaveYearView($event: any, isSecondCalendar: boolean) { } - function onConfirm() { - // 区间 - if (enablePeriod.value && selectedPeriod.value) { - const isBeginEmptyDate = !isInitializedDate(selectedPeriod.value.from); - const isEndEmptyDate = !isInitializedDate(selectedPeriod.value.to); + const updateRangeDate = () => { + const { from, to } = selectedPeriod.value; - if (isBeginEmptyDate || isEndEmptyDate) { - const now = new Date(); - if (isBeginEmptyDate) { - selectedPeriod.value.from = { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() }; - } + const isBeginEmptyDate = !isInitializedDate(from); + const isEndEmptyDate = !isInitializedDate(to); - selectedPeriod.value.to = { ...selectedPeriod.value.from }; - } + let begin = {...from}; + let end = {...to}; - if (props.showTime) { - const { hour, minute, second } = getTimeValue(timeValue.value, true); - selectedPeriod.value.from = { ...selectedPeriod.value.from, ...{ hour, minute, second } }; - const { hour: endHour, minute: endMinute, second: endSecond } = getEndTimeValue(timeRangeValue.value); - selectedPeriod.value.to = { ...selectedPeriod.value.to, ...{ hour: endHour, minute: endMinute, second: endSecond } }; + if (isBeginEmptyDate || isEndEmptyDate) { + const now = new Date(); + if (isBeginEmptyDate) { + begin = { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() }; } - const { from, to } = selectedPeriod.value; - context.emit('datePicked', { startDate: from, endDate: to }); + + end = { ...begin }; + } + + if (props.showTime) { + const { hour, minute, second } = getTimeValue(timeValue.value, true); + begin = { ...begin, ...{ hour, minute, second } }; + + const { hour: endHour, minute: endMinute, second: endSecond } = getEndTimeValue(timeRangeValue.value); + end = { ...end, ...{ hour: endHour, minute: endMinute, second: endSecond } }; + } + + return { begin, end }; + }; + + function onConfirm() { + // 区间 + if (enablePeriod.value && selectedPeriod.value) { + const { begin, end } = updateRangeDate(); + selectedPeriod.value= { from: begin, to: end }; + context.emit('datePicked', { startDate: begin, endDate: end }); } else { if (props.showTime) { const { hour, minute, second } = getTimeValue(timeValue.value, true); @@ -1176,15 +1188,16 @@ export default defineComponent({ const canConfirm = computed(() => { if (enablePeriod.value) { - // if (props.showTime) { - // const { from: begin, to: end } = selectedPeriod.value; - // const canClick = equalOrEarlier(begin, end); - // return { - // "pointer-events": canClick ? "auto" : "none", - // opacity: canClick ? 1 : 0.3, - // }; - // } - return true; + if (props.showTime) { + const { begin, end } = updateRangeDate(); + const canClick = equalOrEarlier(begin, end); + + return { + "pointer-events": canClick ? "auto" : "none", + opacity: canClick ? 1 : 0.3, + }; + } + // return true; } else { const { hour, minute, second } = getTimeValue(timeValue.value, true); const currentDateValue = { ...selectedDate.value, ...{ hour, minute, second } }; diff --git a/packages/ui-vue/components/date-picker/src/composition/use-date.ts b/packages/ui-vue/components/date-picker/src/composition/use-date.ts index bd684a34b67..f1e672e5a19 100644 --- a/packages/ui-vue/components/date-picker/src/composition/use-date.ts +++ b/packages/ui-vue/components/date-picker/src/composition/use-date.ts @@ -205,9 +205,9 @@ export function useDate(): UseDate { const timeArr = timeValue.replace('时', ':').replace('分', ':').replace('秒', '').split(':'); if (timeArr.length >= 2) { return { - hour: timeArr[0], - minute: timeArr[1], - second: timeArr[2] ? timeArr[2] : 0 + hour: parseInt(timeArr[0], 10), + minute: parseInt(timeArr[1]), + second: parseInt(timeArr[2] || '0') || 0 }; } } else { diff --git a/packages/ui-vue/components/dynamic-form/src/component/dynamic-form-group/dynamic-form-group.component.tsx b/packages/ui-vue/components/dynamic-form/src/component/dynamic-form-group/dynamic-form-group.component.tsx index d6f928626e2..4e7d2d2e619 100644 --- a/packages/ui-vue/components/dynamic-form/src/component/dynamic-form-group/dynamic-form-group.component.tsx +++ b/packages/ui-vue/components/dynamic-form/src/component/dynamic-form-group/dynamic-form-group.component.tsx @@ -77,6 +77,7 @@ export default defineComponent({ } } else if (editorType === 'lookup' && editor.value['onUpdate:idValue'] && typeof editor.value['onUpdate:idValue'] === 'function') { editorProps['onUpdate:idValue'] = editor.value['onUpdate:idValue']; + editorProps.id = id.value; } else if (editorType === 'collection-property-editor' && editor.value['onSelectionChange'] && typeof editor.value['onSelectionChange'] === 'function') { editorProps['onSelectionChange'] = editor.value['onSelectionChange']; } else if (editorType === 'property-editor') { diff --git a/packages/ui-vue/components/modal/src/modal.component.tsx b/packages/ui-vue/components/modal/src/modal.component.tsx index 7a65d0a351f..9c1941f55fd 100644 --- a/packages/ui-vue/components/modal/src/modal.component.tsx +++ b/packages/ui-vue/components/modal/src/modal.component.tsx @@ -144,6 +144,9 @@ export default defineComponent({ if (modelValue.value) { hasModal.value = hasOpenModal(); + } else { + maximized.value = false; + allowDrag.value = props.draggable; } }); // 监听是否展示标题变化 -- Gitee From 24a4213addec2ffbda318262c1bf71bfd3cc6c9d Mon Sep 17 00:00:00 2001 From: ping-ant <9424832+ping-ant@user.noreply.gitee.com> Date: Thu, 14 Aug 2025 01:47:18 +0000 Subject: [PATCH 4/5] =?UTF-8?q?!1858=20fix:=20=E4=BF=AE=E5=A4=8D=E9=9A=90?= =?UTF-8?q?=E8=97=8F=E5=8C=BA=E5=9F=9F=E9=9D=A2=E6=9D=BF=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20*=20fix:=20=E4=BF=AE=E5=A4=8D=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=E9=9D=A2=E6=9D=BF=E9=80=89=E6=8B=A9=E5=B8=AE?= =?UTF-8?q?=E5=8A=A9=E6=97=B6=E6=95=B0=E6=8D=AE=E9=87=8D=E5=A4=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98=20*=20fix:=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=8F=8C=E5=87=BB=E9=9A=90=E8=97=8F=E5=8C=BA=E5=9F=9F?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E4=BA=A4=E4=BA=92=E9=9D=A2=E6=9D=BF=E4=B8=AD?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=90=8E=E9=94=99=E8=AF=AF=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E5=88=B0ts=E7=BC=96=E8=BE=91=E5=99=A8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../external-component-selector.component.tsx | 2 +- .../lookup/lookup-schema.service.ts | 28 +++++++++++++++---- .../external-lookup.property-config.ts | 12 ++------ .../property-config/modal.property-config.ts | 15 ++-------- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/packages/designer/src/components/components/form-designer/components/external-component-panel/components/external-component-selector/external-component-selector.component.tsx b/packages/designer/src/components/components/form-designer/components/external-component-panel/components/external-component-selector/external-component-selector.component.tsx index d6ea25cf0ae..c5105f9eeb8 100644 --- a/packages/designer/src/components/components/form-designer/components/external-component-panel/components/external-component-selector/external-component-selector.component.tsx +++ b/packages/designer/src/components/components/form-designer/components/external-component-panel/components/external-component-selector/external-component-selector.component.tsx @@ -20,7 +20,7 @@ export default defineComponent({ const metadataService = new MetadataService(); const formBasicInfo = formSchemaUtils.getFormMetadataBasicInfo(); - const editorParams = { formBasicInfo }; + const editorParams = { formBasicInfo, enableGroup: false }; const viewOptions = [ { id: 'recommend', title: '推荐', type: 'Card', dataSource: 'Recommand', pagination: true }, { id: 'total', title: '全部', type: 'Card', dataSource: 'Total', pagination: true } diff --git a/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts b/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts index 66a64d3c5d6..09a9d4b8a7f 100644 --- a/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts +++ b/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts @@ -5,8 +5,7 @@ export class LookupSchemaService { private metadataType = '.hlp'; - constructor(private metadataService: MetadataService) { - } + constructor(private metadataService: MetadataService) { } private getLocalMetadata(metadataPath) { return this.metadataService?.getMetadataListInSu(metadataPath, this.metadataType); @@ -31,18 +30,37 @@ export class LookupSchemaService { }); } - getRecommandData = async (searchingText: string, pagination: SchemaRepositoryPagination, editorParams): Promise => { - const {relativePath} = editorParams.formBasicInfo; + private mergeAndDeduplicateById(...items: T[][]): T[] { + const idSet = new Set(); + const mergedItems: T[] = []; + + for (const array of items) { + for (const item of array) { + if (!idSet.has(item.id)) { + idSet.add(item.id); + mergedItems.push(item); + } + } + } + return mergedItems; + } + + getRecommandData = async (searchingText: string, pagination: SchemaRepositoryPagination, editorParams: any): Promise => { + const { relativePath } = editorParams.formBasicInfo; + const shouldDeduplicate = editorParams.enableGroup === false; const recentRequest = await this.getRecentMetadata(relativePath); const recentData = this.metadata2SchemaItem(recentRequest.data, 'recent'); const suMetadataRequest = await this.getLocalMetadata(relativePath); const localData = this.metadata2SchemaItem(suMetadataRequest.data, 'local'); + if (shouldDeduplicate) { + return this.mergeAndDeduplicateById(recentData, localData); + } return recentData.concat(localData); }; - getSchemaData = async (searchingText: string, pagination: SchemaRepositoryPagination, editorParams): Promise => { + getSchemaData = async (searchingText: string, pagination: SchemaRepositoryPagination, editorParams: any): Promise => { const { relativePath } = editorParams.formBasicInfo; const allMetadataRes = await this.metadataService?.getAllMetadataList(relativePath, this.metadataType); let items = allMetadataRes.data; diff --git a/packages/ui-vue/components/lookup/src/property-config/external-lookup.property-config.ts b/packages/ui-vue/components/lookup/src/property-config/external-lookup.property-config.ts index 8247a36218d..2b8e0387783 100644 --- a/packages/ui-vue/components/lookup/src/property-config/external-lookup.property-config.ts +++ b/packages/ui-vue/components/lookup/src/property-config/external-lookup.property-config.ts @@ -76,16 +76,8 @@ export class ExternalLookupPropertyConfig extends BaseControlProperty { private getEventPropConfig(propertyData: any) { const self: any = this; const initialData = self.eventsEditorUtils['formProperties'](propertyData, self.viewModelId, this.events); - const properties = {}; - properties[self.viewModelId] = { - type: 'events-editor', - editor: { - initialData, - viewSourceHandle: (commandInfo: any) => { - self.eventsEditorUtils.jumpToMethod(commandInfo); - } - } - }; + const properties = self.createBaseEventProperty(initialData); + return { title: '事件', hideTitle: true, diff --git a/packages/ui-vue/components/modal/src/property-config/modal.property-config.ts b/packages/ui-vue/components/modal/src/property-config/modal.property-config.ts index 72a57b7d066..d4669ba1188 100644 --- a/packages/ui-vue/components/modal/src/property-config/modal.property-config.ts +++ b/packages/ui-vue/components/modal/src/property-config/modal.property-config.ts @@ -84,16 +84,8 @@ export class ModalProperty extends BaseControlProperty { const self: any = this; const events = ModalEvents; const initialData = self.eventsEditorUtils['formProperties'](propertyData, self.viewModelId, events); - const properties = {}; - properties[self.viewModelId] = { - type: 'events-editor', - editor: { - initialData, - viewSourceHandle: (commandInfo: any) => { - self.eventsEditorUtils.jumpToMethod(commandInfo); - } - } - }; + const properties = self.createBaseEventProperty(initialData); + return { title: '事件', hideTitle: true, @@ -110,8 +102,7 @@ export class ModalProperty extends BaseControlProperty { } events.forEach(event => { newPropertyData[event.label] = propertyData[event.label]; - }) - + }); } }; } -- Gitee From 0e078c7750347fc02718a87fbdf4614c19f0a751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=A3=E7=BB=B4=E6=B6=9B?= Date: Thu, 14 Aug 2025 12:11:24 +0000 Subject: [PATCH 5/5] =?UTF-8?q?!1868=20=E4=BF=AE=E5=A4=8D=E7=88=B6?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E5=92=8C=E5=BC=B9=E7=AA=97=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E6=9C=89=E5=8F=98=E6=9B=B4=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E8=8F=9C=E5=8D=95=E9=87=8D=E5=A4=8D=E8=AE=A9?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=A1=AE=E8=AE=A4=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20*=20fix:=20=E4=BF=AE=E5=A4=8D=E7=88=B6=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E5=92=8C=E5=BC=B9=E7=AA=97=E8=A1=A8=E5=8D=95=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E6=9C=89=E5=8F=98=E6=9B=B4=E6=97=B6=EF=BC=8C=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E9=87=8D=E5=A4=8D=E8=AE=A9=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/navigation-event.service.ts | 36 ++++++++++--------- .../lib/navigation-middleware.service.ts | 33 +++++++++++++---- .../lib/navigation.service.ts | 2 +- packages/command-services/lib/types.ts | 15 ++++++++ 4 files changed, 62 insertions(+), 24 deletions(-) diff --git a/packages/command-services/lib/navigation-event.service.ts b/packages/command-services/lib/navigation-event.service.ts index 08c2bd7cb90..7aca5ed3d83 100644 --- a/packages/command-services/lib/navigation-event.service.ts +++ b/packages/command-services/lib/navigation-event.service.ts @@ -1,6 +1,6 @@ import { RuntimeFrameworkService } from './rtf.service'; import { QuerystringService } from './querystring.service'; -import { TAB_EVENT } from './types'; +import { TAB_EVENT, TabClosingConfirmResult } from './types'; import { CommandContext, Token } from '@farris/devkit-vue'; import { NavigationHistoryService } from './navigation-history.service'; @@ -10,16 +10,14 @@ export class NavigationEventService { * 命令上下文 */ public commandContext: CommandContext; - /** * 关闭后事件处理器 */ private onClosedListeners: Map void>; - /** * 关闭前处理器 */ - private onClosingListeners: Map Promise>; + private onClosingListeners: Map Promise>; /** * 切换事件处理器 */ @@ -51,7 +49,7 @@ export class NavigationEventService { private navigationHistoryService: NavigationHistoryService ) { this.onClosedListeners = new Map void>(); - this.onClosingListeners = new Map Promise>(); + this.onClosingListeners = new Map Promise>(); this.onTabSwitchListeners = new Map void>(); this.onTabRefreshListeners = new Map void>(); this.registerEvent(); @@ -138,21 +136,23 @@ export class NavigationEventService { } const listeners = Array.from(this.onClosingListeners.values()); - // 用户拒绝 - let userRejected = false; + // 用户已确认(点击了确定或取消) + let userConfirmed = false; + let userConfirmResult: boolean | undefined; const resultPromise = listeners.reduce((promiseChain: Promise, handle) => { - return promiseChain.then(chainResults => { + return promiseChain.then((chainResults: TabClosingConfirmResult[]) => { - // 如果用户已经拒绝,则跳过后续的处理 - if (userRejected) { - return chainResults; - } + const extraOptions = {userConfirmed, userConfirmResult}; // 处理当前的 handle,只取第一个结果 - return handle(e).then(result => { + return handle(e, extraOptions).then((result: TabClosingConfirmResult) => { - // 如果用户拒绝,则设置标志 - userRejected = !result; + // 如果用户点击了确定或取消,则终止 + userConfirmed = result.confirmType === 'User'; + if (result.confirmType === 'User') { + userConfirmed = true; + userConfirmResult = result.confirmResult; + } // 将结果添加到结果链中 return [...chainResults, result]; @@ -162,10 +162,12 @@ export class NavigationEventService { }, Promise.resolve([])); // 如果所有用户返回true,则关闭标签页 - return resultPromise.then(chainResults => { + return resultPromise.then((chainResults: TabClosingConfirmResult[]) => { // 检查是否所有的结果都是 true - return chainResults.every((result: any) => result); + return chainResults.every((result: TabClosingConfirmResult) => { + return result.confirmResult === true; + }); }); } diff --git a/packages/command-services/lib/navigation-middleware.service.ts b/packages/command-services/lib/navigation-middleware.service.ts index 5653a232bf3..9dce5cc79c5 100644 --- a/packages/command-services/lib/navigation-middleware.service.ts +++ b/packages/command-services/lib/navigation-middleware.service.ts @@ -34,12 +34,27 @@ export class NavigationMiddlewareService implements IDisposable { * 菜单关闭前 */ public onClosing() { - const listenerToken = this.navigationService.addEventListener(TAB_EVENT.onTabClosing, (options) => { + const listenerToken = this.navigationService.addEventListener(TAB_EVENT.onTabClosing, (options: any, extraOptions?: any) => { + + // 如果用户已经手工确认了是否关闭菜单,以用户选择为准,不再重复确认 + if (extraOptions && extraOptions.userConfirmed) { + + // 用户已经确定不关闭菜单 + if (extraOptions.userConfirmResult === false) { + return Promise.resolve({confirmResult:false, confirmType: 'User'}); + } else { + + // 用户已经确定关闭菜单 + return this.cancelDataService.cancel(false).then(() => { + return {confirmResult: true, confirmType: 'User'}; + }); + } + } // 判断是否已经有关闭前的确认框 const isConfirming = this.viewModel.getModule().getContext().getParam('ON_CLOSING_CONFIRM') || false; if (isConfirming) { - return Promise.resolve(false); + return Promise.resolve({confirmResult:false, confirmType: 'User'}); } // 检测变更前先结束编辑 @@ -59,20 +74,26 @@ export class NavigationMiddlewareService implements IDisposable { // 如果用户选择了确定,执行取消并关闭Tab关闭 if (result) { - return this.cancelDataService.cancel(false).then(() => true); + return this.cancelDataService.cancel(false).then(() => { + return {confirmResult:true, confirmType: 'User'}; + }); } // 否则返回false,阻止Tab页关闭 - return Promise.resolve(false); + return Promise.resolve({confirmResult:false, confirmType: 'User'}); }); } else { // 未检测到变更,关闭Tab页 - return Promise.resolve(true); + return Promise.resolve({confirmResult:true, confirmType: 'NoChange'}); } }).catch((error) => { return this.formMessageService.confirm(this.languageService.language.hasChangeCheckFaild).then((result: boolean) => { - return Promise.resolve(result); + if (result) { + return Promise.resolve({confirmResult:true, confirmType: 'User'}); + } else { + return Promise.resolve( {confirmResult:false, confirmType: 'User'}); + } }); }); }); diff --git a/packages/command-services/lib/navigation.service.ts b/packages/command-services/lib/navigation.service.ts index 6938793ee81..169d176f71f 100644 --- a/packages/command-services/lib/navigation.service.ts +++ b/packages/command-services/lib/navigation.service.ts @@ -251,7 +251,7 @@ export class NavigationService { * @param handler * @returns */ - public addEventListener(eventType: string, handler: (options: any) => any): string | null { + public addEventListener(eventType: string, handler: (options: any, extraOptions?: any) => any): string | null { return this.navigationEventService.addEventListener(eventType, handler); } diff --git a/packages/command-services/lib/types.ts b/packages/command-services/lib/types.ts index 4227e18c14f..0c1d787b0de 100644 --- a/packages/command-services/lib/types.ts +++ b/packages/command-services/lib/types.ts @@ -7,21 +7,36 @@ export const AppType = { }; export const TAB_EVENT = { + /** * Tab关闭后 */ onTabClosed: 'FuncClosed', + /** * Tab关闭前 */ onTabClosing: 'beforeFuncCloseEvent', + /** * Tab切换 */ onTabSwitched: 'funcSwitchEvent', + + /** + * Tab刷新 + */ onTabRefresh: 'tabRefresh' }; +/** + * 标签页关闭前确认结果 + */ +export interface TabClosingConfirmResult { + confirmResult: boolean; + confirmType: 'User' | 'NoChange' +} + export const TAB_QUERY_STRING = { TabId: 'tabId', AppType: 'appType', -- Gitee