From 4d2980388aba210f46b369d5c7373d965333435f Mon Sep 17 00:00:00 2001 From: hyygzds Date: Mon, 22 Sep 2025 14:12:11 +0800 Subject: [PATCH 01/14] fix: cherry pick data grid column command modifier --- .../src/button-group.component.tsx | 14 +++++- .../button-group-dropdown-menu.component.tsx | 2 +- .../button-group-dropdown.component.tsx | 13 +++++- .../components/editors/commands.component.tsx | 46 ++++++++++++++----- .../ui-vue/demos/data-grid/command_option.vue | 18 ++++++-- 5 files changed, 75 insertions(+), 18 deletions(-) diff --git a/packages/ui-vue/components/button-group/src/button-group.component.tsx b/packages/ui-vue/components/button-group/src/button-group.component.tsx index 6ea630233b..44d7033913 100644 --- a/packages/ui-vue/components/button-group/src/button-group.component.tsx +++ b/packages/ui-vue/components/button-group/src/button-group.component.tsx @@ -58,6 +58,18 @@ export default defineComponent({ return classObject; }; + /** + * button group style + * @returns + */ + const buttonGroupStyle = () => { + return { + display: 'inline-flex', + 'vertical-align': 'middle', + 'margin-bottom': '2px' + }; + }; + function onClick(payload: MouseEvent, buttonItem: any) { context.emit('change', buttonItem.id); context.emit('click', buttonItem); @@ -87,7 +99,7 @@ export default defineComponent({ return () => (
-
+
{flatButtons.map((buttonItem) => renderFlatButton(buttonItem))}
{!!dpButtons.length && renderDropdownButton(dpButtons)} diff --git a/packages/ui-vue/components/button-group/src/components/button-group-dropdown-menu.component.tsx b/packages/ui-vue/components/button-group/src/components/button-group-dropdown-menu.component.tsx index 07cd9917dd..b96c9903c1 100644 --- a/packages/ui-vue/components/button-group/src/components/button-group-dropdown-menu.component.tsx +++ b/packages/ui-vue/components/button-group/src/components/button-group-dropdown-menu.component.tsx @@ -25,7 +25,7 @@ export default function (props: ButtonGroupProps, buttonGroupRef: Ref, useP function renderDropdownMenu(dropdownButtons: any[]) { return ( + host={'body'} fitContent={true} onHidden={hidePopup} minWidth={120}>
{dropdownButtons.map((dropdownItem: any) => renderDropdownItem(dropdownItem))}
diff --git a/packages/ui-vue/components/button-group/src/components/button-group-dropdown.component.tsx b/packages/ui-vue/components/button-group/src/components/button-group-dropdown.component.tsx index 273383204a..527384d67f 100644 --- a/packages/ui-vue/components/button-group/src/components/button-group-dropdown.component.tsx +++ b/packages/ui-vue/components/button-group/src/components/button-group-dropdown.component.tsx @@ -9,10 +9,21 @@ export default function (props: ButtonGroupProps, context: SetupContext) { const usePopupComposition = usePopup(props, context, dropdownButtonRef); const { onMouseleaveDropdownButton, onMouseenterDropdownButton, onClickDropdownButton, shouldPopupContent } = usePopupComposition; const { renderDropdownMenu } = getDropdownMenu(props, buttonGroupRef, usePopupComposition); + const dropdownStyle = () => { + return { + 'margin-bottom': '2px' + }; + }; function renderDropdownButton(dropdownButtons: any[]) { return ( -
+
diff --git a/packages/ui-vue/components/data-view/components/editors/commands.component.tsx b/packages/ui-vue/components/data-view/components/editors/commands.component.tsx index a83a86de90..d5f7baf3f1 100644 --- a/packages/ui-vue/components/data-view/components/editors/commands.component.tsx +++ b/packages/ui-vue/components/data-view/components/editors/commands.component.tsx @@ -15,6 +15,7 @@ */ import { DataColumn, DataColumnCommand, DataViewOptions, VisualData, VisualDataCell, VisualDataStatus } from '../../composition/types'; import FButton from '@farris/ui-vue/components/button'; +import FButtonGroup from '@farris/ui-vue/components/button-group'; import { useI18n } from 'vue-i18n'; export default function (props: DataViewOptions) { const { t: getLocaleValue } = useI18n(); @@ -51,31 +52,31 @@ export default function (props: DataViewOptions) { } function getCommandLcales(commandText: string) { - if(commandText === '编辑') { + if (commandText === '编辑') { return getLocaleValue('datagrid.commandColumn.edit'); } - if(commandText === '确定') { + if (commandText === '确定') { return getLocaleValue('datagrid.commandColumn.accept'); } - if(commandText === '取消') { + if (commandText === '取消') { return getLocaleValue('datagrid.commandColumn.cancel'); } - if(commandText === '删除') { + if (commandText === '删除') { return getLocaleValue('datagrid.commandColumn.remove'); } return commandText; } - function renderCommandColumn(cell: VisualDataCell, visualDataRow: VisualData) { + function renderDefaultCommand(cell: VisualDataCell, visualDataRow: VisualData) { const { column } = cell; return column!.commands && column!.commands.map((command: DataColumnCommand, index: number) => { - if(!index) { + if (!index) { return shouldShowCurrentCommandButton(command, visualDataRow) && excuteCommand(command, payload, visualDataRow, cell)} - style={{ 'margin-bottom': '3px' }} - > {getCommandLcales(command.text)} ; + type={command.type} + size={command.size || 'small'} + onClick={(payload: MouseEvent) => excuteCommand(command, payload, visualDataRow, cell)} + style={{ 'margin-bottom': '3px' }} + > {getCommandLcales(command.text)} ; } return shouldShowCurrentCommandButton(command, visualDataRow) && { + return columnCommand.command; + }); + if (hasDefaultCommand) { + return renderDefaultCommand(cell, visualDataRow); + } + return ; + } + return { renderCommandColumn }; } diff --git a/packages/ui-vue/demos/data-grid/command_option.vue b/packages/ui-vue/demos/data-grid/command_option.vue index 8a8637f1d3..bcd14dfa34 100644 --- a/packages/ui-vue/demos/data-grid/command_option.vue +++ b/packages/ui-vue/demos/data-grid/command_option.vue @@ -233,7 +233,6 @@ const commandOption = { { text: '编辑', type: 'primary', - command: 'edit', onClick(payload: MouseEvent, dataIndex: number, visualDataRow: VisualData) { gridComponentInstance.value.editDataItem(visualDataRow); } @@ -241,7 +240,6 @@ const commandOption = { { text: '删除', type: 'danger', - command: 'remove', onClick(payload: MouseEvent, dataIndex: number, visualDataRow: VisualData) { gridComponentInstance.value.removeDataItem(dataIndex); } @@ -249,7 +247,6 @@ const commandOption = { { text: '确定', type: 'success', - command: 'accept', onClick(payload: MouseEvent, dataIndex: number, visualDataRow: VisualData) { gridComponentInstance.value.acceptDataItem(visualDataRow); } @@ -257,10 +254,23 @@ const commandOption = { { text: '取消', type: 'link', - command: 'cancel', onClick(payload: MouseEvent, dataIndex: number, visualDataRow: VisualData) { gridComponentInstance.value.cancelDataItem(visualDataRow); } + }, + { + text: '上移', + type: 'primary', + onClick(payload: MouseEvent, dataIndex: number, visualDataRow: VisualData) { + // gridComponentInstance.value.cancelDataItem(visualDataRow); + } + }, + { + text: '下移', + type: 'primary', + onClick(payload: MouseEvent, dataIndex: number, visualDataRow: VisualData) { + // gridComponentInstance.value.cancelDataItem(visualDataRow); + } } ], onClickEditCommand: (cell: VisualDataCell, row: VisualData) => { -- Gitee From 3ce26dfdf0620fc1da38628480cb5d06956343c3 Mon Sep 17 00:00:00 2001 From: hyygzds Date: Thu, 25 Sep 2025 17:10:46 +0800 Subject: [PATCH 02/14] fix: cherry pick combolist load sync modifier --- .../load-combo-list-data-callback-handler.ts | 36 ++++++++++ .../src/callback-handler/providers.ts | 2 + .../ui-vue/components/combo-list/index.ts | 3 +- .../combo-list/src/combo-list.props.ts | 3 + .../src/composition/use-data-source.ts | 10 ++- .../combo-list.property-config.ts | 67 +++++++++++++++++++ .../src/schema/callback-resolvers.ts | 14 ++++ .../src/schema/combo-list.schema.json | 4 ++ packages/ui-vue/demos/combo-list/remote.vue | 17 ++++- 9 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 packages/renderer/src/callback-handler/load-combo-list-data-callback-handler.ts create mode 100644 packages/ui-vue/components/combo-list/src/schema/callback-resolvers.ts diff --git a/packages/renderer/src/callback-handler/load-combo-list-data-callback-handler.ts b/packages/renderer/src/callback-handler/load-combo-list-data-callback-handler.ts new file mode 100644 index 0000000000..f4df4e9ed0 --- /dev/null +++ b/packages/renderer/src/callback-handler/load-combo-list-data-callback-handler.ts @@ -0,0 +1,36 @@ +import { Module } from '@farris/devkit-vue'; +import { CallbackHandler } from './callback-handler'; + +/** + * 弹窗关闭前回调 + */ +export class LoadComboListDataCallbackHandler extends CallbackHandler { + + /** + * 回调类型 + */ + public callbackType: string | null = 'load'; + + /** + * 构造函数 + */ + constructor(module: Module) { + super(module); + } + + /** + * 处理回调 + */ + public handle(type: string, args: any[]): undefined | boolean | Promise { + const schema = args[0]; + const { load } = schema; + const defaultReturnValue = true; + + if (!load) { + return defaultReturnValue; + } + + const callbackArgs = { payload: null, schema }; + return this.handleCallback(type, callbackArgs, load, defaultReturnValue); + } +} diff --git a/packages/renderer/src/callback-handler/providers.ts b/packages/renderer/src/callback-handler/providers.ts index 49a866e20d..76b4b1e9fe 100644 --- a/packages/renderer/src/callback-handler/providers.ts +++ b/packages/renderer/src/callback-handler/providers.ts @@ -8,6 +8,7 @@ import { BeforeLoadDataCallbackHandler } from "./before-load-data-callback-handl import { BeforeSelectDataCallbackHandler } from "./before-select-data-callback-handler"; import { DictPickedCallbackHandler } from "./dict-picked-callback-handler"; import { BeforeCloseModalCallbackHandler } from './before-close-modal-callback-handler'; +import { LoadComboListDataCallbackHandler } from './load-combo-list-data-callback-handler'; import { FormNotifyService } from "@farris/command-services-vue"; export const callbackHandlerProviders: StaticProvider[] = [ @@ -17,5 +18,6 @@ export const callbackHandlerProviders: StaticProvider[] = [ { provide: CALLBACK_HANDLER_TOKEN, useClass: BeforeSelectDataCallbackHandler, deps: [Module], multi: true }, { provide: CALLBACK_HANDLER_TOKEN, useClass: DictPickedCallbackHandler, deps: [Module], multi: true }, { provide: CALLBACK_HANDLER_TOKEN, useClass: BeforeCloseModalCallbackHandler, deps: [Module], multi: true }, + { provide: CALLBACK_HANDLER_TOKEN, useClass: LoadComboListDataCallbackHandler, deps: [Module], multi: true }, { provide: CallbackHandlerRegistry, useClass: CallbackHandlerRegistry, deps: [Injector] } ]; diff --git a/packages/ui-vue/components/combo-list/index.ts b/packages/ui-vue/components/combo-list/index.ts index bd5bbd9ac1..917f3f6712 100644 --- a/packages/ui-vue/components/combo-list/index.ts +++ b/packages/ui-vue/components/combo-list/index.ts @@ -16,7 +16,7 @@ */ import FComboList from './src/combo-list.component'; import FComboListDesign from './src/designer/combo-list.design.component'; -import { propsResolver } from './src/combo-list.props'; +import { callbackResolver, propsResolver } from './src/combo-list.props'; import { withInstall } from '@farris/ui-vue/components/common'; export * from './src/combo-list.props'; @@ -24,6 +24,7 @@ export * from './src/combo-list.props'; FComboList.register = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record) => { componentMap['combo-list'] = FComboList; propsResolverMap['combo-list'] = propsResolver; + resolverMap['combo-list'] = { callbackResolver }; }; FComboList.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record) => { componentMap['combo-list'] = FComboListDesign; diff --git a/packages/ui-vue/components/combo-list/src/combo-list.props.ts b/packages/ui-vue/components/combo-list/src/combo-list.props.ts index 5ce8eca027..ca9b75289c 100644 --- a/packages/ui-vue/components/combo-list/src/combo-list.props.ts +++ b/packages/ui-vue/components/combo-list/src/combo-list.props.ts @@ -20,6 +20,7 @@ import { createPropsResolver } from '@farris/ui-vue/components/dynamic-resolver' import { schemaMapper } from './schema/schema-mapper'; import comboListSchema from './schema/combo-list.schema.json'; import { schemaResolver } from './schema/schema-resolver'; +import { createComboListCallbackResolver } from './schema/callback-resolvers'; export interface Option { disabled?: boolean; @@ -231,3 +232,5 @@ export const comboListDesignProps = Object.assign({}, comboListProps, { export type ComboListDesignProps = ExtractPropTypes; export const propsResolver = createPropsResolver(comboListProps, comboListSchema, schemaMapper, schemaResolver); + +export const callbackResolver = createComboListCallbackResolver(); diff --git a/packages/ui-vue/components/combo-list/src/composition/use-data-source.ts b/packages/ui-vue/components/combo-list/src/composition/use-data-source.ts index af15caa15b..b54e283782 100644 --- a/packages/ui-vue/components/combo-list/src/composition/use-data-source.ts +++ b/packages/ui-vue/components/combo-list/src/composition/use-data-source.ts @@ -85,7 +85,15 @@ export function useDataSource(props: ComboListProps): UseDataSource { } if (props.remote) { - loadRemoteData(); + if (props.load) { + props.load().then((data: any) => { + dataSource.value = data; + }).catch((e: any) => { + console.log(e);; + }); + } else { + loadRemoteData(); + } } watch(() => props.data, () => { diff --git a/packages/ui-vue/components/combo-list/src/property-config/combo-list.property-config.ts b/packages/ui-vue/components/combo-list/src/property-config/combo-list.property-config.ts index 428d62405f..6bf033ea5e 100644 --- a/packages/ui-vue/components/combo-list/src/property-config/combo-list.property-config.ts +++ b/packages/ui-vue/components/combo-list/src/property-config/combo-list.property-config.ts @@ -157,10 +157,12 @@ export class ComboListProperty extends InputBaseProperty { propertyData.editor.valueField = 'value'; propertyData.editor.textField = 'name'; propertyData.editor.remote = null; + propertyData.editor.load = null; } else if (changeObject.propertyValue === 'dynamic') { propertyData.editor.remote = { method: 'GET' }; propertyData.editor.valueField = 'value'; propertyData.editor.textField = 'name'; + propertyData.editor.load = propertyData.load; } break; } @@ -317,4 +319,69 @@ export class ComboListProperty extends InputBaseProperty { } } + + /** + * 组装输入类控件的交互面板:包含标签超链、绑定字段值变化前后事件等。 + * @param propertyData 属性值 + * @param viewModelId 视图模型id + * @param showPosition 面板展示位置 + * @param customEvent 输入控件特有的事件配置 + */ + public getEventPropertyConfig(propertyData: any, showPosition = 'card', customEventList?: { label: string, name: string }[], + setPropertyRelates?: (changeObject, data, parameters) => void) { + const self = this; + // 静态事件 + let eventList = [ + { + label: 'onChange', + name: '值变化事件' + }, + { + label: 'onClear', + name: '清空事件' + }, + { + label: 'load', + name: '加载远端数据' + } + ] as any; + if (customEventList) { + eventList = eventList.concat(customEventList); + } + // 追加值变化 + this.appendFieldValueChangeEvents(propertyData, eventList); + + const initialData = self.eventsEditorUtils['formProperties'](propertyData, self.viewModelId, eventList); + const properties = self.createBaseEventProperty(initialData); + + const eventsEditorConfig = { + title: '事件', + hideTitle: true, + properties, + tabId: 'commands', + tabName: '交互', + setPropertyRelates(changeObject: FormPropertyChangeObject, data: any) { + const parameters = changeObject.propertyValue; + delete propertyData[self.viewModelId]; + if (parameters) { + parameters.setPropertyRelates = this.setPropertyRelates; // 添加自定义方法后,调用此回调方法,用于处理联动属性 + // parameters.controlInfo = { type: self.getControlMethodType(propertyData), name: propertyData.title }; // 暂存控件信息,用于自动创建新方法的方法编号和名称 + + self.eventsEditorUtils.saveRelatedParameters(propertyData, self.viewModelId, parameters['events'], parameters); + } + + if (setPropertyRelates) { + setPropertyRelates(changeObject, data, parameters); + } + + // 同步视图模型值变化事件 + const designVM = self.designViewModelUtils.getDgViewModel(self.viewModelId); + if (designVM && self.designViewModelField) { + designVM.changeField(self.designViewModelField.id, { valueChanging: propertyData.fieldValueChanging, valueChanged: propertyData.fieldValueChanged }); + } + } + }; + + return eventsEditorConfig; + } } diff --git a/packages/ui-vue/components/combo-list/src/schema/callback-resolvers.ts b/packages/ui-vue/components/combo-list/src/schema/callback-resolvers.ts new file mode 100644 index 0000000000..cd75863a9c --- /dev/null +++ b/packages/ui-vue/components/combo-list/src/schema/callback-resolvers.ts @@ -0,0 +1,14 @@ +import { Caller } from "@farris/ui-vue/components/dynamic-resolver"; + +export function createComboListCallbackResolver() { + function resolve(viewSchema: Record, caller: Caller) { + const callbacks: Record = {}; + callbacks.load = (): Promise => { + return caller.call('load', [viewSchema]); + }; + return callbacks; + } + return { + resolve + }; +} diff --git a/packages/ui-vue/components/combo-list/src/schema/combo-list.schema.json b/packages/ui-vue/components/combo-list/src/schema/combo-list.schema.json index 391d9e77bb..1eb60017a8 100644 --- a/packages/ui-vue/components/combo-list/src/schema/combo-list.schema.json +++ b/packages/ui-vue/components/combo-list/src/schema/combo-list.schema.json @@ -183,6 +183,10 @@ "description": "启用高亮搜索", "type": "boolean", "default": false + }, + "load": { + "description": "动态加载数据", + "type": "string" } }, "required": [ diff --git a/packages/ui-vue/demos/combo-list/remote.vue b/packages/ui-vue/demos/combo-list/remote.vue index 57424b7a56..ebdb0cde06 100644 --- a/packages/ui-vue/demos/combo-list/remote.vue +++ b/packages/ui-vue/demos/combo-list/remote.vue @@ -11,6 +11,19 @@ const remote = { function updataModelValueHandler(eventData) { modelChange.value = 'value值变更为:' + eventData ? eventData : '空' } +function loadData() { + return new Promise((resolve,reject) => { + setTimeout(() => { + const data = [ + {id: 'a', name: '选项一'}, + {id: 'b', name: '选项2'}, + {id: 'c', name: '选项3'} + ]; + resolve(data); + }); + }); +} +