From 12e0d892ad6c631c4cfba15cd8325c57fdd5cb94 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Sat, 15 Nov 2025 14:02:01 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E5=AE=8C=E5=96=84=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?picker=E3=80=81form-group=E7=AD=89=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../button-group.property-config.ts | 24 ++++---- .../mobile-ui-vue/components/card/index.ts | 4 +- .../components/card/src/card.component.tsx | 8 ++- .../components/card/src/card.props.ts | 3 +- .../components/card/src/card.scss | 4 ++ .../src/properties/toolbar-item.property.ts | 28 ++++----- .../designer/form-item.design.component.tsx | 11 +++- .../response-form-use-designer-rules.ts | 2 +- .../form-item/src/form-item.component.tsx | 29 +++++++-- .../form-item/src/form-item.props.ts | 25 +++++++- .../components/form-item/src/form.props.ts | 2 +- .../components/list-view-item.component.tsx | 16 +++-- .../list-view/src/composition/types.ts | 5 +- .../src/composition/use-selection.ts | 2 + .../list-view/src/list-view.component.tsx | 30 ++++++++-- .../list-view.property-config.ts | 1 + .../components/notify/src/index.tsx | 5 ++ .../notify/src/verify-detail.service.tsx | 32 ++++++++++ .../picker/src/composition/use-columns.ts | 60 +++++++++++++++---- .../src/composition/use-picker-panel-state.ts | 19 +++--- .../src/composition/use-picker-state.ts | 5 +- .../picker/src/picker-panel.component.tsx | 14 ++--- .../picker/src/picker.component.tsx | 8 ++- .../components/picker/src/types/index.ts | 11 ++-- .../src/composition/use-field-selection.ts | 7 ++- .../collection-property-editor.component.tsx | 15 +++++ .../src/composition/use-outline-node.ts | 8 +-- .../components/designer-outline/src/types.ts | 7 ++- 28 files changed, 279 insertions(+), 106 deletions(-) create mode 100644 packages/mobile-ui-vue/components/notify/src/verify-detail.service.tsx diff --git a/packages/mobile-ui-vue/components/button-group/src/property-config/button-group.property-config.ts b/packages/mobile-ui-vue/components/button-group/src/property-config/button-group.property-config.ts index 71f11600ee..1b72e8f191 100644 --- a/packages/mobile-ui-vue/components/button-group/src/property-config/button-group.property-config.ts +++ b/packages/mobile-ui-vue/components/button-group/src/property-config/button-group.property-config.ts @@ -55,15 +55,13 @@ export class ButtonGroupProperty extends BaseControlProperty { mode: { title: "显示模式", description: "按钮组的显示模式", + type: 'enum', editor: { - type: 'combo-tree', - textField: 'text', - valueField: 'value', data: [ - { value: 'default', text: '独立按钮' }, - { value: 'group', text: '组合按钮' }, - { value: 'outline', text: '边框组合' }, - { value: 'text', text: '文本分隔' }, + { id: 'default', name: '独立按钮' }, + { id: 'group', name: '组合按钮' }, + { id: 'outline', name: '边框组合' }, + { id: 'text', name: '文本分隔' }, ], }, }, @@ -80,15 +78,13 @@ export class ButtonGroupProperty extends BaseControlProperty { size: { title: '按钮大小', description: '按钮的大小', + type: 'enum', editor: { - type: 'combo-tree', - textField: 'text', - valueField: 'value', data: [ - { value: 'large', text: '大号按钮' }, - { value: 'middle', text: '普通按钮' }, - { value: 'small', text: '小号按钮' }, - { value: 'mini', text: '迷你按钮' }, + { id: 'large', name: '大号按钮' }, + { id: 'middle', name: '普通按钮' }, + { id: 'small', name: '小号按钮' }, + { id: 'mini', name: '迷你按钮' }, ], }, } diff --git a/packages/mobile-ui-vue/components/card/index.ts b/packages/mobile-ui-vue/components/card/index.ts index 9f7c7702a5..2ff8e04cce 100644 --- a/packages/mobile-ui-vue/components/card/index.ts +++ b/packages/mobile-ui-vue/components/card/index.ts @@ -1,13 +1,13 @@ import { withInstall, withRegister, withRegisterDesigner } from '@farris/mobile-ui-vue/common'; import CardInstallless from './src/card.component'; -import { propsResolverGenerator } from './src/card.props'; +import { eventHandlerResolver, propsResolverGenerator } from './src/card.props'; import CardDesign from './src/designer/card.design.component'; const CARD_REGISTERED_NAME = 'card'; const Card = withInstall(CardInstallless); -withRegister(Card, { name: CARD_REGISTERED_NAME, propsResolverGenerator }); +withRegister(Card, { name: CARD_REGISTERED_NAME, propsResolverGenerator , resolver: { eventHandlerResolver }}); withRegisterDesigner(Card, { name: CARD_REGISTERED_NAME, propsResolverGenerator, designerComponent: CardDesign }); export * from './src/card.props'; diff --git a/packages/mobile-ui-vue/components/card/src/card.component.tsx b/packages/mobile-ui-vue/components/card/src/card.component.tsx index 73c82f0a7c..6f145f3e3d 100644 --- a/packages/mobile-ui-vue/components/card/src/card.component.tsx +++ b/packages/mobile-ui-vue/components/card/src/card.component.tsx @@ -1,12 +1,12 @@ import { defineComponent, ref, computed } from 'vue'; import { useBem } from '@farris/mobile-ui-vue/common'; -import { ButtonGroup } from '@farris/mobile-ui-vue/button-group'; +import { ButtonGroup, ButtonItem } from '@farris/mobile-ui-vue/button-group'; import { CARD_NAME, cardProps, CardProps } from './card.props'; export default defineComponent({ name: CARD_NAME, props: cardProps, - emits: [], + emits: ['click'], setup(props: CardProps, context) { const { bem } = useBem(CARD_NAME); const { slots } = context; @@ -45,6 +45,9 @@ export default defineComponent({ ); } + function clickButton(buttonItem: ButtonItem) { + context.emit('click', buttonItem) + } function renderFooter() { if (slots.footer) { @@ -56,6 +59,7 @@ export default defineComponent({ items={props.toolbarItems} mode={'text'} block + onClick={clickButton} > ); diff --git a/packages/mobile-ui-vue/components/card/src/card.props.ts b/packages/mobile-ui-vue/components/card/src/card.props.ts index 5b5499cb58..17bbf592fc 100644 --- a/packages/mobile-ui-vue/components/card/src/card.props.ts +++ b/packages/mobile-ui-vue/components/card/src/card.props.ts @@ -1,5 +1,5 @@ import { ExtractPropTypes } from 'vue'; -import { getPropsResolverGenerator } from '@farris/mobile-ui-vue/dynamic-resolver'; +import { createCardEventHandlerResolver, getPropsResolverGenerator } from '@farris/mobile-ui-vue/dynamic-resolver'; import { ButtonItem } from '@farris/mobile-ui-vue/button-group'; import cardSchema from './schema/card.schema.json'; import { schemaMapper } from './schema/schema-mapper'; @@ -33,3 +33,4 @@ export const propsResolverGenerator = getPropsResolverGenerator( ); export type CardProps = ExtractPropTypes; +export const eventHandlerResolver = createCardEventHandlerResolver(); diff --git a/packages/mobile-ui-vue/components/card/src/card.scss b/packages/mobile-ui-vue/components/card/src/card.scss index a8106b291a..eb85b866e8 100644 --- a/packages/mobile-ui-vue/components/card/src/card.scss +++ b/packages/mobile-ui-vue/components/card/src/card.scss @@ -40,4 +40,8 @@ &__footer { @include hairline('top'); } + + &__content { + background-color: #f7f8fa; + } } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/common/src/properties/toolbar-item.property.ts b/packages/mobile-ui-vue/components/common/src/properties/toolbar-item.property.ts index 16d97a2ee1..2cd2c393f0 100644 --- a/packages/mobile-ui-vue/components/common/src/properties/toolbar-item.property.ts +++ b/packages/mobile-ui-vue/components/common/src/properties/toolbar-item.property.ts @@ -39,24 +39,22 @@ export class ToolbarItemProperty extends BaseControlProperty { protected getAppearanceConfig(propertyData: any) { const buttonTypeData = [ - { text: '主要按钮', value: 'primary' }, - { text: '危险按钮', value: 'danger' }, - { text: '警告按钮', value: 'warning' }, - { text: '成功按钮', value: 'success' }, - { text: '次要按钮', value: 'secondary' }, - { text: '提示按钮', value: 'info' }, + { name: '主要按钮', id: 'primary' }, + { name: '危险按钮', id: 'danger' }, + { name: '警告按钮', id: 'warning' }, + { name: '成功按钮', id: 'success' }, + { name: '次要按钮', id: 'secondary' }, + { name: '提示按钮', id: 'info' }, ]; const additionalProperties: any = {}; if (this.options?.showButtonType) { additionalProperties.displayType = { description: '按钮的主题风格', title: '按钮类型', + type: 'enum', editor: { - type: 'combo-tree', - textField: 'text', - valueField: 'value', - data: buttonTypeData, - }, + data: buttonTypeData + } }; } if (this.options?.showIcon) { @@ -84,13 +82,11 @@ export class ToolbarItemProperty extends BaseControlProperty { additionalProperties.variant = { description: '按钮的变体', title: '变体', + type: 'enum', editor: { - type: 'combo-tree', - textField: 'text', - valueField: 'value', data: [ - { text: '无', value: 'default' }, - { text: '图标在上', value: 'bare-vertical' }, + { name: '无', id: 'default' }, + { name: '图标在上', id: 'bare-vertical' }, ], }, }; diff --git a/packages/mobile-ui-vue/components/form-item/src/designer/form-item.design.component.tsx b/packages/mobile-ui-vue/components/form-item/src/designer/form-item.design.component.tsx index 4d5edd794d..f4c8c92354 100644 --- a/packages/mobile-ui-vue/components/form-item/src/designer/form-item.design.component.tsx +++ b/packages/mobile-ui-vue/components/form-item/src/designer/form-item.design.component.tsx @@ -51,14 +51,19 @@ export default defineComponent({ () => props.editor, ], ([newEditor]) => { - editor.value = { ...newEditor }; - }, { deep: true } + editor.value = { + ...newEditor, + readonly: true + }; + }, { deep: true,immediate: true } ); return () => ( + {...props} + editor={editor.value} + visible={true}> {renderConditionEditor.value()} ); diff --git a/packages/mobile-ui-vue/components/form-item/src/designer/response-form-use-designer-rules.ts b/packages/mobile-ui-vue/components/form-item/src/designer/response-form-use-designer-rules.ts index b4932e5202..1efb89cdc0 100644 --- a/packages/mobile-ui-vue/components/form-item/src/designer/response-form-use-designer-rules.ts +++ b/packages/mobile-ui-vue/components/form-item/src/designer/response-form-use-designer-rules.ts @@ -66,7 +66,7 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe // 控件若有绑定信息,则根据绑定信息创建控件 if (resolveContext.bindingSourceContext?.entityFieldNode) { const controlCreatorUtils = designerHostService?.controlCreatorUtils; - formGroupElementSchema = controlCreatorUtils.setFormFieldProperty(resolveContext.bindingSourceContext?.entityFieldNode, componentSchema?.type); + formGroupElementSchema = controlCreatorUtils.setFormFieldProperty(resolveContext.bindingSourceContext?.entityFieldNode, componentSchema?.type,''); } else { formGroupElementSchema = getSchemaByTypeForDesigner('form-group') as ComponentSchema; formGroupElementSchema.editor = componentSchema; diff --git a/packages/mobile-ui-vue/components/form-item/src/form-item.component.tsx b/packages/mobile-ui-vue/components/form-item/src/form-item.component.tsx index ef57c53043..713b713b99 100644 --- a/packages/mobile-ui-vue/components/form-item/src/form-item.component.tsx +++ b/packages/mobile-ui-vue/components/form-item/src/form-item.component.tsx @@ -36,6 +36,18 @@ export default defineComponent({ const modelValue = ref(props.modelValue); const editor = ref(props.editor); const editorRef = ref(); + const errors = ref(props.errors); + const visible = ref(props.visible); + + const message = computed(() => { + if (errors.value) { + const messages = Object.keys(errors.value).map((key: string) => { + return errors.value[key]?.name; + }); + return messages.length ? messages.join(' ') : ''; + } + return ''; + }); const { resolveEditorProps, resolveEditorType, getChangeFunctionName } = useTypeResolver(); const formItemContext = useFormItemContext(props); @@ -90,7 +102,7 @@ export default defineComponent({ } return () => ; }); - + const renderContent = () => { return
{ slots.default ? slots.default() : editor.value && renderConditionEditor.value() @@ -98,7 +110,7 @@ export default defineComponent({ }; const errorMessageClass = computed(() => { - const errorMessageAlign = props.errorMessageAlign || formContext?.errorMessageAlign || 'left'; + const errorMessageAlign = props.errorMessageAlign || formContext?.errorMessageAlign || 'right'; return { [bem('error-message')]: true, [bem('error-message', errorMessageAlign)]: true @@ -108,6 +120,9 @@ export default defineComponent({ if (slots.errorMessage) { return [slots.errorMessage()]; } + if (message.value) { + return
{message.value}
; + } return
{errorMessage.value}
; }; @@ -133,12 +148,17 @@ export default defineComponent({ () => props.editor, () => props.label, () => props.modelValue, + () => props.errors, + () => props.visible, ], - ([newId, newEditor, newLabel, newModelValue]) => { + ([newId, newEditor, newLabel, newModelValue, newErrors, newVisible]) => { id.value = newId; editor.value = newEditor; label.value = newLabel; modelValue.value = newModelValue; + errors.value = newErrors; + visible.value = newVisible; + } ); @@ -153,7 +173,8 @@ export default defineComponent({ }; return ( - , + default: null + } +}; export const formItemProps = { id: { type: String, default: '' }, @@ -38,11 +52,16 @@ export const formItemProps = { showErrorMessage: { type: Boolean, default: undefined }, /** 错误信息位置 */ - errorMessageAlign: { type: String as PropType, deafult: undefined }, - + errorMessageAlign: { type: String as PropType, deafult: 'right' }, + editor: { type: Object as PropType, default: {} }, customClass: { type: String, default: '' }, - customStyle: { type: String, defaut: '' } + customStyle: { type: String, defaut: '' }, + + errors: { type: Object as PropType, default: null }, + /** 控制是否可见 */ + visible: { type: Boolean, default: true }, + }; export type FormItemProps = ExtractPropTypes; diff --git a/packages/mobile-ui-vue/components/form-item/src/form.props.ts b/packages/mobile-ui-vue/components/form-item/src/form.props.ts index c0c8a0b2b0..aaabaaa208 100644 --- a/packages/mobile-ui-vue/components/form-item/src/form.props.ts +++ b/packages/mobile-ui-vue/components/form-item/src/form.props.ts @@ -32,7 +32,7 @@ export const formProps = { showErrorMessage: { type: Boolean, default: true }, /** 错误信息排列方式 */ - errorMessageAlign: { type: String as PropType, default: 'left' } + errorMessageAlign: { type: String as PropType, default: 'right' } }; diff --git a/packages/mobile-ui-vue/components/list-view/src/components/list-view-item.component.tsx b/packages/mobile-ui-vue/components/list-view/src/components/list-view-item.component.tsx index 9e920ed606..6311f43427 100644 --- a/packages/mobile-ui-vue/components/list-view/src/components/list-view-item.component.tsx +++ b/packages/mobile-ui-vue/components/list-view/src/components/list-view-item.component.tsx @@ -24,7 +24,7 @@ export default function ( const shouldDisableSwipeCell = computed(() => isMultiSelectMode.value); function onListItemClick(item: any, index: number): void { - emit('clickItem', { data: item, index }); + emit('clickItem', { dataItem: item, index }); } function onCheckboxClick(event: MouseEvent): void { @@ -57,10 +57,16 @@ export default function (
{getItemText(item)}
); } - const onClickSwipeToolbarItem = (item: any) => { - context.emit('clickSwipeToolbar', item); + + function onClickSwipeToolbarItem(item: any) { + item && context.emit('clickSwipeToolbar', item); }; + function onTouchItem($event: TouchEvent, item: any, index: number) { + useSelectionComposition.currentSelectedDataId.value = useDataComposition.getItemID(item.id); + context.emit('touchItem', { dataItem: item, index }); + } + function renderSwipeCell(item: any, index: number, disabled: boolean) { if (!shouldRenderSwipeCell.value) { return renderItemContent(item, index, disabled); @@ -86,7 +92,9 @@ export default function ( const rootItemIndex = isChildItem ? parentItemIndex : index; return ( -
onListItemClick(item, rootItemIndex!)}> +
onListItemClick(item, rootItemIndex!)} + onTouchend={($event: TouchEvent)=>onTouchItem($event, item, rootItemIndex!)}> {isMultiSelectMode.value && (
{shouldShowCheckbox && renderCheckbox(item)} diff --git a/packages/mobile-ui-vue/components/list-view/src/composition/types.ts b/packages/mobile-ui-vue/components/list-view/src/composition/types.ts index ec9bb022e3..45e23b9fe6 100644 --- a/packages/mobile-ui-vue/components/list-view/src/composition/types.ts +++ b/packages/mobile-ui-vue/components/list-view/src/composition/types.ts @@ -1,4 +1,4 @@ -import { ComputedRef } from 'vue'; +import { ComputedRef, Ref } from 'vue'; export interface UseData { @@ -16,7 +16,8 @@ export interface UseData { } export interface UseSelection { - + currentSelectedDataId: Ref; + isMultiSelectMode: ComputedRef; toggleMultiSelect: (selectMode: boolean) => void; diff --git a/packages/mobile-ui-vue/components/list-view/src/composition/use-selection.ts b/packages/mobile-ui-vue/components/list-view/src/composition/use-selection.ts index 3546ab1595..0c99f3aa02 100644 --- a/packages/mobile-ui-vue/components/list-view/src/composition/use-selection.ts +++ b/packages/mobile-ui-vue/components/list-view/src/composition/use-selection.ts @@ -10,6 +10,7 @@ export function useSelection( ): UseSelection { const { emit } = context; + const currentSelectedDataId: Ref = ref(''); const isMultiSelectMode = computed(() => { return props.enableMultiSelect && props.multiSelect; @@ -94,6 +95,7 @@ export function useSelection( } return { + currentSelectedDataId, isMultiSelectMode, toggleMultiSelect, isItemSelected, diff --git a/packages/mobile-ui-vue/components/list-view/src/list-view.component.tsx b/packages/mobile-ui-vue/components/list-view/src/list-view.component.tsx index 33a227517d..d4a560ac83 100644 --- a/packages/mobile-ui-vue/components/list-view/src/list-view.component.tsx +++ b/packages/mobile-ui-vue/components/list-view/src/list-view.component.tsx @@ -15,7 +15,7 @@ */ import { defineComponent, SetupContext, computed, withDirectives, toRefs, ref, nextTick, watch } from 'vue'; import { LIST_VIEW_NAME, listViewProps, ListViewProps } from './list-view.props'; -import { useBem, vOnLongPress } from '@farris/mobile-ui-vue/common'; +import { isPromise, useBem, vOnLongPress } from '@farris/mobile-ui-vue/common'; import List from '@farris/mobile-ui-vue/list'; import PullRefresh from '@farris/mobile-ui-vue/pull-refresh'; import Button from '@farris/mobile-ui-vue/button'; @@ -30,6 +30,7 @@ export default defineComponent({ emits: [ 'clickItem', + 'touchItem', 'clickSwipeToolbar', 'update:multiSelect', 'selectionChange', @@ -106,6 +107,10 @@ export default defineComponent({ toggleMultiSelect(true); } + function updateDataSource(newData: Record[]) { + + } + function renderListContent() { const listContentClass = { [bem('content')]: true, @@ -175,9 +180,16 @@ export default defineComponent({ isListRefreshing.value = false; return; } - props.pullDownRefresh().then(() => { - isListRefreshing.value = false; - }) + const result = props.pullDownRefresh(); + + if (isPromise(result)) { + result.then(() => { + isListRefreshing.value = false; + }) + return; + } + isListRefreshing.value = false; + }, }; return ( @@ -220,6 +232,12 @@ export default defineComponent({ listComponentRef.value?.check(); } + // 获取选中行标识 + function getCurrentRowId() { + return useSelectionComposition.currentSelectedDataId.value; + } + + watch( [ () => props.visible, @@ -228,12 +246,14 @@ export default defineComponent({ visible.value = newVisible; } ); - + expose({ elementRef, check: checkListNeedLoadMore, getSelectedItems, clearSelection, + updateDataSource, + getCurrentRowId }); return () => { diff --git a/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.ts b/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.ts index e6f311876f..b3444d1b68 100644 --- a/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.ts +++ b/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.ts @@ -82,6 +82,7 @@ export class ListViewProperty extends ContainerBaseProperty { title: '是否启用下拉刷新', type: 'boolean', description: '是否启用下拉刷新列表数据', + visible: false }, }); } diff --git a/packages/mobile-ui-vue/components/notify/src/index.tsx b/packages/mobile-ui-vue/components/notify/src/index.tsx index 0aa07a2eb5..501e9cef3e 100644 --- a/packages/mobile-ui-vue/components/notify/src/index.tsx +++ b/packages/mobile-ui-vue/components/notify/src/index.tsx @@ -2,6 +2,7 @@ import { App } from 'vue'; import { isObject, inBrowser, mountComponent, usePopupState } from '@farris/mobile-ui-vue/common'; import FMNotify from './notify.component'; import { NotifyProps, NotifyType } from './notify.props'; +import FVerifyDetailService from './verify-detail.service'; let instance; let timer; @@ -95,8 +96,12 @@ Notify.resetDefaultOptions = () => { Notify.install = (app: App) => { app.component((FMNotify.name as string), FMNotify); app.config.globalProperties.$notify = Notify; + app.provide('FNotifyService', Notify); + app.provide('FVerifyDetailService', FVerifyDetailService); + }; Notify.Component = FMNotify; export default Notify; +export { FVerifyDetailService }; diff --git a/packages/mobile-ui-vue/components/notify/src/verify-detail.service.tsx b/packages/mobile-ui-vue/components/notify/src/verify-detail.service.tsx new file mode 100644 index 0000000000..c73d7c6746 --- /dev/null +++ b/packages/mobile-ui-vue/components/notify/src/verify-detail.service.tsx @@ -0,0 +1,32 @@ +/* eslint-disable @typescript-eslint/no-unsafe-function-type */ +/** + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Notify from "."; + + +class VerifyDetailService { + + static show(props: any, parent?: HTMLElement): void { + Notify.error('存在校验未通过项,请检查!'); + } + + static clear(): void { + + } +} + +export default VerifyDetailService; diff --git a/packages/mobile-ui-vue/components/picker/src/composition/use-columns.ts b/packages/mobile-ui-vue/components/picker/src/composition/use-columns.ts index 688bdbdbfb..998b4eb1bc 100644 --- a/packages/mobile-ui-vue/components/picker/src/composition/use-columns.ts +++ b/packages/mobile-ui-vue/components/picker/src/composition/use-columns.ts @@ -1,10 +1,10 @@ -import { computed, } from 'vue'; +import { computed, watch } from 'vue'; import { isArray, isFunction, isObject } from '@farris/mobile-ui-vue/common'; import { PickerPanelProps } from '../picker-panel.props'; import { Column, ColumnItem, Columns, UseColumns, UsePickerState, ValueType } from '../types'; export const useColumns = (props: PickerPanelProps, pickerState: UsePickerState): UseColumns => { - const { innerValue, setValueByIndex, getValueByIndex } = pickerState; + const { realValue, selectedValue, setValueByIndex, getValueByIndex, formatValue } = pickerState; const getFirstColumnItem = (column: Column) => { return column && column[0]; @@ -75,38 +75,72 @@ export const useColumns = (props: PickerPanelProps, pickerState: UsePickerState) const getPickeds = () => { return columns.value .map((column, index) => { - const itemValue = innerValue.value[index]; + const itemValue = realValue.value[index]; const item = column.find((item) => item[props.valueField] === itemValue); - return item || getFirstColumnItem(column); - }); + return item as ValueType; + }).filter(item => item); }; const getValue = () => { return getPickeds() - .filter(item => item) - .map((item) => item[props.valueField] as ValueType); + .map((item) => item[props.valueField]); }; const getTextValue = () => { return getPickeds() - .filter(item => item) .map((item) => item[props.textField]).join('-'); }; - const setDefaultValue = () => { + /** + * 设置默认选中值 + */ + const setDefaultSelectedValue = () => { + columns.value.forEach((column, index) => { + const itemValue = selectedValue.value[index]; + const item = column.find((item) => item[props.valueField] === itemValue); + if (!item) { + selectedValue.value[index] = getFirstColumnItem(column)[props.valueField]; + } + }) + }; + + /** + * 更新真实值为选中值 + */ + const updateRealValue = () => { columns.value.map((column, index) => { - const itemValue = innerValue.value[index]; - const defaultValue = getFirstColumnItem(column)[props.valueField]; - const value = (itemValue || defaultValue) as ValueType; + const value = selectedValue.value[index]; setValueByIndex(index, value); }); + + realValue.value = selectedValue.value; }; + /** + * 重置选中值 + * @param value + */ + const resetSelectedValue = (value: string | ValueType[]) => { + selectedValue.value = formatValue(value); + setDefaultSelectedValue(); + }; + + watch( + () => props.modelValue, + () => { + realValue.value = formatValue(props.modelValue); + resetSelectedValue(props.modelValue); + }, + { immediate: true } + ); + + return { columns, getPickeds, getValue, getTextValue, - setDefaultValue + resetSelectedValue, + updateRealValue }; }; diff --git a/packages/mobile-ui-vue/components/picker/src/composition/use-picker-panel-state.ts b/packages/mobile-ui-vue/components/picker/src/composition/use-picker-panel-state.ts index 7439f8ec28..95c91e7ba4 100644 --- a/packages/mobile-ui-vue/components/picker/src/composition/use-picker-panel-state.ts +++ b/packages/mobile-ui-vue/components/picker/src/composition/use-picker-panel-state.ts @@ -7,29 +7,26 @@ export const usePickerState = (props: PickerPanelProps): UsePickerState => { const formatValue = (value: string | ValueType[]) => isArray(value) ? value : isString(value) ? value.split(props.separator) : isDef(value) ? [value] : []; - const innerValue = ref(formatValue(props.modelValue)); + const realValue = ref(formatValue(props.modelValue)); + const selectedValue = ref(formatValue(props.modelValue)); const setValueByIndex = (index: number, value: ValueType) => { - innerValue.value[index] = value; + selectedValue.value[index] = value; }; const getValueByIndex = (index: number) => { - return innerValue.value[index]; + return selectedValue.value[index]; }; - watch( - () => props.modelValue, - () => { - innerValue.value = formatValue(props.modelValue); - } - ); const lineHeight = 44; return { - innerValue, + realValue, + selectedValue, lineHeight, setValueByIndex, - getValueByIndex + getValueByIndex, + formatValue }; }; diff --git a/packages/mobile-ui-vue/components/picker/src/composition/use-picker-state.ts b/packages/mobile-ui-vue/components/picker/src/composition/use-picker-state.ts index 1433a8034a..870404fbfa 100644 --- a/packages/mobile-ui-vue/components/picker/src/composition/use-picker-state.ts +++ b/packages/mobile-ui-vue/components/picker/src/composition/use-picker-state.ts @@ -20,10 +20,9 @@ export const usePickerState = ( // 组件变量传递存在延迟,等待子组件变量更新完成 nextTick(() => updateInputValue()); }); + onMounted(() => { - if (props.modelValue) { - updateInputValue(); - } + updateInputValue(); }); const handleConfirm = (value: any[]) => { diff --git a/packages/mobile-ui-vue/components/picker/src/picker-panel.component.tsx b/packages/mobile-ui-vue/components/picker/src/picker-panel.component.tsx index 0b4c1d6dd4..8127d526db 100644 --- a/packages/mobile-ui-vue/components/picker/src/picker-panel.component.tsx +++ b/packages/mobile-ui-vue/components/picker/src/picker-panel.component.tsx @@ -16,11 +16,11 @@ export default defineComponent({ usePickerContext(props); const pickerStateComposition = usePickerState(props); - const { innerValue, lineHeight, setValueByIndex } = pickerStateComposition; + const { realValue, selectedValue, lineHeight, setValueByIndex } = pickerStateComposition; - const { columns, getPickeds, getValue, getTextValue, setDefaultValue } = useColumns(props, pickerStateComposition); + const { columns, getPickeds, getValue, getTextValue, updateRealValue, resetSelectedValue } = useColumns(props, pickerStateComposition); - expose({ getTextValue, getValue, getPickeds }); + expose({ getTextValue, getValue, getPickeds, resetSelectedValue }); const { bem } = useBem(PICKER_PANEL_NAME); @@ -31,9 +31,9 @@ export default defineComponent({ }; const onConfirm = () => { - setDefaultValue(); - emit('confirm', innerValue.value); - emit('update:modelValue', innerValue.value); + updateRealValue(); + emit('confirm', realValue.value); + emit('update:modelValue', realValue.value); }; const onCancel = () => { @@ -74,7 +74,7 @@ export default defineComponent({ {columns.value.map((column, index) => ( showPopup.value = false }; }); - + + watch(() => showPopup.value, (newShowPopup) => { + componentRef.value.resetSelectedValue(props.modelValue); + }) + return () => ( = { index: number; value: T }; export interface UsePickerState { - innerValue: Ref; + realValue: Ref; + selectedValue: Ref; lineHeight: number; setValueByIndex: (index: number, value: ValueType) => void; getValueByIndex: (index: number) => ValueType; + formatValue: (value: string | ValueType[]) => ValueType[]; } export interface UseColumns { @@ -25,7 +27,8 @@ export interface UseColumns { getPickeds: () => (ValueType | ColumnItem)[]; getValue: () => ValueType[]; getTextValue: () => string; - setDefaultValue: () => void; + resetSelectedValue: (value: ValueType[] | string) => void; + updateRealValue: () => void; } export type ColumnTranslate = { @@ -58,9 +61,9 @@ export type PickerContext = { instance: ComponentInternalInstance | null; }; -export type GroupItem = {name: number; title: string}; +export type GroupItem = { name: number; title: string }; export type GroupContext = { - addItem: (item: GroupItem) => void; + addItem: (item: GroupItem) => void; updateItem: (id: number, title: string) => void; }; diff --git a/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts b/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts index f43b83fe89..c1a27559f3 100644 --- a/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts +++ b/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts @@ -1,12 +1,12 @@ import { FNotifyService } from "../../../notify"; -import { FormBindingType, SchemaDOMMapping } from "@farris/ui-vue/components/property-panel"; +import { FormBindingType, SchemaDOMMapping as defaultSchemaDOMMapping } from "@farris/ui-vue/components/property-panel"; import { merge } from "lodash-es"; import { BindingSelectorProps } from "../binding-selector.props"; import { FormSchemaEntityField$Type, FormSchemaEntityFieldTypeName } from "@farris/ui-vue/components/common"; export function useFieldSelection(props: BindingSelectorProps) { - const { designViewModelUtils, schemaService, formSchemaUtils } = props.editorParams.designerHostService; + const { designViewModelUtils, schemaService, formSchemaUtils, designerContext } = props.editorParams.designerHostService; const { viewModelId } = props.editorParams; let fieldTreeData = []; let localeVariableTreeData = []; @@ -275,7 +275,8 @@ export function useFieldSelection(props: BindingSelectorProps) { } const controlFieldMapping = {}; - const { fieldControlTypeMapping } = SchemaDOMMapping; + const schemaDOMMapping = designerContext && designerContext.schemaDOMMapping ? designerContext.schemaDOMMapping : defaultSchemaDOMMapping; + const { fieldControlTypeMapping } = schemaDOMMapping; for (const fieldType in fieldControlTypeMapping) { const controlTypes = fieldControlTypeMapping[fieldType]; diff --git a/packages/ui-vue/components/collection-property-editor/src/collection-property-editor.component.tsx b/packages/ui-vue/components/collection-property-editor/src/collection-property-editor.component.tsx index 48f3339ee0..998c70d0ef 100644 --- a/packages/ui-vue/components/collection-property-editor/src/collection-property-editor.component.tsx +++ b/packages/ui-vue/components/collection-property-editor/src/collection-property-editor.component.tsx @@ -35,10 +35,25 @@ export default defineComponent({ return `共 ${propertyData.value?.length || 0} 项`; }); + /** 净化data,移除私有属性 */ + function cleanData(data: any[]) { + if(!data){ + return; + } + data.forEach((dataItem: any) => { + Object.keys(dataItem).forEach((key: string) => { + if (key.indexOf('__fv') > -1) { + delete dataItem[key]; + } + }); + }); + } + /** * 确定事件 */ function onSubmit() { + cleanData(propertyData.value); context.emit('valueChange', propertyData.value); return true; } diff --git a/packages/ui-vue/components/designer-outline/src/composition/use-outline-node.ts b/packages/ui-vue/components/designer-outline/src/composition/use-outline-node.ts index 965fdf97f6..998b91a9bf 100644 --- a/packages/ui-vue/components/designer-outline/src/composition/use-outline-node.ts +++ b/packages/ui-vue/components/designer-outline/src/composition/use-outline-node.ts @@ -24,10 +24,7 @@ export function useOutlineNode(designerHostService: DesignerHostService, context switch (componentsItem?.type) { // 输入类控件,根据editor来区分 case 'form-group': { - iconType = dgControl[componentsItem.type]?.icon || componentsItem.editor?.type || ''; - if (dgControl[componentsItem.editor.type]?.icon) { - iconType = dgControl[componentsItem.editor.type].icon; - } + iconType = dgControl[componentsItem.editor?.type]?.icon || componentsItem.editor?.type || ''; break; } default: { @@ -131,6 +128,9 @@ export function useOutlineNode(designerHostService: DesignerHostService, context case ComponentType.calendar: { return '日历组件'; } + case ComponentType.page: { + return componentsItem.name || '页面'; + } default: { return '组件'; } diff --git a/packages/ui-vue/components/designer-outline/src/types.ts b/packages/ui-vue/components/designer-outline/src/types.ts index 2ff6f26ebf..858e5fab0f 100644 --- a/packages/ui-vue/components/designer-outline/src/types.ts +++ b/packages/ui-vue/components/designer-outline/src/types.ts @@ -30,7 +30,12 @@ export enum ComponentType { /** * 日历 */ - calendar = 'calendar' + calendar = 'calendar', + + /** + * 页面 + */ + page = 'page' } /** -- Gitee From d42f7836c4a2db9457df28ca25d74adacde455b2 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Fri, 21 Nov 2025 10:26:27 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E6=94=AF=E6=8C=81=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + .../lib/application-param.service.ts | 20 ++++- .../lib/dynamic-script.service.ts | 27 +++++- packages/designer/farris.config.mjs | 2 - packages/designer/package.json | 1 - packages/designer/src/app-providers.ts | 8 +- .../dynamic-script.service.ts | 84 ++++++++++++++++++ .../designer-context/use-designer-context.ts | 50 +++++------ .../use-mobile-designer-context.ts | 27 +++--- .../use-pc-designer-context.ts | 4 +- .../use-pc-rtc-designer-context.ts | 3 +- .../src/components/designer.component.tsx | 2 +- .../src/components/types/designer-context.ts | 15 +++- .../types/toolbox/mobile-toolbox.json | 6 ++ .../components/dialog/src/index.tsx | 4 +- .../dialog/src/message-box.service.tsx | 88 +++++++++++++++++++ 16 files changed, 291 insertions(+), 51 deletions(-) create mode 100644 packages/designer/src/components/composition/designer-context/dynamic-script.service.ts create mode 100644 packages/mobile-ui-vue/components/dialog/src/message-box.service.tsx diff --git a/package.json b/package.json index 33a08cafdd..af76a17bbd 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "build:ui-binding-vue": "pnpm --filter ui-binding-vue run build:lib && pnpm --filter ui-binding-vue run rollup", "build:renderer": "pnpm --filter renderer run build:system", "build:ui-vue": "pnpm --filter ui-vue run build:lib && pnpm --filter ui-vue run build:system", + "build:mobile-ui-vue": "pnpm --filter mobile-ui-vue run build:lib", "build:charts-vue": "pnpm --filter charts-vue run build:lib && pnpm --filter charts-vue run build:system", "build:designer": "pnpm --filter designer run build:system", "build:expression-engine-vue": "pnpm --filter expression-engine-vue run rollup", diff --git a/packages/command-services/lib/application-param.service.ts b/packages/command-services/lib/application-param.service.ts index 136f2088a2..4490c72550 100644 --- a/packages/command-services/lib/application-param.service.ts +++ b/packages/command-services/lib/application-param.service.ts @@ -7,6 +7,7 @@ import { RuntimeFrameworkService } from './rtf.service'; */ export class ApplicationParamService { + private WEB_FORM_PARAM_KYES = 'WEB_FORM_PARAM_KYES'; constructor( private paramService: ParamService, private runtimeFrameworkService: RuntimeFrameworkService, @@ -58,14 +59,31 @@ export class ApplicationParamService { */ private setQueryParams(queryParams: any, viewModel: ViewModel): any { const parsedQueryParams: any = {}; + if(!viewModel || !viewModel.uiStore){ + return; + } + const uiState = viewModel.uiStore; + + // 把上一次参数清除 + const oldParamKeys = uiState.getValue(this.WEB_FORM_PARAM_KYES); + if (oldParamKeys && oldParamKeys.length > 0) { + oldParamKeys.forEach((paramKey: string) => { + uiState.setValue(paramKey, null); + }); + } + // 设置表单参数 - const uiState = viewModel && viewModel.uiStore || {}; + const newParamKeys:string[] = []; Object.keys(queryParams).forEach((paramName: string) => { if (!uiState.hasOwnProperty(paramName)) { + newParamKeys.push(paramName); parsedQueryParams[paramName] = queryParams[paramName]; } }); + + uiState.setValue(this.WEB_FORM_PARAM_KYES,newParamKeys); + this.updateUIState(viewModel, parsedQueryParams); } diff --git a/packages/command-services/lib/dynamic-script.service.ts b/packages/command-services/lib/dynamic-script.service.ts index 18ca3b64ba..59a8689ec0 100644 --- a/packages/command-services/lib/dynamic-script.service.ts +++ b/packages/command-services/lib/dynamic-script.service.ts @@ -17,8 +17,19 @@ export class DynamicScriptService { */ private scriptInfoMap: any = { "ui": [ - { terminal: Terminal.PC, key: '@farris/ui-vue' }, - { terminal: Terminal.Mobile, key: '@farris/mobile-ui-vue' } + { + terminal: Terminal.PC, + key: '@farris/ui-vue', + cssPaths: [] + }, + { + terminal: Terminal.Mobile, + key: '@farris/mobile-ui-vue', + cssPaths: [ + '/platform/common/web/assets/farris-mobile-page-vue.css?version=20251023', + '/platform/common/web/assets/farris-mobile-ui-vue.css?version=20251023' + ] + } ] } @@ -28,6 +39,13 @@ export class DynamicScriptService { } + private loadCss(path: string) { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = path; + document.head.appendChild(link) + } + /** * 加载脚本 */ @@ -45,6 +63,11 @@ export class DynamicScriptService { const scriptInfoList = this.scriptInfoMap[scriptKey]; const scriptInfo: any = scriptInfoList.find((scriptInfo: any) => scriptInfo.terminal === this.terminal.value); const scriptPath = manifest.default['imports'][scriptInfo.key]; + + scriptInfo.cssPaths.forEach((cssPath: string) => { + this.loadCss(cssPath); + }); + if (scriptPath) { const result = await System.import(scriptPath); this.module[scriptKey] = result; diff --git a/packages/designer/farris.config.mjs b/packages/designer/farris.config.mjs index af9fa5863f..c7d2a4db44 100644 --- a/packages/designer/farris.config.mjs +++ b/packages/designer/farris.config.mjs @@ -12,7 +12,6 @@ const replaceUIVueComponentsPath = function () { const chunk = bundle[fileName]; if (chunk.type === 'chunk') { chunk.code = chunk.code.replace(/@farris\/ui-vue\/components/g, '@farris/ui-vue'); - chunk.code = chunk.code.replace(/@farris\/mobile-ui-vue\/components/g, '@farris/mobile-ui-vue'); } } } @@ -42,7 +41,6 @@ export default { alias: [ { find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)) }, { find: '@farris/ui-vue/components', replacement: fileURLToPath(new URL('../ui-vue/components', import.meta.url)) }, - { find: '@farris/mobile-ui-vue', replacement: fileURLToPath(new URL('../mobile-ui-vue/components', import.meta.url)) }, { find: '@farris/code-editor-vue/components', replacement: fileURLToPath(new URL('../code-editor/components', import.meta.url)) } ], // 插件 默认值 [vue(), vueJsx()] 不要重复添加 diff --git a/packages/designer/package.json b/packages/designer/package.json index 0e86043241..d6e2d95f50 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "@farris/ui-vue": "workspace:^", - "@farris/mobile-ui-vue": "workspace:^", "@farris/code-editor-vue":"workspace:^", "@monaco-editor/loader": "^1.4.0", "monaco-editor": "^0.52.2", diff --git a/packages/designer/src/app-providers.ts b/packages/designer/src/app-providers.ts index c87803ff7c..cd6e81667b 100644 --- a/packages/designer/src/app-providers.ts +++ b/packages/designer/src/app-providers.ts @@ -7,10 +7,14 @@ import { MetadataPathToken, MetadataServiceToken } from "./components/types"; import { LookupFieldSelectorService, LookupSchemaService } from "./components/composition/schema-repository"; import { ControllerSelectorSchemaService } from "./components/composition/schema-repository/controller/controller-selector.service"; import { FormSelectorSchemaService } from "./components/composition/schema-repository/form/form-selector.service"; -import { useDesignerContext } from "./components/composition/designer-context/use-designer-context"; +import { getDesignerMode, useDesignerContext } from "./components/composition/designer-context/use-designer-context"; import { globalRichTextEditorAssetsPath } from '@farris/ui-vue'; +import { DynamicScriptService } from "./components/composition/designer-context/dynamic-script.service"; -const designerContext = useDesignerContext(); +const dynamicScriptService = new DynamicScriptService(getDesignerMode()); +await dynamicScriptService.load(); + +const designerContext = useDesignerContext(dynamicScriptService); export default { install(app: App): void { diff --git a/packages/designer/src/components/composition/designer-context/dynamic-script.service.ts b/packages/designer/src/components/composition/designer-context/dynamic-script.service.ts new file mode 100644 index 0000000000..b3d9052af5 --- /dev/null +++ b/packages/designer/src/components/composition/designer-context/dynamic-script.service.ts @@ -0,0 +1,84 @@ +import { DesignerMode, Terminal } from "../../types/designer-context"; + +declare const System: any; + + +/** + * 动态加载脚本 + */ +export class DynamicScriptService { + /** + * 已加载脚本的模块 + */ + private module: any = {}; + private manifestPath: string = '/platform/runtime/common/web/runtime.common.web.manifest.json'; + /** + * 脚本信息 + */ + private scriptInfoMap: any = { + "ui": [ + { terminal: Terminal.PC, key: '@farris/ui-vue' }, + { + terminal: Terminal.Mobile, + key: '@farris/mobile-ui-vue', + cssPaths: [ + '/platform/common/web/assets/farris-mobile-page-vue.css?version=20250123', + '/platform/common/web/assets/farris-mobile-ui-vue.css?version=20250123' + ] + } + ], + "css": [ + { terminal: Terminal.PC, key: '@farris/ui-vue' }, + { terminal: Terminal.Mobile, key: '@farris/mobile-ui-vue' } + ] + } + + private terminal: Terminal = Terminal.PC; + + constructor( + private designerMode: DesignerMode + ) { + this.terminal = this.designerMode.split('_')[0] as Terminal; + } + + private loadCss(path: string){ + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = path; + document.head.appendChild(link) + } + /** + * 加载脚本 + */ + public async load(): Promise { + if (Object.keys(this.module).length > 0) { + return Promise.resolve(this.module); + } + + // 1、加载manifest,获取脚本路径 + const nowTime = new Date().getTime(); + const manifest = await System.import(`${this.manifestPath}?v=${nowTime}`); + + // 2、动态加载脚本和样式 + for (const scriptKey of Object.keys(this.scriptInfoMap)) { + const scriptInfoList = this.scriptInfoMap[scriptKey]; + const scriptInfo: any = scriptInfoList.find((scriptInfo: any) => scriptInfo.terminal === this.terminal); + const scriptPath = manifest.default['imports'][scriptInfo.key]; + if (scriptPath) { + const result = await System.import(scriptPath); + this.module[scriptKey] = result; + } + + scriptInfo.cssPaths?.forEach(cssPath => { + this.loadCss(cssPath); + }); + }; + + return Promise.resolve(this.module); + } + + public getModule(): any { + return this.module; + } + +} diff --git a/packages/designer/src/components/composition/designer-context/use-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-designer-context.ts index 2b204cdd42..26973f5bf3 100644 --- a/packages/designer/src/components/composition/designer-context/use-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-designer-context.ts @@ -1,43 +1,43 @@ import { DesignerMode, UseDesignerContext } from "../../types/designer-context"; import { useLocation } from "../use-location"; +import { DynamicScriptService } from "./dynamic-script.service"; import { useMobileDesignerContext } from "./use-mobile-designer-context"; import { usePCDesignerContext } from "./use-pc-designer-context"; import { usePCRtcDesignerContext } from "./use-pc-rtc-designer-context"; - /** - * 设计器上下文 - * @returns + * 判断的当前设计器运行环境 */ -export function useDesignerContext(): UseDesignerContext { - /** - * 判断的当前设计器运行环境 - */ - function getDesignerMode(): DesignerMode { - const { getHrefParam, getUrlParam } = useLocation(); - const metadataPath = getUrlParam('id') || ''; - const designerEnvType = getHrefParam('envType'); +export function getDesignerMode(): DesignerMode { + const { getHrefParam, getUrlParam } = useLocation(); + const metadataPath = getUrlParam('id') || ''; + const designerEnvType = getHrefParam('envType'); - if (designerEnvType === 'runtimeCustom') { - return DesignerMode.PC_RTC; - } - if (metadataPath && metadataPath.includes('.mfrm')) { - return DesignerMode.Mobile; - } - - return DesignerMode.PC; + if (designerEnvType === 'runtimeCustom') { + return DesignerMode.PC_RTC; + } + if (metadataPath && metadataPath.includes('.mfrm')) { + return DesignerMode.Mobile; } + return DesignerMode.PC; +} + +/** + * 设计器上下文 + * @returns + */ +export function useDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { const designerMode = getDesignerMode(); switch (designerMode) { - case DesignerMode.PC: case DesignerMode.Mobile: { - return usePCDesignerContext(); + case DesignerMode.PC: { + return usePCDesignerContext(dynamicScriptService); + } + case DesignerMode.Mobile: { + return useMobileDesignerContext(dynamicScriptService); } - // { - // return useMobileDesignerContext(); - // } case DesignerMode.PC_RTC: { - return usePCRtcDesignerContext(); + return usePCRtcDesignerContext(dynamicScriptService); } } } diff --git a/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts index ef41dba0c1..aaca53034a 100644 --- a/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts @@ -1,29 +1,30 @@ import { DesignerMode, UseDesignerContext } from "../../types/designer-context"; import ToolboxItems from '../../types/toolbox/mobile-toolbox.json'; import SupportedControllers from '../../composition/command/supported-controllers/pc-supported-controller.json'; - -import { registerDesignerComponents, registerComponents, components,DgControl } from '@farris/mobile-ui-vue'; -import { useMobileControlCreator } from "../control-creator/use-mobile-control-creator"; +import { usePCControlCreator } from "../control-creator/use-pc-control-creator.service"; import { FormComponent, UseFormSchema } from "../../../components/types"; import ControllCategories from '../schema-repository/controller/mobile-categories'; import { useFormMetadata } from "../form-metadata.service"; import { useCommandBuilderService as useCommandBuilder } from "../command-builder.service"; +import { DynamicScriptService } from "./dynamic-script.service"; + +export function useMobileDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { -export function useMobileDesignerContext(): UseDesignerContext { + const uiModel = dynamicScriptService?.getModule().ui; + uiModel?.registerDesignerComponents(); + uiModel?.registerComponents(); /** 设计器模式 */ const designerMode: DesignerMode = DesignerMode.Mobile; - + /** 控件清单 */ - const dgControl: any = DgControl; + const dgControl: any = uiModel?.DgControl; /** 工具箱的数据 */ const toolboxItems: any[] = ToolboxItems; /** 要注册的UI组件 */ - const componentsToRegister: any[] = components; - registerDesignerComponents(); - registerComponents(); + const componentsToRegister: any[] = uiModel?.components; /** 支持的控制器 */ const supportedControllers: any = SupportedControllers; @@ -32,7 +33,7 @@ export function useMobileDesignerContext(): UseDesignerContext { /** 控件创建服务 */ - const useControlCreator = useMobileControlCreator; + const useControlCreator = usePCControlCreator; /** 表单元数据服务 */ const useFormMetadataService = useFormMetadata; @@ -40,6 +41,8 @@ export function useMobileDesignerContext(): UseDesignerContext { /** 表单构件元数据服务 */ const useCommandBuilderService = useCommandBuilder; + const schemaDOMMapping = uiModel?.SchemaDOMMapping; + /** * 获取所有的页面组件 * @returns @@ -52,6 +55,7 @@ export function useMobileDesignerContext(): UseDesignerContext { return { designerMode, + uiModel, dgControl, toolboxItems, componentsToRegister, @@ -60,6 +64,7 @@ export function useMobileDesignerContext(): UseDesignerContext { useControlCreator, getPageComponents, useFormMetadataService, - useCommandBuilderService + useCommandBuilderService, + schemaDOMMapping, }; } diff --git a/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts index 39fa01da2f..d879e4e634 100644 --- a/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts @@ -6,8 +6,9 @@ import { FormComponent, UseFormSchema } from "../../../components/types"; import ControllCategories from '../schema-repository/controller/pc-categories'; import { useFormMetadata } from "../form-metadata.service"; import { useCommandBuilderService as useCommandBuilder } from "../command-builder.service"; +import { DynamicScriptService } from "./dynamic-script.service"; -export function usePCDesignerContext(): UseDesignerContext { +export function usePCDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { /** 设计器模式 */ const designerMode: DesignerMode = DesignerMode.PC; @@ -45,6 +46,7 @@ export function usePCDesignerContext(): UseDesignerContext { return pageComponents; } + return { designerMode, toolboxItems, diff --git a/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts index ae738fda6c..2e009a8a13 100644 --- a/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts @@ -9,8 +9,9 @@ import axios from "axios"; import { ElementPropertyConfig } from "@farris/ui-vue/components/property-panel"; import { FNotifyService } from "@farris/ui-vue/components"; import { useRtcCommandBuilderService as useRtcCommandBuilder } from "../command-builder-rtc.service"; +import { DynamicScriptService } from "./dynamic-script.service"; -export function usePCRtcDesignerContext(): UseDesignerContext { +export function usePCRtcDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { /** 设计器模式 */ const designerMode: DesignerMode = DesignerMode.PC_RTC; diff --git a/packages/designer/src/components/designer.component.tsx b/packages/designer/src/components/designer.component.tsx index f2ca0ee462..97e7396b5f 100644 --- a/packages/designer/src/components/designer.component.tsx +++ b/packages/designer/src/components/designer.component.tsx @@ -74,7 +74,7 @@ export default defineComponent({ // metadatFullPath const metadataPath: string = inject(MetadataPathToken, ''); // 控件创建服务 - const controlCreatorService = designerContext.useControlCreator(schemaService, useFormStateMachineComposition); + const controlCreatorService = designerContext.useControlCreator(schemaService, useFormStateMachineComposition, designerContext); provide('controlCreatorUtils', controlCreatorService); provide('formMetadataConverter', new FormMetadataConverter()); const { eventBetweenDesignerAndCodeView } = commandBuilderService; diff --git a/packages/designer/src/components/types/designer-context.ts b/packages/designer/src/components/types/designer-context.ts index 0695060703..86fe6181fa 100644 --- a/packages/designer/src/components/types/designer-context.ts +++ b/packages/designer/src/components/types/designer-context.ts @@ -1,6 +1,6 @@ import { ElementPropertyConfig } from "@farris/ui-vue/components/property-panel"; import { DesignerProps } from "../designer.props"; -import { FormComponent, UseControlCreator, UseFormMetadata, UseFormSchema, UseSchemaService } from "../types"; +import { FormComponent, UseControlCreator, UseFormMetadata, UseFormSchema, UseFormStateMachine, UseSchemaService } from "../types"; import { UseCommandBuilderService } from "./command"; /** 设计器模式 */ @@ -15,15 +15,24 @@ export enum DesignerMode { PC_RTC = 'PC_RTC' } +/** + * 终端 + */ +export enum Terminal { + PC = 'PC', + Mobile = 'Mobile' +} + export interface UseDesignerContext { dgControl: any; + uiModel?: any; instances?: Record; designerMode: DesignerMode; toolboxItems: any[]; componentsToRegister: any[]; supportedControllers: any; controllCategories: any; - useControlCreator: (schemaService: UseSchemaService, useFormStateMachineComposition: UseFormStateMachine) => UseControlCreator; + useControlCreator: (schemaService: UseSchemaService, useFormStateMachineComposition: UseFormStateMachine, designerContext: UseDesignerContext) => UseControlCreator; getPageComponents: (useFormSchema: UseFormSchema) => FormComponent[]; /** 查询元数据内容 */ @@ -48,4 +57,6 @@ export interface UseDesignerContext { /** 表单构件元数据服务 */ useCommandBuilderService: (formSchemaService: UseFormSchema) => UseCommandBuilderService + + schemaDOMMapping?: Record; } diff --git a/packages/designer/src/components/types/toolbox/mobile-toolbox.json b/packages/designer/src/components/types/toolbox/mobile-toolbox.json index a57dbd113a..aa158d66b2 100644 --- a/packages/designer/src/components/types/toolbox/mobile-toolbox.json +++ b/packages/designer/src/components/types/toolbox/mobile-toolbox.json @@ -65,6 +65,12 @@ "category": "input", "icon": "radio-group" }, + { + "id": "CheckBox", + "type": "check-box", + "name": "复选框", + "category": "input" + }, { "id": "CheckBoxGroup", "type": "check-group", diff --git a/packages/mobile-ui-vue/components/dialog/src/index.tsx b/packages/mobile-ui-vue/components/dialog/src/index.tsx index 05433ca2ac..771c1838ca 100644 --- a/packages/mobile-ui-vue/components/dialog/src/index.tsx +++ b/packages/mobile-ui-vue/components/dialog/src/index.tsx @@ -3,7 +3,7 @@ import { mountComponent, usePopupState, isObject, inBrowser } from '@farris/mobi import { InputProps, InputGroup } from '@farris/mobile-ui-vue/input-group'; import { DialogProps, MessageAlign } from './dialog.props'; import FMDialog from './dialog.component'; - +import FMessageBoxService from './message-box.service'; let instance; function defaultOptions(): DialogProps { @@ -185,7 +185,7 @@ Dialog.resetDefaultOptions = () => { Dialog.install = (app: App) => { app.component((FMDialog.name as string), FMDialog); app.config.globalProperties.$dialog = Dialog; - app.provide("FMessageBoxService",Dialog) + app.provide("FMessageBoxService",FMessageBoxService) }; Dialog.Component = FMDialog; diff --git a/packages/mobile-ui-vue/components/dialog/src/message-box.service.tsx b/packages/mobile-ui-vue/components/dialog/src/message-box.service.tsx new file mode 100644 index 0000000000..6d80cd2802 --- /dev/null +++ b/packages/mobile-ui-vue/components/dialog/src/message-box.service.tsx @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { getCurrentInstance, reactive } from 'vue'; +import Dialog from './index'; + +export interface ExceptionInfo { + date: string; + message: string; + detail: string; +} + +export interface MessageBoxOption { + width?: number; + type: string; + title?: string; + detail?: string; + okButtonText?: string; + cancelButtonText?: string; + exceptionInfo?: ExceptionInfo; + acceptCallback?: () => void; + rejectCallback?: () => void; + buttons?: Array; +} + +export default class MessageBoxService { + public static app: any = null; + + static show(options: MessageBoxOption) { + Dialog({ + message: options.detail, + title: options.title, + showClose: false, + buttons: options.buttons, + }); + } + + static info(message: string, detail: string) { + Dialog.alert({ + message + }); + } + + static warning(message: string, detail: string) { + Dialog.alert({ + message + }); + } + + static success(message: string, detail: string) { + Dialog.alert({ + message + }); + } + + static error(message: string, detail: string, date?: string): any { + Dialog.alert({ + message + }); + } + + static prompt(message: string, detail: string) { + Dialog.alert({ + message + }); + + } + + static question(message: string, detail: string, acceptCallback: () => void, rejectCallback: () => void) { + Dialog.confirm({ + message, + onConfirm: acceptCallback, + onCancel: rejectCallback, + }); + } +} -- Gitee From 82c7507dba5f651ee96fc770a1e34cd82f6849a0 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 24 Nov 2025 10:38:45 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=E6=94=AF=E6=8C=81=E8=9E=8D=E5=90=88?= =?UTF-8?q?=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/app-providers.ts | 8 +-- .../composition/handler/frm-cmp-builder.ts | 10 ++-- .../dynamic-script.service.ts | 58 +++++++++++-------- .../designer-context/use-designer-context.ts | 54 ++++++++++++++--- .../use-mobile-designer-context.ts | 9 ++- .../use-pc-designer-context.ts | 9 +-- .../use-pc-rtc-designer-context.ts | 2 +- .../composition/metadata.service.ts | 16 ++--- .../lookup/lookup-field-selector.service.ts | 8 +-- .../src/components/designer.component.tsx | 50 ++++++++++++++-- .../src/components/types/designer-context.ts | 16 ++++- .../designer/src/components/types/metadata.ts | 3 + .../types/toolbox/mobile-toolbox.json | 2 +- packages/designer/src/style.css | 30 ++++++++++ packages/renderer/src/app.vue | 8 ++- ...on-component-config-dependency-resolver.ts | 32 ++++++++++ .../index.ts | 1 + .../providers.ts | 2 + .../button-component-config-resolver.ts | 28 +++++++++ .../src/component-config-resolver/index.ts | 1 + .../component-config-resolver/providers.ts | 2 + 21 files changed, 281 insertions(+), 68 deletions(-) create mode 100644 packages/renderer/src/component-config-dependency-resolver/button-component-config-dependency-resolver.ts create mode 100644 packages/renderer/src/component-config-resolver/button-component-config-resolver.ts diff --git a/packages/designer/src/app-providers.ts b/packages/designer/src/app-providers.ts index cd6e81667b..6b71959798 100644 --- a/packages/designer/src/app-providers.ts +++ b/packages/designer/src/app-providers.ts @@ -7,13 +7,13 @@ import { MetadataPathToken, MetadataServiceToken } from "./components/types"; import { LookupFieldSelectorService, LookupSchemaService } from "./components/composition/schema-repository"; import { ControllerSelectorSchemaService } from "./components/composition/schema-repository/controller/controller-selector.service"; import { FormSelectorSchemaService } from "./components/composition/schema-repository/form/form-selector.service"; -import { getDesignerMode, useDesignerContext } from "./components/composition/designer-context/use-designer-context"; +import { getInitTerminal, useDesignerContext } from "./components/composition/designer-context/use-designer-context"; import { globalRichTextEditorAssetsPath } from '@farris/ui-vue'; import { DynamicScriptService } from "./components/composition/designer-context/dynamic-script.service"; -const dynamicScriptService = new DynamicScriptService(getDesignerMode()); -await dynamicScriptService.load(); - +const dynamicScriptService = new DynamicScriptService(); +const terminal = getInitTerminal(); +await dynamicScriptService.load(terminal); const designerContext = useDesignerContext(dynamicScriptService); export default { diff --git a/packages/designer/src/components/components/code-view/composition/handler/frm-cmp-builder.ts b/packages/designer/src/components/components/code-view/composition/handler/frm-cmp-builder.ts index 15fb0ce65c..5a3b114565 100644 --- a/packages/designer/src/components/components/code-view/composition/handler/frm-cmp-builder.ts +++ b/packages/designer/src/components/components/code-view/composition/handler/frm-cmp-builder.ts @@ -5,8 +5,8 @@ import { FieldOption } from "../type/fields-getter"; import { MetadataService } from "../../../../composition/metadata.service"; import { NavDataUtilService } from "./nav-data-util.service"; import { fieldGetterController } from "./field-getter"; -import { DesignerMode } from "../../../../../components/types/designer-context"; -import { useDesignerContext } from "../../../../../components/composition/designer-context/use-designer-context"; +import { DesignerEnvironment } from "../../../../../components/types/designer-context"; +import { getDesignerEnvironment } from "../../../../../components/composition/designer-context/use-designer-context"; import { MetadataDto as FormMetadataDto } from "../../../../../components/types/metadata"; import { MetadataDto } from "../entity/metadata-generator"; @@ -41,12 +41,12 @@ export class FrmCmpBuilder { metadataService: MetadataService; navDataUtilService: NavDataUtilService; fieldGetter; - private designerMode: DesignerMode; + private designerEnvironment: DesignerEnvironment; constructor(private formBasicInfo: FormMetadataDto) { this.metadataService = new MetadataService(); this.navDataUtilService = new NavDataUtilService(); this.fieldGetter = fieldGetterController(); - this.designerMode = useDesignerContext().designerMode; + this.designerEnvironment = getDesignerEnvironment(); } /** * 弹框新增一个前端控制器构件 @@ -81,7 +81,7 @@ export class FrmCmpBuilder { if (fieldsMap) { const code: string = (fieldsMap.code || 'Controller').trim(); const name: string = (fieldsMap.name || code).trim(); - return this.designerMode === DesignerMode.PC_RTC ? this.doAddRtcNewCmp(code, name) : this.doAddNewCmp(code, name, frmPath); + return this.designerEnvironment === DesignerEnvironment.RTC ? this.doAddRtcNewCmp(code, name) : this.doAddNewCmp(code, name, frmPath); } return null; } diff --git a/packages/designer/src/components/composition/designer-context/dynamic-script.service.ts b/packages/designer/src/components/composition/designer-context/dynamic-script.service.ts index b3d9052af5..896ff9b1ba 100644 --- a/packages/designer/src/components/composition/designer-context/dynamic-script.service.ts +++ b/packages/designer/src/components/composition/designer-context/dynamic-script.service.ts @@ -1,4 +1,4 @@ -import { DesignerMode, Terminal } from "../../types/designer-context"; +import { DesignerTerminal } from "../../types/designer-context"; declare const System: any; @@ -11,36 +11,34 @@ export class DynamicScriptService { * 已加载脚本的模块 */ private module: any = {}; + private loadedTerminals: DesignerTerminal[] = []; + private manifestPath: string = '/platform/runtime/common/web/runtime.common.web.manifest.json'; /** * 脚本信息 */ private scriptInfoMap: any = { "ui": [ - { terminal: Terminal.PC, key: '@farris/ui-vue' }, + { terminal: DesignerTerminal.PC, key: '@farris/ui-vue', needLoad: false }, { - terminal: Terminal.Mobile, + terminal: DesignerTerminal.Mobile, key: '@farris/mobile-ui-vue', cssPaths: [ '/platform/common/web/assets/farris-mobile-page-vue.css?version=20250123', '/platform/common/web/assets/farris-mobile-ui-vue.css?version=20250123' ] } - ], - "css": [ - { terminal: Terminal.PC, key: '@farris/ui-vue' }, - { terminal: Terminal.Mobile, key: '@farris/mobile-ui-vue' } ] } - private terminal: Terminal = Terminal.PC; - - constructor( - private designerMode: DesignerMode - ) { - this.terminal = this.designerMode.split('_')[0] as Terminal; - } + public currentTerminal: DesignerTerminal = DesignerTerminal.PC; + + constructor() {} + /** + * 加载样式 + * @param path + */ private loadCss(path: string){ const link = document.createElement('link'); link.rel = 'stylesheet'; @@ -50,23 +48,35 @@ export class DynamicScriptService { /** * 加载脚本 */ - public async load(): Promise { - if (Object.keys(this.module).length > 0) { - return Promise.resolve(this.module); + public async load(terminal: DesignerTerminal): Promise { + this.currentTerminal = terminal; + + // 1、检测是否已加载 + if(this.loadedTerminals.includes(terminal)){ + return Promise.resolve(this.module[terminal]); } - // 1、加载manifest,获取脚本路径 + if (this.module[terminal]) { + return Promise.resolve(this.module[terminal]); + } + + // 2、加载manifest,获取脚本路径 const nowTime = new Date().getTime(); const manifest = await System.import(`${this.manifestPath}?v=${nowTime}`); - // 2、动态加载脚本和样式 + // 3、动态加载脚本和样式 + this.module[terminal] = {}; for (const scriptKey of Object.keys(this.scriptInfoMap)) { const scriptInfoList = this.scriptInfoMap[scriptKey]; - const scriptInfo: any = scriptInfoList.find((scriptInfo: any) => scriptInfo.terminal === this.terminal); + const scriptInfo: any = scriptInfoList.find((scriptInfo: any) => scriptInfo.terminal === terminal); + if(scriptInfo.needLoad === false){ + continue; + } + const scriptPath = manifest.default['imports'][scriptInfo.key]; if (scriptPath) { const result = await System.import(scriptPath); - this.module[scriptKey] = result; + this.module[terminal][scriptKey] = result; } scriptInfo.cssPaths?.forEach(cssPath => { @@ -74,11 +84,13 @@ export class DynamicScriptService { }); }; - return Promise.resolve(this.module); + this.loadedTerminals.push(terminal) + + return Promise.resolve(this.module[terminal]); } public getModule(): any { - return this.module; + return this.module[this.currentTerminal]; } } diff --git a/packages/designer/src/components/composition/designer-context/use-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-designer-context.ts index 26973f5bf3..b36128e97a 100644 --- a/packages/designer/src/components/composition/designer-context/use-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-designer-context.ts @@ -1,21 +1,50 @@ -import { DesignerMode, UseDesignerContext } from "../../types/designer-context"; +import { DesignerEnvironment, DesignerMode, DesignerTerminal, UseDesignerContext } from "../../types/designer-context"; import { useLocation } from "../use-location"; import { DynamicScriptService } from "./dynamic-script.service"; import { useMobileDesignerContext } from "./use-mobile-designer-context"; import { usePCDesignerContext } from "./use-pc-designer-context"; import { usePCRtcDesignerContext } from "./use-pc-rtc-designer-context"; + /** - * 判断的当前设计器运行环境 + * 获取设计器终端类型。该方法只能在初始化时调用,因为PC和移动融合开发模式下,支持切换终端类型。 + * @returns */ -export function getDesignerMode(): DesignerMode { - const { getHrefParam, getUrlParam } = useLocation(); +export function getInitTerminal(): DesignerTerminal { + const { getUrlParam } = useLocation(); const metadataPath = getUrlParam('id') || ''; + + if (metadataPath && metadataPath.includes('.mfrm')) { + return DesignerTerminal.Mobile; + } + return DesignerTerminal.PC; +} + +/** + * 获取设计器环境 + * @returns + */ +export function getDesignerEnvironment(): DesignerEnvironment { + const { getHrefParam } = useLocation(); const designerEnvType = getHrefParam('envType'); if (designerEnvType === 'runtimeCustom') { + return DesignerEnvironment.RTC; + } + + return DesignerEnvironment.LowCode; +} + +/** + * 获取设计器模式 + */ +export function getDesignerMode(terminal: DesignerTerminal): DesignerMode { + const designerEnvType = getDesignerEnvironment(); + + if (terminal === DesignerTerminal.PC && designerEnvType === DesignerEnvironment.RTC) { return DesignerMode.PC_RTC; } - if (metadataPath && metadataPath.includes('.mfrm')) { + + if (terminal === DesignerTerminal.Mobile) { return DesignerMode.Mobile; } @@ -27,17 +56,24 @@ export function getDesignerMode(): DesignerMode { * @returns */ export function useDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { - const designerMode = getDesignerMode(); + const currentTerminal = dynamicScriptService ? dynamicScriptService.currentTerminal : getInitTerminal(); + const designerMode = getDesignerMode(currentTerminal); + + let designerContext: UseDesignerContext; switch (designerMode) { case DesignerMode.PC: { - return usePCDesignerContext(dynamicScriptService); + designerContext = usePCDesignerContext(dynamicScriptService); + break; } case DesignerMode.Mobile: { - return useMobileDesignerContext(dynamicScriptService); + designerContext = useMobileDesignerContext(dynamicScriptService); + break; } case DesignerMode.PC_RTC: { - return usePCRtcDesignerContext(dynamicScriptService); + designerContext = usePCRtcDesignerContext(dynamicScriptService); + break; } } + return designerContext; } diff --git a/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts index aaca53034a..2a70521997 100644 --- a/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts @@ -8,7 +8,7 @@ import { useFormMetadata } from "../form-metadata.service"; import { useCommandBuilderService as useCommandBuilder } from "../command-builder.service"; import { DynamicScriptService } from "./dynamic-script.service"; -export function useMobileDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { +export function useMobileDesignerContext(dynamicScriptService: DynamicScriptService | undefined): UseDesignerContext { const uiModel = dynamicScriptService?.getModule().ui; uiModel?.registerDesignerComponents(); @@ -50,7 +50,12 @@ export function useMobileDesignerContext(dynamicScriptService?: DynamicScriptSer function getPageComponents(useFormSchema: UseFormSchema): FormComponent[] { const predicateFunction = (component: any) => component.componentType && component.componentType.toLowerCase() === 'page'; const pageComponents = useFormSchema.getComponetsByPredicate(predicateFunction); - return pageComponents; + if (pageComponents && pageComponents.length > 0) { + return pageComponents; + } + + const pageComponent = useFormSchema.getComponentById('root-component'); + return pageComponent ? [pageComponent] : []; } return { diff --git a/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts index d879e4e634..fe27a93180 100644 --- a/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts @@ -1,14 +1,14 @@ import { DesignerMode, UseDesignerContext } from "../../types/designer-context"; import ToolboxItems from '../../types/toolbox/pc-toolbox.json'; import { usePCControlCreator } from "../control-creator/use-pc-control-creator.service"; -import SupportedControllers from '../../composition/command/supported-controllers/pc-supported-controller.json'; -import { FormComponent, UseFormSchema } from "../../../components/types"; +import SupportedControllers from '../command/supported-controllers/pc-supported-controller.json'; +import { FormComponent, UseFormSchema } from "../../types"; import ControllCategories from '../schema-repository/controller/pc-categories'; import { useFormMetadata } from "../form-metadata.service"; import { useCommandBuilderService as useCommandBuilder } from "../command-builder.service"; import { DynamicScriptService } from "./dynamic-script.service"; -export function usePCDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { +export function usePCDesignerContext(dynamicScriptService: DynamicScriptService | undefined): UseDesignerContext { /** 设计器模式 */ const designerMode: DesignerMode = DesignerMode.PC; @@ -56,6 +56,7 @@ export function usePCDesignerContext(dynamicScriptService?: DynamicScriptService useControlCreator, getPageComponents, useFormMetadataService, - useCommandBuilderService + useCommandBuilderService, + dynamicScriptService }; } diff --git a/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts index 2e009a8a13..0ceb3093e7 100644 --- a/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts @@ -11,7 +11,7 @@ import { FNotifyService } from "@farris/ui-vue/components"; import { useRtcCommandBuilderService as useRtcCommandBuilder } from "../command-builder-rtc.service"; import { DynamicScriptService } from "./dynamic-script.service"; -export function usePCRtcDesignerContext(dynamicScriptService?: DynamicScriptService): UseDesignerContext { +export function usePCRtcDesignerContext(dynamicScriptService: DynamicScriptService | undefined): UseDesignerContext { /** 设计器模式 */ const designerMode: DesignerMode = DesignerMode.PC_RTC; diff --git a/packages/designer/src/components/composition/metadata.service.ts b/packages/designer/src/components/composition/metadata.service.ts index 5e1e6d645a..fd23252957 100644 --- a/packages/designer/src/components/composition/metadata.service.ts +++ b/packages/designer/src/components/composition/metadata.service.ts @@ -1,10 +1,10 @@ import axios from 'axios'; -import { DesignerMode } from '../types/designer-context'; -import { useDesignerContext } from './designer-context/use-designer-context'; +import { DesignerEnvironment } from '../types/designer-context'; +import { getDesignerEnvironment } from './designer-context/use-designer-context'; import { useLocation } from './use-location'; export class MetadataService { - private designerMode = useDesignerContext().designerMode; + private designerEnvironment = getDesignerEnvironment(); /** 低代码获取元数据url */ private metadataBasePath = '/api/dev/main/v1.0/metadatas'; @@ -40,7 +40,7 @@ export class MetadataService { */ public getMetadataListByType(relativePath: string, metadataType: string): Promise { let url; - if (this.designerMode === DesignerMode.PC_RTC) { + if (this.designerEnvironment === DesignerEnvironment.RTC) { url = `${this.rtcMetadataBasePath}?metadataTypes=${metadataType}`; } else { url = `${this.metadataBasePath}?path=${relativePath}&metadataTypeList=${metadataType}`; @@ -58,7 +58,7 @@ export class MetadataService { */ public getRefMetadata(relativePath: string, metadataId: string): Promise { let url; - if (this.designerMode === DesignerMode.PC_RTC) { + if (this.designerEnvironment === DesignerEnvironment.RTC) { url = `${this.rtcMetadataBasePath}/${metadataId}`; } else { url = `${this.metadataBasePath}/relied?metadataPath=${relativePath}&metadataID=${metadataId}`; @@ -103,7 +103,7 @@ export class MetadataService { public getAllMetadataList(relativePath: string, metadataType: string, pageSize = 1000) { let url = `${this.metadataServicePath}/unionmdlist?path=${relativePath}&`; - if (this.designerMode === DesignerMode.PC_RTC) { + if (this.designerEnvironment === DesignerEnvironment.RTC) { url = `${this.rtcMetadataBasePath}/rtmetadatalist?`; } return axios.get(`${url}pageIndex=1&pageSize=${pageSize}&metadataTypeList=${metadataType}`).then((res: any) => { @@ -116,7 +116,7 @@ export class MetadataService { } public getPickMetadata(relativePath: string, data: any) { - if (this.designerMode === DesignerMode.PC_RTC) { + if (this.designerEnvironment === DesignerEnvironment.RTC) { const url = `${this.rtcMetadataBasePath}/${data?.id}`; return axios.get(url, data).then((res: any) => { return { metadata: res.data }; @@ -130,7 +130,7 @@ export class MetadataService { } public saveMetadata(metadataDto: any, formBasicInfo?: any) { - if (this.designerMode === DesignerMode.PC_RTC) { + if (this.designerEnvironment === DesignerEnvironment.RTC) { const { dimension1, dimension2 } = formBasicInfo; return axios.post(this.rtcMetadataBasePath, { metadataDto, diff --git a/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts b/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts index 1cf50fb7bd..2e60458251 100644 --- a/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts +++ b/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts @@ -1,11 +1,11 @@ import axios from 'axios'; -import { DesignerMode } from '../../../../components/types/designer-context'; -import { useDesignerContext } from '../../designer-context/use-designer-context'; +import { DesignerEnvironment } from '../../../../components/types/designer-context'; +import { getDesignerEnvironment } from '../../designer-context/use-designer-context'; import { MetadataService } from "../../metadata.service"; export class LookupFieldSelectorService { - private designerMode = useDesignerContext().designerMode; + private designerEnvironment = getDesignerEnvironment(); constructor(private metadataService: MetadataService) { } @@ -181,7 +181,7 @@ export class LookupFieldSelectorService { * 运行时定制:在帮助配置中添加FilterExpression以及维度信息 */ private setFilterExpressionAndDimensionForRtc(requestHelpConfig: any, editorParams: any) { - if (requestHelpConfig.helpConfig && editorParams.formBasicInfo && this.designerMode === DesignerMode.PC_RTC) { + if (requestHelpConfig.helpConfig && editorParams.formBasicInfo && this.designerEnvironment === DesignerEnvironment.RTC) { const { dimension1, dimension2 } = editorParams.formBasicInfo; requestHelpConfig.helpConfig.FilterExpression = requestHelpConfig.filterCondition || ''; diff --git a/packages/designer/src/components/designer.component.tsx b/packages/designer/src/components/designer.component.tsx index 97e7396b5f..2e3dea3a3b 100644 --- a/packages/designer/src/components/designer.component.tsx +++ b/packages/designer/src/components/designer.component.tsx @@ -1,4 +1,4 @@ -import { SetupContext, defineComponent, inject, ref, computed, provide, watch, onBeforeMount } from "vue"; +import { SetupContext, defineComponent, inject, ref, computed, provide, watch, onBeforeMount, Ref, getCurrentInstance } from "vue"; import { DesignerProps, designerProps } from "./designer.props"; import { useFormSchema } from "./composition/use-form-schema"; import { FormMetadaDataDom, MetadataPathToken } from "./types"; @@ -16,8 +16,9 @@ import { FormMetadataConverter } from "./composition/form-metadata-converter"; import FCodeViewDesign from "./components/code-view/components/code-view.component"; import useFormStateMachine from './composition/use-form-statemachine'; import { MetadataService } from "./composition/metadata.service"; -import { DesignerMode, UseDesignerContext } from "./types/designer-context"; +import { DesignerMode, DesignerTerminal, UseDesignerContext } from "./types/designer-context"; import { useExternalResource } from "./composition/use-external-resource.service"; +import { useDesignerContext } from "./composition/designer-context/use-designer-context"; export default defineComponent({ name: 'FDesigner', @@ -42,6 +43,11 @@ export default defineComponent({ const codeViewComponent = ref(); const metadataService = new MetadataService(); const designerContext = inject('designerContext') as UseDesignerContext; + const designerComponentKey = ref(0); + const terminalRef: Ref = ref(DesignerTerminal.PC); + const app = getCurrentInstance()?.appContext.app; + const fusionMode = ref(false); + // 注册 formSchema服务 const useFormSchemaComposition = useFormSchema(); provide('useFormSchema', useFormSchemaComposition); @@ -55,7 +61,7 @@ export default defineComponent({ // 操作表单设计时ViewModel的工具类 const designViewModelService = useDesignViewModel(useFormSchemaComposition, schemaService); provide('designViewModelUtils', designViewModelService); - designerContext.instances = { formDesigner: formDesignerRef }; + // 注册 命令服务 const formCommandService = useFormCommandService( useFormSchemaComposition, @@ -84,6 +90,9 @@ export default defineComponent({ onBeforeMount(() => { useFormMetadataComposition.queryMetadata().then((formSchema: FormMetadaDataDom) => { schema.value = formSchema; + fusionMode.value = !!formSchema?.options?.fusionMode; + designerContext.fusionMode = fusionMode.value; + useFormMetadataComposition.queryFormTemplateRule(formSchema?.module).then(() => { metadataLoaded.value = true; // 加载命令=》虽然是异步,但是此处不需要异步串联 @@ -380,6 +389,24 @@ export default defineComponent({ formDesignerRef.value.refreshFormDesigner(); } + async function onChangeTerminal(terminal: any) { + if(!designerContext.dynamicScriptService){ + return; + } + + await designerContext.dynamicScriptService.load(terminal); + const newDesignerContext = useDesignerContext(designerContext.dynamicScriptService); + newDesignerContext.fusionMode = fusionMode.value; + app && app.provide('designerContext', newDesignerContext); + + terminalRef.value = terminal; + designerComponentKey.value++; + } + + const hiddenTerminal = computed(() =>{ + return !fusionMode.value || 'formDesigner' !== activeShowDesignerType.value; + }); + return () => { return ( metadataLoaded.value ? @@ -396,9 +423,24 @@ export default defineComponent({
onChangeShowDesignerType('viewModelDesigner')}>
模型
{designerContext.designerMode === 'PC' &&
onChangeShowDesignerType('formSetting')}>
配置
}
+ +
- + {/* */} diff --git a/packages/designer/src/components/types/designer-context.ts b/packages/designer/src/components/types/designer-context.ts index 86fe6181fa..713b8cde33 100644 --- a/packages/designer/src/components/types/designer-context.ts +++ b/packages/designer/src/components/types/designer-context.ts @@ -2,6 +2,7 @@ import { ElementPropertyConfig } from "@farris/ui-vue/components/property-panel" import { DesignerProps } from "../designer.props"; import { FormComponent, UseControlCreator, UseFormMetadata, UseFormSchema, UseFormStateMachine, UseSchemaService } from "../types"; import { UseCommandBuilderService } from "./command"; +import { DynamicScriptService } from "../composition/designer-context/dynamic-script.service"; /** 设计器模式 */ export enum DesignerMode { @@ -18,15 +19,24 @@ export enum DesignerMode { /** * 终端 */ -export enum Terminal { +export enum DesignerTerminal { PC = 'PC', Mobile = 'Mobile' } +/** + * + */ +export enum DesignerEnvironment { + LowCode = 'LowCode', + NoCode = 'NoCode', + RTC = 'RuntimeCustom' +} + export interface UseDesignerContext { dgControl: any; uiModel?: any; - instances?: Record; + fusionMode:boolean; designerMode: DesignerMode; toolboxItems: any[]; componentsToRegister: any[]; @@ -59,4 +69,6 @@ export interface UseDesignerContext { useCommandBuilderService: (formSchemaService: UseFormSchema) => UseCommandBuilderService schemaDOMMapping?: Record; + + dynamicScriptService: DynamicScriptService|undefined; } diff --git a/packages/designer/src/components/types/metadata.ts b/packages/designer/src/components/types/metadata.ts index 5d4467509c..49f09ad17a 100644 --- a/packages/designer/src/components/types/metadata.ts +++ b/packages/designer/src/components/types/metadata.ts @@ -37,6 +37,9 @@ export interface FormOptions { /** 表单是否启用数据类型转换 */ paramTypeTransform?: boolean; + + /** 融合开发模式 */ + fusionMode?:boolean; } export interface FormMetaDataModule { diff --git a/packages/designer/src/components/types/toolbox/mobile-toolbox.json b/packages/designer/src/components/types/toolbox/mobile-toolbox.json index aa158d66b2..09fe367b79 100644 --- a/packages/designer/src/components/types/toolbox/mobile-toolbox.json +++ b/packages/designer/src/components/types/toolbox/mobile-toolbox.json @@ -46,7 +46,7 @@ }, { "id": "EnumField", - "type": "picker", + "type": "combo-list", "name": "选择器", "category": "input", "icon": "input-group" diff --git a/packages/designer/src/style.css b/packages/designer/src/style.css index 4333eaae90..e7ca5e3acd 100644 --- a/packages/designer/src/style.css +++ b/packages/designer/src/style.css @@ -4,4 +4,34 @@ } .plugin-frame.active { display: block; +} + + + +.terminal-pane { + align-items: center; + display: flex; + margin: 0 4px +} + +.terminal-pane .terminal-pane-item { + border-radius: 3px; + cursor: pointer; + display: inline-block; + height: 32px; + margin: 0 4px; + padding: 6px; + width: 32px +} + +.terminal-pane .terminal-pane-item:hover svg { + opacity: 1 +} + +.terminal-pane .terminal-pane-item.actived { + background: #f1f2f3 +} + +.terminal-pane svg { + opacity: .6 } \ No newline at end of file diff --git a/packages/renderer/src/app.vue b/packages/renderer/src/app.vue index 8b59df1820..e2c224d1a0 100644 --- a/packages/renderer/src/app.vue +++ b/packages/renderer/src/app.vue @@ -82,7 +82,13 @@ router.beforeResolve(async (to: RouteLocationNormalizedGeneric) => { // 添加表单路由 const metadataManager = devkitInjector.get(MetadataManager); const metadatas = metadataManager.getMetadataCache(bizMetadataId.value); - if (metadatas.form.type === "MobileForm") { + let terminal = Terminal.PC; + if(metadatas.form.content?.options?.fusionMode){ + terminal = navigator.userAgent.toLocaleLowerCase().includes('mobile') ? Terminal.Mobile : Terminal.PC; + }else{ + terminal = metadatas.form.type === "MobileForm" ? Terminal.Mobile : Terminal.PC; + } + if (terminal === Terminal.Mobile) { const terminal = devkitInjector.get(TERMINAL_TOKEN) as Ref; terminal.value = Terminal.Mobile; addFormRoute(metadatas.form, router); diff --git a/packages/renderer/src/component-config-dependency-resolver/button-component-config-dependency-resolver.ts b/packages/renderer/src/component-config-dependency-resolver/button-component-config-dependency-resolver.ts new file mode 100644 index 0000000000..797c70216a --- /dev/null +++ b/packages/renderer/src/component-config-dependency-resolver/button-component-config-dependency-resolver.ts @@ -0,0 +1,32 @@ +import { isNil } from "lodash-es"; +import { Configuration, ConfigurationType } from "../config"; +import { ConfigDependencyResolveService } from "../config-dependency-resolver"; +import { ComponentConfigDependencyResolver } from "./component-config-dependency-resolver"; + +export class ButtonComponentConfigDependencyResolver extends ComponentConfigDependencyResolver { + + constructor(private configDepencencyResolveService: ConfigDependencyResolveService) { + super(); + } + + public resolve(schema: Record): Configuration[] | null { + if (!schema || schema.type !== 'button') { + return null; + } + const { visible, disabled } = schema; + const configs: Configuration[] = []; + if (!isNil(visible)) { + const visibleConfigDeps = this.configDepencencyResolveService.resolve(visible, schema); + if (visibleConfigDeps) { + configs.push({ deps: visibleConfigDeps, config: visible, path: '/visible', type: ConfigurationType.Visible }); + } + } + if (!isNil(disabled)) { + const disabledConfigDeps = this.configDepencencyResolveService.resolve(disabled, schema); + if (disabledConfigDeps) { + configs.push({ deps: disabledConfigDeps, config: disabled, path: '/disabled', type: ConfigurationType.Disabled }); + } + } + return configs; + } +} diff --git a/packages/renderer/src/component-config-dependency-resolver/index.ts b/packages/renderer/src/component-config-dependency-resolver/index.ts index 075b37ea7b..110c111ea2 100644 --- a/packages/renderer/src/component-config-dependency-resolver/index.ts +++ b/packages/renderer/src/component-config-dependency-resolver/index.ts @@ -15,4 +15,5 @@ export * from './tabs-component-config-dependency-resolver'; export * from './filter-bar-component-config-dependency-resolver'; export * from './drawer-component-config-dependency-resolver'; export * from './calendar-component-config-dependency-resolver'; +export * from './button-component-config-dependency-resolver'; export * from './providers'; diff --git a/packages/renderer/src/component-config-dependency-resolver/providers.ts b/packages/renderer/src/component-config-dependency-resolver/providers.ts index 621d41c0be..587e7edeaa 100644 --- a/packages/renderer/src/component-config-dependency-resolver/providers.ts +++ b/packages/renderer/src/component-config-dependency-resolver/providers.ts @@ -17,6 +17,7 @@ import { TabsComponentConfigDependencyResolver } from "./tabs-component-config-d import { FilterBarComponentConfigDependencyResolver } from "./filter-bar-component-config-dependency-resolver"; import { DrawerComponentConfigDependencyResolver } from "./drawer-component-config-dependency-resolver"; import { CalendarComponentConfigDependencyResolver } from "./calendar-component-config-dependency-resolver"; +import { ButtonComponentConfigDependencyResolver } from "./button-component-config-dependency-resolver"; export const componentConfigDependencyResolverProviders: StaticProvider[] = [ @@ -34,6 +35,7 @@ export const componentConfigDependencyResolverProviders: StaticProvider[] = [ { provide: COMPONENT_CONFIG_DEPENDENCY_RESOLVER_TOKEN, useClass: FilterBarComponentConfigDependencyResolver, deps: [ConfigDependencyResolveService], multi: true}, { provide: COMPONENT_CONFIG_DEPENDENCY_RESOLVER_TOKEN, useClass: DrawerComponentConfigDependencyResolver, deps: [ConfigDependencyResolveService], multi: true}, { provide: COMPONENT_CONFIG_DEPENDENCY_RESOLVER_TOKEN, useClass: CalendarComponentConfigDependencyResolver, deps: [ConfigDependencyResolveService], multi: true}, + { provide: COMPONENT_CONFIG_DEPENDENCY_RESOLVER_TOKEN, useClass: ButtonComponentConfigDependencyResolver, deps: [ConfigDependencyResolveService], multi: true}, { provide: ComponentConfigDependencyResolverRegistry, useClass: ComponentConfigDependencyResolverRegistry, deps: [Injector] }, { provide: ComponentConfigDependencyResolveService, useClass: ComponentConfigDependencyResolveService, deps: [ComponentConfigDependencyResolverRegistry] } ]; diff --git a/packages/renderer/src/component-config-resolver/button-component-config-resolver.ts b/packages/renderer/src/component-config-resolver/button-component-config-resolver.ts new file mode 100644 index 0000000000..c15168fa0c --- /dev/null +++ b/packages/renderer/src/component-config-resolver/button-component-config-resolver.ts @@ -0,0 +1,28 @@ +import { ComponentConfigResolver } from "./component-config-resolver"; +import { ConfigResolver } from "../config"; +import { isNil } from "lodash-es"; +import { GlobalTranslate } from "../i18n"; + +export class ButtonComponentConfigResolver extends ComponentConfigResolver { + public type: string = 'button'; + + constructor( + private configResolver: ConfigResolver, + private translate: GlobalTranslate, + private formMetadataId: string + ) { + super(); + } + + public resolve(metadata: Record): Record { + const { visible, disabled, id} = metadata; + if (!isNil(visible)) { + metadata.visible = this.configResolver.resolve(visible, id); + } + if (!isNil(disabled)) { + metadata.disabled = this.configResolver.resolve(disabled, id); + } + + return metadata; + } +} diff --git a/packages/renderer/src/component-config-resolver/index.ts b/packages/renderer/src/component-config-resolver/index.ts index 10dac49f78..c550c304fa 100644 --- a/packages/renderer/src/component-config-resolver/index.ts +++ b/packages/renderer/src/component-config-resolver/index.ts @@ -16,4 +16,5 @@ export * from './list-view-component-config-resolver'; export * from './filter-bar-component-config-resolver'; export * from './drawer-component-config-resolver'; export * from './calendar-component-config-resolver'; +export * from './button-component-config-resolver'; export * from './providers'; diff --git a/packages/renderer/src/component-config-resolver/providers.ts b/packages/renderer/src/component-config-resolver/providers.ts index 24150203e7..116d73b0d5 100644 --- a/packages/renderer/src/component-config-resolver/providers.ts +++ b/packages/renderer/src/component-config-resolver/providers.ts @@ -21,6 +21,7 @@ import { ListViewComponentConfigResolver } from "./list-view-component-config-re import { FilterBarComponentConfigResolver } from "./filter-bar-component-config-resolver"; import { DrawerComponentConfigResolver } from "./drawer-component-config-resolver"; import { CalendarComponentConfigResolver } from "./calendar-component-config-resolver"; +import { ButtonComponentConfigResolver } from "./button-component-config-resolver"; export const componentConfigResolverProviders: StaticProvider[] = [ { provide: COMPONENT_CONFIG_RESOLVER_TOKEN, useClass: FormGroupComponentConfigResolver, deps: [FormMetadataService, ConfigResolver, LanguageListManager, GlobalTranslate, FORM_METADATA_ID_TOKEN], multi: true }, @@ -38,6 +39,7 @@ export const componentConfigResolverProviders: StaticProvider[] = [ { provide: COMPONENT_CONFIG_RESOLVER_TOKEN, useClass: FilterBarComponentConfigResolver, deps: [ConfigResolver, GlobalTranslate, FORM_METADATA_ID_TOKEN], multi: true }, { provide: COMPONENT_CONFIG_RESOLVER_TOKEN, useClass: DrawerComponentConfigResolver, deps: [FormMetadataService, ConfigResolver, GlobalTranslate, FORM_METADATA_ID_TOKEN], multi: true }, { provide: COMPONENT_CONFIG_RESOLVER_TOKEN, useClass: CalendarComponentConfigResolver, deps: [FormMetadataService, ConfigResolver, LanguageListManager, GlobalTranslate, FORM_METADATA_ID_TOKEN], multi: true }, + { provide: COMPONENT_CONFIG_RESOLVER_TOKEN, useClass: ButtonComponentConfigResolver, deps: [ConfigResolver, GlobalTranslate, FORM_METADATA_ID_TOKEN], multi: true }, { provide: ComponentConfigResolverRegistry, useClass: ComponentConfigResolverRegistry, deps: [Injector] }, { provide: ComponentConfigResolveService, useClass: ComponentConfigResolveService, deps: [ComponentConfigResolverRegistry, FormMetadataService] } ]; -- Gitee