From c9d90f40c814308f00d53724eebdae06c877473e Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 25 Feb 2025 11:04:41 +0800 Subject: [PATCH 01/34] =?UTF-8?q?feature:=E6=8F=90=E4=BE=9B=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E8=AE=BE=E8=AE=A1=E6=97=B6=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mobile-ui-vue/components/button/index.ts | 10 ++ .../src/designer/button.design.component.tsx | 57 +++++++ .../button/src/designer/use-designer-rules.ts | 57 +++++++ .../property-config/button.property-config.ts | 51 ++++++ .../button/src/schema/button.schema.json | 19 ++- .../mobile-ui-vue/components/common/index.ts | 1 + .../common/src/entity/input-base-property.ts | 15 +- .../components/component/index.ts | 10 ++ .../designer/component.design.component.tsx | 41 +++++ .../src/designer/use-designer-rules.ts | 123 ++++++++++++++ .../component.property-config.ts | 63 ++++++++ .../components/content-container/index.ts | 10 ++ .../content-container.design.component.tsx | 38 +++++ .../src/designer/use-designer-rules.ts | 50 ++++++ .../content-container.property-config.ts | 15 ++ .../components/date-picker-input/index.ts | 14 ++ .../src/date-picker-input.props.ts | 8 +- .../designer/date-picker.design.component.tsx | 54 +++++++ .../src/designer/use-designer-rules.ts | 15 ++ .../date-picker.property-config.ts | 74 +++++++++ .../src/schema/schema-mapper.ts | 5 + .../src/schema/schema-resolver.ts | 5 + .../date-picker-input/src/schema/schema.json | 72 +++++++++ .../designer-canvas/src/components/maps.ts | 46 ++++-- .../src/composition/dg-control.ts | 71 +++----- .../src/composition/function/drag-resolve.tsx | 12 +- .../src/composition/function/use-dragula.ts | 6 +- .../designer-canvas/src/composition/types.ts | 6 +- .../src/designer-canvas.component.tsx | 17 +- .../components/designer-toolbox/index.ts | 5 + .../src/toolbox.component.tsx | 153 ++++++++++++++++++ .../designer-toolbox/src/toolbox.css | 75 +++++++++ .../designer-toolbox/src/toolbox.json | 110 +++++++++++++ .../designer-toolbox/src/toolbox.props.ts | 10 ++ .../components/designer-toolbox/src/types.ts | 22 +++ packages/mobile-ui-vue/components/designer.ts | 4 +- .../components/float-container/index.ts | 10 ++ .../float-container.design.component.tsx | 31 ++++ .../src/designer/use-designer-rules.ts | 99 ++++++++++++ .../float-container.property-config.ts | 15 ++ .../components/form-item/index.ts | 9 ++ .../designer/form-item-use-designer-rules.ts | 85 ++++++++++ .../designer/form-item.design.component.tsx | 137 ++++++++++++++++ .../response-form-use-designer-rules.ts | 103 ++++++++++++ .../response-form.design.component.tsx | 46 ++++++ .../form-item/src/form-item.props.ts | 4 +- .../form-group.property-config.ts | 16 ++ .../response-form.property-config.ts | 16 ++ .../mobile-ui-vue/components/form/index.ts | 9 ++ .../components/input-group/index.ts | 10 ++ .../designer/input-group.design.component.tsx | 50 ++++++ .../src/designer/use-designer-rules.ts | 15 ++ .../input-group.property-config.ts | 34 ++++ .../src/schema/input-group.schema.json | 36 ++++- .../components/list-view/index.ts | 32 ++-- .../designer/list-view.design.component.tsx | 40 ++++- .../src/designer/use-designer-rules.ts | 26 ++- .../component.property-config.ts | 51 ++++++ .../list-view.property-config.json | 6 +- .../mobile-ui-vue/components/modal/index.ts | 4 +- .../mobile-ui-vue/components/navbar/index.ts | 6 + .../src/designer/nav.design.component.tsx | 51 ++++++ .../navbar/src/designer/use-designer-rules.ts | 63 ++++++++ .../property-config/navbar.property-config.ts | 31 ++++ .../components/page-body-container/index.ts | 7 +- .../page-body-container.design.component.tsx | 8 +- .../src/designer/use-designer-rules.ts | 26 ++- .../src/page-body-container.props.ts | 4 +- .../page-body-container.property-config.json | 52 ------ .../page-body-container.property-config.ts | 15 ++ .../components/page-container/index.ts | 7 +- .../page-container.design.component.tsx | 8 +- .../src/designer/use-designer-rules.ts | 36 +++-- .../src/page-container.props.ts | 4 +- .../page-container.property-config.json | 52 ------ .../page-container.property-config.ts | 15 ++ .../components/page-footer-container/index.ts | 7 +- ...page-footer-container.design.component.tsx | 8 +- .../src/designer/use-designer-rules.ts | 24 ++- .../src/page-footer-container.props.ts | 4 +- ...page-footer-container.property-config.json | 52 ------ .../page-footer-container.property-config.ts | 15 ++ .../components/page-header-container/index.ts | 7 +- ...page-header-container.design.component.tsx | 8 +- .../src/designer/use-designer-rules.ts | 30 ++-- .../src/page-header-container.props.ts | 4 +- ...page-header-container.property-config.json | 52 ------ .../page-header-container.property-config.ts | 15 ++ .../components/radio-group/index.ts | 14 ++ .../designer/radio-group.design.component.tsx | 63 ++++++++ .../src/designer/use-designer-rules.ts | 15 ++ .../radio-group.property-config.ts | 53 ++++++ .../radio-group/src/radio-group.props.ts | 8 +- .../src/schema/radio-group.schema.json | 85 ++++++++++ .../radio-group/src/schema/schema-mapper.ts | 5 + .../radio-group/src/schema/schema-resolver.ts | 5 + .../components/textarea/index.ts | 14 ++ .../designer/textarea.design.component.tsx | 51 ++++++ .../src/designer/use-designer-rules.ts | 20 +++ .../textarea.property-config.ts | 34 ++++ .../textarea/src/schema/input.schema.json | 75 +++++++++ .../textarea/src/schema/schema-mapper.ts | 5 + .../textarea/src/schema/schema-resolver.ts | 5 + .../components/textarea/src/textarea.props.ts | 8 +- 104 files changed, 2879 insertions(+), 420 deletions(-) create mode 100644 packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/button/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts create mode 100644 packages/mobile-ui-vue/components/component/src/designer/component.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/component/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/component/src/property-config/component.property-config.ts create mode 100644 packages/mobile-ui-vue/components/content-container/src/designer/content-container.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/content-container/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/content-container/src/property-config/content-container.property-config.ts create mode 100644 packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/date-picker-input/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts create mode 100644 packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts create mode 100644 packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-resolver.ts create mode 100644 packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json create mode 100644 packages/mobile-ui-vue/components/designer-toolbox/index.ts create mode 100644 packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.component.tsx create mode 100644 packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.css create mode 100644 packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json create mode 100644 packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.props.ts create mode 100644 packages/mobile-ui-vue/components/designer-toolbox/src/types.ts create mode 100644 packages/mobile-ui-vue/components/float-container/src/designer/float-container.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/float-container/src/property-config/float-container.property-config.ts create mode 100644 packages/mobile-ui-vue/components/form-item/src/designer/form-item-use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/form-item/src/designer/form-item.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/form-item/src/designer/response-form-use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/form-item/src/designer/response-form.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/form-item/src/property-config/form-group.property-config.ts create mode 100644 packages/mobile-ui-vue/components/form-item/src/property-config/response-form.property-config.ts create mode 100644 packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/input-group/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/input-group/src/property-config/input-group.property-config.ts create mode 100644 packages/mobile-ui-vue/components/list-view/src/property-config/component.property-config.ts create mode 100644 packages/mobile-ui-vue/components/navbar/src/designer/nav.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/navbar/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts delete mode 100644 packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.json create mode 100644 packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.ts delete mode 100644 packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.json create mode 100644 packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.ts delete mode 100644 packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.json create mode 100644 packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.ts delete mode 100644 packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.json create mode 100644 packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.ts create mode 100644 packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/radio-group/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts create mode 100644 packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json create mode 100644 packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts create mode 100644 packages/mobile-ui-vue/components/radio-group/src/schema/schema-resolver.ts create mode 100644 packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/textarea/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts create mode 100644 packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json create mode 100644 packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts create mode 100644 packages/mobile-ui-vue/components/textarea/src/schema/schema-resolver.ts diff --git a/packages/mobile-ui-vue/components/button/index.ts b/packages/mobile-ui-vue/components/button/index.ts index f211334c44a..2c5790ae860 100644 --- a/packages/mobile-ui-vue/components/button/index.ts +++ b/packages/mobile-ui-vue/components/button/index.ts @@ -2,6 +2,7 @@ import { Plugin } from 'vue'; import { withInstall, } from '@components/common'; import ButtonInstallless from './src/button.component'; import { propsResolver } from './src/button.props'; +import ButtonDesign from './src/designer/button.design.component'; const BUTTON_REGISTERED_NAME = 'button'; @@ -14,5 +15,14 @@ Button.register = ( propsResolverMap[BUTTON_REGISTERED_NAME] = propsResolver; }; +Button.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[BUTTON_REGISTERED_NAME] = ButtonDesign; + propsResolverMap[BUTTON_REGISTERED_NAME] = propsResolver; +}; + + export { Button }; export default Button as typeof Button & Plugin; diff --git a/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx b/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx new file mode 100644 index 00000000000..88fa36811c4 --- /dev/null +++ b/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx @@ -0,0 +1,57 @@ +/** + * 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 { computed, defineComponent, inject, onMounted, ref, SetupContext } from 'vue'; +import { ButtonProps, buttonProps } from '../button.props'; +import Button from '../..'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; +import { useDesignerRules } from './use-designer-rules'; + +export default defineComponent({ + name: 'FmButtonDesign', + props: buttonProps, + emits: ['click'], + setup(props: ButtonProps, context: SetupContext) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + context.expose(componentInstance.value); + + const schema = componentInstance.value.schema; + + const inputProps = computed(() => ({ + ...props, + })); + + return () => { + return ( + schema.text ? + + : + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/button/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/button/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..57b56ec4c0d --- /dev/null +++ b/packages/mobile-ui-vue/components/button/src/designer/use-designer-rules.ts @@ -0,0 +1,57 @@ +import { ref } from "vue"; +import { ButtonProperty } from "../property-config/button.property-config"; +import { DesignerHostService, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; + +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { + + const triggerBelongedComponentToMoveWhenMoved = ref(false); + + const triggerBelongedComponentToDeleteWhenDeleted = ref(false); + + function canAccepts(draggingContext: DraggingResolveContext): boolean { + + return false; + } + + + function checkCanMoveComponent() { + return true; + } + function checkCanDeleteComponent() { + return true; + } + + function hideNestedPaddingInDesginerView() { + return true; + } + + function getStyles(): string { + return ' '; + } + + function getDesignerClass(): string { + return ' '; + } + + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new ButtonProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + return { + canAccepts, + triggerBelongedComponentToMoveWhenMoved, + triggerBelongedComponentToDeleteWhenDeleted, + checkCanMoveComponent, + checkCanDeleteComponent, + hideNestedPaddingInDesginerView, + getStyles, + getDesignerClass, + getPropsConfig + }; +} diff --git a/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts b/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts new file mode 100644 index 00000000000..797c3b7aae6 --- /dev/null +++ b/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts @@ -0,0 +1,51 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class ButtonProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + //行为 + this.propertyConfig.categories['behavior'] = this.getBehaviorConfig(propertyData); + + return this.propertyConfig; + } + + private getBehaviorConfig(propertyData) { + return { + description: "基本信息", + title: "行为", + properties: { + visible: { + title: "可见", + type: "boolean", + }, + disabled: { + title: "只读", + type: "boolean", + }, + displayType: { + title: "按钮类型", + type: "string", + }, + block: { + title: "是否占满整行", + type: "boolean", + }, + round: { + title: "启用圆角", + type: "boolean", + }, + text: { + title: "提示文本", + type: "string", + } + } + }; + } + +} diff --git a/packages/mobile-ui-vue/components/button/src/schema/button.schema.json b/packages/mobile-ui-vue/components/button/src/schema/button.schema.json index 3109eabb1fb..c97693e7758 100644 --- a/packages/mobile-ui-vue/components/button/src/schema/button.schema.json +++ b/packages/mobile-ui-vue/components/button/src/schema/button.schema.json @@ -17,7 +17,7 @@ "displayType": { "description": "显示类型", "type": "string", - "default": "default" + "default": "primary" }, "icon": { "description": "图标", @@ -30,6 +30,16 @@ "default": false, "isEvent": true }, + "text": { + "description": "", + "type": "string", + "default": "按钮" + }, + "block": { + "description": "", + "type": "boolean", + "default": true + }, "appearance": { "description": "外观", "type": "object", @@ -52,6 +62,11 @@ ], "required": [ "id", - "type" + "type", + "visible", + "round", + "disabled", + "text", + "icon" ] } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/common/index.ts b/packages/mobile-ui-vue/components/common/index.ts index 279f22b74ef..b3b9463aea1 100644 --- a/packages/mobile-ui-vue/components/common/index.ts +++ b/packages/mobile-ui-vue/components/common/index.ts @@ -20,6 +20,7 @@ export * from './utils/resolve-field'; export * from './utils/use-guid'; export * from './entity/entity-schema'; export * from './src/utils'; +export const FM_UI_PROVIDER_SERVICE_TOKEN = Symbol('UIProviderService'); export default { install(app: App): void { diff --git a/packages/mobile-ui-vue/components/common/src/entity/input-base-property.ts b/packages/mobile-ui-vue/components/common/src/entity/input-base-property.ts index fb43a637e9a..e705e141bab 100644 --- a/packages/mobile-ui-vue/components/common/src/entity/input-base-property.ts +++ b/packages/mobile-ui-vue/components/common/src/entity/input-base-property.ts @@ -218,15 +218,18 @@ export class InputBaseProperty extends BaseControlProperty { type: "boolean", visible: false }, - // required: { - // description: "", - // title: "必填", - // type: "boolean" - // }, + required: { + description: "", + title: "必填", + type: "boolean", + visible: false + }, placeholder: { description: "空值时,输入控件内的占位文本", title: "提示文本", - type: "string" + type: "string", + visible: false + } }, properties); diff --git a/packages/mobile-ui-vue/components/component/index.ts b/packages/mobile-ui-vue/components/component/index.ts index cba22460cb6..bed6e3bd70c 100644 --- a/packages/mobile-ui-vue/components/component/index.ts +++ b/packages/mobile-ui-vue/components/component/index.ts @@ -18,6 +18,7 @@ import type { Plugin } from 'vue'; import { withInstall } from '@components/common'; import ComponentInstallless from './src/component.component'; import { propsResolver } from './src/component.props'; +import ComponentDesign from './src/designer/component.design.component'; const COMPONENT_REGISTERED_NAME = 'component'; @@ -30,6 +31,15 @@ Component.register = ( propsResolverMap[COMPONENT_REGISTERED_NAME] = propsResolver; }; +Component.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[COMPONENT_REGISTERED_NAME] = ComponentDesign; + propsResolverMap[COMPONENT_REGISTERED_NAME] = propsResolver; +}; + + export * from './src/component.props'; export { Component }; export default Component as typeof Component & Plugin; diff --git a/packages/mobile-ui-vue/components/component/src/designer/component.design.component.tsx b/packages/mobile-ui-vue/components/component/src/designer/component.design.component.tsx new file mode 100644 index 00000000000..06b97e5ff2a --- /dev/null +++ b/packages/mobile-ui-vue/components/component/src/designer/component.design.component.tsx @@ -0,0 +1,41 @@ +import { SetupContext, defineComponent, inject, ref, onMounted, computed } from 'vue'; +import { ComponentPropsType, componentProps } from '../component.props'; +import { useDesignerRules } from './use-designer-rules'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas'; + +export default defineComponent({ + name: 'FComponetDesign', + props: componentProps, + emits: [], + setup(props: ComponentPropsType, context) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + const componentClass = computed(() => { + const classObject = { + 'drag-container': true + } as Record; + return classObject; + }); + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + + if (designItemContext.parent?.schema?.type === 'component-ref') { + componentInstance.value.parent = designItemContext.parent?.parent?.componentInstance; + } + }); + + context.expose(componentInstance.value); + + return () => { + return ( +
+ {context.slots.default && context.slots.default()} +
+ ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/component/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/component/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..4759823a140 --- /dev/null +++ b/packages/mobile-ui-vue/components/component/src/designer/use-designer-rules.ts @@ -0,0 +1,123 @@ +import { DesignerHostService, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { ComponentProperty } from "../property-config/component.property-config"; + +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { + + /** + * 判断是否可以接收拖拽新增的子级控件 + */ + function canAccepts(): boolean { + return true; + } + + function checkCanDeleteComponent() { + return false; + } + + function checkCanMoveComponent() { + return true; + } + + + function hideNestedPaddingInDesginerView() { + return false; + } + + function getStyles(): string { + return ' '; + } + + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new ComponentProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + /** + * 删除DataGrid/Form类组件时,将父级Section或者TabPage上的相关按钮一起删除 + */ + function removeAddDeleteBtnOnParentContainer() { + const schema = designItemContext?.schema; + const formSchemaUtils = designerHostService?.formSchemaUtils; + const viewModelId = formSchemaUtils.getViewModelIdByComponentId(schema.id); + + if (schema.componentType !== 'form') { + return; + } + if (!designItemContext.componentInstance?.value.parent) { + return; + } + const parentComponentSchema = designItemContext.componentInstance?.value.parent['schema']; + if (parentComponentSchema?.toolbar?.buttons && parentComponentSchema.toolbar.buttons.length) { + parentComponentSchema.toolbar.buttons.forEach(button => { + const clickEvent = button.onClick; + // 判断三段式结构 + const clickEventPath = clickEvent && clickEvent.split('.'); + if (!clickEventPath || clickEventPath.length < 3) { + return; + } + const targetViewModelId = clickEventPath[clickEventPath.length - 2]; + + // 按钮绑定的命令若是在当前viewModel下,则将按钮标记为待删除 + if (targetViewModelId === viewModelId) { + button.needRemove = true; + } + }); + parentComponentSchema.toolbar.buttons = parentComponentSchema.toolbar.buttons.filter(button => !button.needRemove); + + // 为解决标签页画布无法更新的问题,手动触发update方法 + const parentComponentInstance = designItemContext.componentInstance?.value.parent; + if (parentComponentInstance['parent'] && parentComponentInstance['parent']['updateToolbarItems']) { + parentComponentInstance['parent']['updateToolbarItems'](); + } + } + + } + /** + * 组件删除后事件:移除viewmodel和component + */ + function removeViewModelComponent() { + const designViewModelUtils = designerHostService?.designViewModelUtils; + const formSchemaUtils = designerHostService?.formSchemaUtils; + const schema = designItemContext?.schema; + + if (designViewModelUtils && formSchemaUtils) { + const viewModelId = formSchemaUtils.getViewModelIdByComponentId(schema.id); + designViewModelUtils.deleteViewModelById(viewModelId); + + formSchemaUtils.deleteComponent(schema.id); + } + } + /** + * 组件删除后事件:移除表达式、界面规则、受控规则等全局配置 + */ + function removeGlobalConfigs() { + const designViewModelUtils = designerHostService?.designViewModelUtils; + const formSchemaUtils = designerHostService?.formSchemaUtils; + const schema = designItemContext?.schema; + const viewModelId = formSchemaUtils.getViewModelIdByComponentId(schema.id); + + designViewModelUtils.getDgViewModel(viewModelId).fields.forEach(field => { + + // 若绑定字段配置了表达式,需要删除表达式 + if (formSchemaUtils.getExpressions() && formSchemaUtils.getExpressions().length) { + const expFieldIndex = formSchemaUtils.getExpressions().findIndex(e => e.fieldId === field.id); + if (expFieldIndex > -1) { + formSchemaUtils.getExpressions().splice(expFieldIndex, 1); + } + } + }); + } + /** + * 组件删除后事件 + */ + function onRemoveComponent() { + removeAddDeleteBtnOnParentContainer(); + removeGlobalConfigs(); + removeViewModelComponent(); + } + return { canAccepts, checkCanDeleteComponent, checkCanMoveComponent, hideNestedPaddingInDesginerView, getStyles, getPropsConfig, onRemoveComponent }; +} diff --git a/packages/mobile-ui-vue/components/component/src/property-config/component.property-config.ts b/packages/mobile-ui-vue/components/component/src/property-config/component.property-config.ts new file mode 100644 index 00000000000..cdf986d57bd --- /dev/null +++ b/packages/mobile-ui-vue/components/component/src/property-config/component.property-config.ts @@ -0,0 +1,63 @@ +import { BaseControlProperty } from "@/components/property-panel"; + + +export class ComponentProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + // 事件 + this.getEventPropConfig(propertyData); + return this.propertyConfig; + } + private getEventPropConfig(propertyData: any) { + const events = [ + { + label: "onBeforeInit", + name: "初始化前事件", + }, + { + label: "onInit", + name: "初始化事件", + }, + { + label: "onLoadData", + name: "加载数据事件", + }, + { + label: "goBack", + name: "原生返回事件", + }, + ]; + const self = this; + const initialData = self.eventsEditorUtils['formProperties'](propertyData, self.viewModelId, events); + const properties = {}; + properties[self.viewModelId] = { + type: 'events-editor', + editor: { + initialData + } + }; + this.propertyConfig.categories['eventsEditor'] = { + title: '事件', + hideTitle: true, + properties, + // 这个属性,标记当属性变更得时候触发重新更新属性 + refreshPanelAfterChanged: true, + tabId: 'commands', + tabName: '交互', + setPropertyRelates(changeObject: any, data: any) { + const parameters = changeObject.propertyValue; + delete propertyData[self.viewModelId]; + if (parameters) { + parameters.setPropertyRelates = this.setPropertyRelates; // 添加自定义方法后,调用此回调方法,用于处理联动属性 + self.eventsEditorUtils.saveRelatedParameters(propertyData, self.viewModelId, parameters['events'], parameters); + } + } + }; + } +} diff --git a/packages/mobile-ui-vue/components/content-container/index.ts b/packages/mobile-ui-vue/components/content-container/index.ts index c1fbc4d9104..c14dc398ca2 100644 --- a/packages/mobile-ui-vue/components/content-container/index.ts +++ b/packages/mobile-ui-vue/components/content-container/index.ts @@ -1,6 +1,7 @@ import { App, Plugin } from 'vue'; import FContentContainer from './src/content-container.component'; import { propsResolver } from './src/content-container.props'; +import ContentContainerDesign from './src/designer/content-container.design.component'; const CONTENT_CONTAINER_REGISTERED_NAME = 'content-container'; @@ -16,6 +17,15 @@ FContentContainer.register = ( propsResolverMap[CONTENT_CONTAINER_REGISTERED_NAME] = propsResolver; }; +FContentContainer.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[CONTENT_CONTAINER_REGISTERED_NAME] = ContentContainerDesign; + propsResolverMap[CONTENT_CONTAINER_REGISTERED_NAME] = propsResolver; +}; + + export * from './src/content-container.props'; export { FContentContainer }; export default FContentContainer as typeof FContentContainer & Plugin; diff --git a/packages/mobile-ui-vue/components/content-container/src/designer/content-container.design.component.tsx b/packages/mobile-ui-vue/components/content-container/src/designer/content-container.design.component.tsx new file mode 100644 index 00000000000..2ec2f1037db --- /dev/null +++ b/packages/mobile-ui-vue/components/content-container/src/designer/content-container.design.component.tsx @@ -0,0 +1,38 @@ +import { SetupContext, computed, defineComponent, inject, onMounted, ref } from 'vue'; +import { ContentContainerPropsType, contentContainerProps } from '../content-container.props'; +import { useDesignerRulesForContentContainer } from './use-designer-rules'; +import { getCustomClass } from '@/components/common'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; + +export default defineComponent({ + name: 'FContentContainerDesign', + props: contentContainerProps, + emits: [], + setup(props: ContentContainerPropsType, context) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useDesignerRulesForContentContainer(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + const containerClass = computed(() => { + const classObject = { + 'drag-container': true + } as Record; + return getCustomClass(classObject, props?.customClass); + }); + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + context.expose(componentInstance.value); + + return () => { + return ( +
+ {context.slots.default && context.slots.default()} +
+ ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/content-container/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/content-container/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..5164c6e8101 --- /dev/null +++ b/packages/mobile-ui-vue/components/content-container/src/designer/use-designer-rules.ts @@ -0,0 +1,50 @@ +import { ComponentSchema, DesignerItemContext } from "@/components/designer-canvas"; +import { ContentContainerProperty } from "../property-config/content-container.property-config"; +import { DesignerHostService, DraggingResolveContext, UseDesignerRules } from "@/components/designer-canvas/src/composition/types"; + +export function useDesignerRulesForContentContainer(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { + const schema = designItemContext.schema as ComponentSchema; + + /** + * 判断是否可以接收拖拽新增的子级控件 + */ + function canAccepts(draggingContext: DraggingResolveContext): boolean { + return true; + } + + function getStyles() { + const component = schema; + if (component.componentType) { + return 'display:inherit;flex-direction:inherit;margin-bottom:10px'; + } + return ''; + } + + function checkCanMoveComponent() { + return true; + } + function checkCanDeleteComponent() { + return true; + } + + function hideNestedPaddingInDesginerView() { + return false; + } + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new ContentContainerProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + return { + canAccepts, + getStyles, + checkCanMoveComponent, + checkCanDeleteComponent, + hideNestedPaddingInDesginerView, + getPropsConfig + }; +} diff --git a/packages/mobile-ui-vue/components/content-container/src/property-config/content-container.property-config.ts b/packages/mobile-ui-vue/components/content-container/src/property-config/content-container.property-config.ts new file mode 100644 index 00000000000..8db40b24dd1 --- /dev/null +++ b/packages/mobile-ui-vue/components/content-container/src/property-config/content-container.property-config.ts @@ -0,0 +1,15 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class ContentContainerProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/date-picker-input/index.ts b/packages/mobile-ui-vue/components/date-picker-input/index.ts index ded2df85a66..ec026ee8f75 100644 --- a/packages/mobile-ui-vue/components/date-picker-input/index.ts +++ b/packages/mobile-ui-vue/components/date-picker-input/index.ts @@ -1,7 +1,21 @@ import { withInstall } from '@components/common'; import DatePickerInputInstallless from './src/date-picker-input.component'; +import DatePickerDesign from './src/designer/date-picker.design.component'; +import { propsResolver } from './src/date-picker-input.props'; + +const DATE_PICKER_REGISTERED_NAME = 'date-picker'; const DatePickerInput = withInstall(DatePickerInputInstallless); +DatePickerInput.register = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record) => { + componentMap[DATE_PICKER_REGISTERED_NAME] = DatePickerInput; + propsResolverMap[DATE_PICKER_REGISTERED_NAME] = propsResolver; +}; +DatePickerInput.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record) => { + componentMap[DATE_PICKER_REGISTERED_NAME] = DatePickerDesign; + propsResolverMap[DATE_PICKER_REGISTERED_NAME] = propsResolver; +}; + + export { DatePickerInput }; export default DatePickerInput; diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/date-picker-input.props.ts b/packages/mobile-ui-vue/components/date-picker-input/src/date-picker-input.props.ts index 7871244aa93..cce31ab4471 100644 --- a/packages/mobile-ui-vue/components/date-picker-input/src/date-picker-input.props.ts +++ b/packages/mobile-ui-vue/components/date-picker-input/src/date-picker-input.props.ts @@ -1,6 +1,10 @@ import { ExtractPropTypes } from 'vue'; import { buttonEditProps } from '@/components/button-edit'; import { datePickerProps } from '@/components/date-picker'; +import { schemaMapper } from './schema/schema-mapper'; +import { schemaResolver } from './schema/schema-resolver'; +import inputSchema from './schema/schema.json'; +import { createPropsResolver } from '@/components/dynamic-resolver'; export const DATA_PICKER_INPUT_NAME = 'FmDatePickerInput'; @@ -9,6 +13,8 @@ export const datePickerInputProps = { ...datePickerProps, round: { type: Boolean, default: false } -}; +} as Record; export type DatePickerInputProps = ExtractPropTypes; + +export const propsResolver = createPropsResolver(datePickerInputProps, inputSchema, schemaMapper, schemaResolver); diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx b/packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx new file mode 100644 index 00000000000..a0aa71bb439 --- /dev/null +++ b/packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx @@ -0,0 +1,54 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; + +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; +import { useDesignerRules } from './use-designer-rules'; +import { datePickerInputProps, DatePickerInputProps } from '../date-picker-input.props'; +import DatePickerInput from '../..'; + +export default defineComponent({ + name: 'FmDatePickerInputDesign', + props: datePickerInputProps, + emits: [], + setup(props: DatePickerInputProps, context: SetupContext) { + const elementRef = ref(); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerHostService = inject('designer-host-service'); + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext,designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + context.expose(componentInstance.value); + + const inputProps = computed(() => ({ + ...props, + editable: false, + readonly: true + + })); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/date-picker-input/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..27cf298004d --- /dev/null +++ b/packages/mobile-ui-vue/components/date-picker-input/src/designer/use-designer-rules.ts @@ -0,0 +1,15 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DatePickerProperty } from "../property-config/date-picker.property-config"; +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const datePickerProps = new DatePickerProperty(componentId, designerHostService); + return datePickerProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts new file mode 100644 index 00000000000..c0551502470 --- /dev/null +++ b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts @@ -0,0 +1,74 @@ +import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; + +export class DatePickerProperty extends InputBaseProperty { + + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + + getEditorProperties(propertyData: any) { + const displayFormatOptions = this.getAllShowType(); + const valueFormatOptions = this.getAllFormat(); + return this.getComponentConfig(propertyData, { type: "year-month-day" }, { + placeholder: { + description: "空值时,输入控件内的占位文本", + title: "提示文本", + type: "string" + }, + showType: { + description: "", + title: "选择类型", + type: "enum", + editor: { + data: displayFormatOptions + } + }, + format: { + description: "", + title: "显示格式", + type: "enum", + editor: { + data: valueFormatOptions + } + } + }, this.setEditorPropertyRelates); + } + + private setEditorPropertyRelates(changeObject: any, propertyData: any) { + if (!changeObject || !propertyData.editor) { + return; + } + switch (changeObject.propertyID) { + case 'showTime': { + + } + } + } + + private getAllShowType() { + return [ + { id: "year", name: "年月日" }, + { id: "datetime", name: "年月日时分" }, + { id: "datehour", name: "年月日时" }, + { id: "year-month", name: "年月" }, + { id: "month-day", name: "月日" } + ]; + } + + /** + * 存储格式枚举项 + */ + getAllFormat(): any[] { + return [ + { id: 'YYYY-MM-dd HH:mm', name: 'YYYY-MM-dd HH:mm' }, + { id: 'MM/dd/YYYY HH:mm', name: 'MM/dd/YYYY HH:mm' }, + { id: 'YYYY年MM月dd日 HH:mm', name: 'YYYY年MM月dd日 HH:mm' }, + { id: 'YYYY-MM-dd HH:mm:ss', name: 'YYYY-MM-dd HH:mm:ss' }, + { id: 'MM/dd/YYYY HH:mm:ss', name: 'MM/dd/YYYY HH:mm:ss' }, + { id: 'YYYY年MM月dd日 HH:mm:ss', name: 'YYYY年MM月dd日 HH:mm:ss' }, + ]; + } + + +} diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts new file mode 100644 index 00000000000..abb57152ea8 --- /dev/null +++ b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts @@ -0,0 +1,5 @@ +import { MapperFunction, resolveAppearance } from '@/components/dynamic-resolver'; + +export const schemaMapper = new Map([ + ['appearance', resolveAppearance] +]); diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-resolver.ts b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-resolver.ts new file mode 100644 index 00000000000..660e1e609e1 --- /dev/null +++ b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-resolver.ts @@ -0,0 +1,5 @@ +import { DynamicResolver } from "@/components/dynamic-resolver"; + +export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record): Record { + return schema; +} diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json new file mode 100644 index 00000000000..a98542bf4ee --- /dev/null +++ b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/date-picker.schema.json", + "title": "date-picker", + "description": "A Farris Input Component", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a Date Picker", + "type": "string" + }, + "type": { + "description": "The type string of Date Picker component", + "type": "string", + "default": "date-picker" + }, + "appearance": { + "description": "", + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "default": {} + }, + "binding": { + "description": "", + "type": "object", + "default": {} + }, + "disable": { + "type": "string", + "default": false + }, + "title": { + "description": "", + "type": "string", + "default": "" + }, + "label": { + "description": "", + "type": "string", + "default": "" + }, + "lableWidth": { + "description": "", + "type": "number" + }, + "placeholder": { + "description": "", + "type": "string", + "default": "" + }, + "visible": { + "description": "", + "type": "boolean", + "default": true + } + }, + "required": [ + "id", + "type", + "visible", + "label", + "placeholder", + "appearance" + ] +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts b/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts index 1a5e6de142d..474da277cb0 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts +++ b/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts @@ -1,4 +1,15 @@ - +import { ContentContainer, DatePickerInput, FormItem, PageHeaderContainer, RadioGroup } from "@/components"; +import Button from "@/components/button"; +import Component from "@/components/component"; +import FloatContainer from "@/components/float-container"; +import Form from "@/components/form"; +import InputGroup from "@/components/input-group"; +import { ListView } from "@/components/list-view"; +import Navbar from "@/components/navbar"; +import PageBodyContainer from "@/components/page-body-container"; +import PageContainer from "@/components/page-container"; +import PageFooterContainer from "@/components/page-footer-container"; +import Textarea from "@/components/textarea"; const componentMap: Record = {}; const componentPropsConverter: Record = {}; @@ -12,21 +23,24 @@ let hasLoaded = false; function loadDesignerRegister() { if (!hasLoaded) { hasLoaded = true; - // FAvatar.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); - - } -} -/** - * 加载设计时组件 - */ -function loadDesignerRegisterByComponents(components:any[]) { - if (!hasLoaded) { - hasLoaded = true; - components.forEach(component => { - component.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); - }); - + Button.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + PageContainer.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + PageHeaderContainer.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + PageBodyContainer.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + PageFooterContainer.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + Navbar.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + Component.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + ListView.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + Form.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + InputGroup.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + FloatContainer.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + ContentContainer.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + FormItem.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + DatePickerInput.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + Textarea.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + RadioGroup.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + } } -export { componentMap, componentPropsConverter, componentPropertyConfigConverter, loadDesignerRegister, loadDesignerRegisterByComponents }; +export { componentMap, componentPropsConverter, componentPropertyConfigConverter, loadDesignerRegister }; diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts b/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts index 3e00a135b84..e3d215a7141 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts +++ b/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts @@ -1,12 +1,24 @@ -export const DgControl = { - 'button': { type: 'button', name: '按钮', icon: 'Button' }, - - 'response-toolbar': { type: 'response-toolbar', name: '工具栏', icon: 'ButtonGroup' }, +export const DgControl = { + 'module': { type: 'Module', name: '模块', icon: 'Module' }, - 'response-toolbar-item': { type: 'response-toolbar-item', name: '按钮', icon: 'Button' }, + 'component': { type: 'component', name: '组件', icon: 'Component' }, 'content-container': { type: 'content-container', name: '容器', icon: 'ContentContainer' }, + 'page-container': { type: 'page-container', name: '页面容器', icon: 'ContentContainer' }, + + 'page-header-container': { type: 'page-header-container', name: '页头容器', icon: 'ContentContainer' }, + + 'page-body-container': { type: 'page-body-container', name: '页面主体容器', icon: 'ContentContainer' }, + + 'page-footer-container': { type: 'page-footer-container', name: '页尾容器', icon: 'ContentContainer' }, + + 'float-container': { type: 'float-container', name: '浮动容器', icon: 'ContentContainer' }, + + 'list-view': { type: 'list-view', name: '列表', icon: 'ListView' }, + + 'button': { type: 'button', name: '按钮', icon: 'Button' }, + 'input-group': { type: 'input-group', name: '文本', icon: 'TextBox' }, 'textarea': { type: 'textarea', name: '多行文本', icon: 'MultiTextBox' }, @@ -27,53 +39,8 @@ export const DgControl = { 'combo-list': { type: 'combo-list', name: '下拉列表', icon: 'EnumField' }, - 'response-form': { type: 'response-form', name: '卡片面板', icon: 'Form' }, - - 'response-layout': { type: 'response-layout', name: '布局容器', icon: 'ResponseLayout3' }, - - 'response-layout-item': { type: 'response-layout-item', name: '布局', icon: 'ResponseLayout1' }, - - 'tree-grid': { type: 'tree-grid', name: '树表格', icon: 'TreeGrid' }, - - 'tree-grid-column': { type: 'tree-grid-column', name: '树表格列' }, - - 'data-grid': { type: 'data-grid', name: '表格', icon: 'DataGrid' }, - - 'data-grid-column': { type: 'data-grid-column', name: '表格列' }, - - 'module': { type: 'Module', name: '模块', icon: 'Module' }, - - 'component': { type: 'component', name: '组件', icon: 'Component' }, - - 'tabs': { type: 'tabs', name: '标签页', icon: 'Tab' }, - - 'tab-page': { type: 'tab-page', name: '标签页项', dependentParentControl: 'Tab' }, - - 'tab-toolbar-item': { type: 'tab-toolbar-item', name: '标签页工具栏按钮', icon: 'Button' }, - - 'time-picker': { type: 'time-picker', name: '时间选择', icon: 'TimePicker' }, - - 'section': { type: 'section', name: '分组面板', icon: 'Section' }, - - 'section-toolbar': { type: 'section-toolbar', name: '分组面板工具栏' }, - - 'section-toolbar-item': { type: 'section-toolbar-item', name: '分组面板按钮' }, - - 'splitter': { type: 'splitter', name: '分栏面板', icon: 'Splitter' }, - - 'splitter-pane': { type: 'splitter-pane', name: '分栏面板项', dependentParentControl: 'Splitter' }, - - 'component-ref': { type: 'component-ref', name: '组件引用节点' }, - - 'uploader': { type: 'uploader', name: '附件上传', icon: 'FileUpload' }, - - 'page-header': { type: 'page-header', name: '页头', icon: 'Header' }, - - 'page-footer': { type: 'page-footer', name: '页脚', icon: 'ModalFooter' }, - - 'tab-toolbar': { type: 'tab-toolbar', name: '标签页工具栏', icon: 'TabToolbar' }, + 'form': { type: 'form', name: '卡片面板', icon: 'Form' }, - 'fieldset': { type: 'fieldset', name: '分组', icon: 'fieldset' }, + 'navigation-bar': { type: 'navigation-bar', name: '导航栏', icon: 'NavBar' }, - 'query-solution': { type: 'query-solution', name: '筛选方案', icon: 'QueryScheme'} }; diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/drag-resolve.tsx b/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/drag-resolve.tsx index 8bdd337b123..491c53d94b1 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/drag-resolve.tsx +++ b/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/drag-resolve.tsx @@ -1,11 +1,9 @@ import { ModalFunctions } from "../../../../modal/src/composition/type"; import { ComponentBindingSourceContext, DesignerHostService, DesignerHTMLElement, DraggingResolveContext } from "../types"; -// import EntityBindingSelectorComponent from '../../../../entity-binding-selector/entity-binding-selector.component'; -// import { FBindingSelectorContainer as BindingSelectorComponent } from "@/components/binding-selector"; import { DesignViewModelField, FormVariable } from "../../../../common/entity/entity-schema"; import { merge } from "lodash-es"; -import { DesignerComponentInstance } from "../../types"; import { DgControl } from "../dg-control"; +import { DesignerComponentInstance } from "@/components"; export function dragResolveService(designerHostService: DesignerHostService) { /** 弹窗实例 */ @@ -64,7 +62,8 @@ export function dragResolveService(designerHostService: DesignerHostService) { */ function renderEntityComponent() { const { componentType } = componentResolveContext; - // return () => (<> ); + const FEntityBindingSelector = designerHostService.uiProviderService.getUiComponent('FEntityBindingSelector'); + return () => (<> ); } /** * 弹出实体绑定窗口 @@ -153,7 +152,10 @@ export function dragResolveService(designerHostService: DesignerHostService) { componentSchema: { editor: { type: componentResolveContext.componentType } } }; const bindingSettings = { enable: false }; - // return () => (<> ); + + const FBindingSelectorContainer = designerHostService.uiProviderService.getUiComponent('FBindingSelectorContainer'); + + return () => (<> ); } /** * 弹出绑定字段的窗口 diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts b/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts index a7be4974f63..1b8b01052bc 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts +++ b/packages/mobile-ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts @@ -349,6 +349,10 @@ export function useDragula(designerHostService: DesignerHostService): UseDragula } - return { attachComponents, attachToolbox, initializeDragula }; + function getDragulaInstance() { + return dragulaInstance; + } + + return { attachComponents, initializeDragula,getDragulaInstance }; } diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/composition/types.ts b/packages/mobile-ui-vue/components/designer-canvas/src/composition/types.ts index e256c20caa3..a3dc5bbfad2 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/composition/types.ts +++ b/packages/mobile-ui-vue/components/designer-canvas/src/composition/types.ts @@ -12,12 +12,13 @@ export interface DesignerHTMLElement extends HTMLElement { schema: ComponentSchema; } + export interface UseDragula { attachComponents: (element: HTMLElement, component: ComponentSchema) => void; - attachToolbox: () => void; - initializeDragula: (containerElement: DesignerHTMLElement) => void; + + getDragulaInstance: () => any; } export interface DesignerHostService { eventsEditorUtils: any; @@ -27,6 +28,7 @@ export interface DesignerHostService { controlCreatorUtils: any; metadataService?: any; formStateMachineUtils: any; + uiProviderService?: any; [key: string]: any; } /** diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/designer-canvas.component.tsx b/packages/mobile-ui-vue/components/designer-canvas/src/designer-canvas.component.tsx index 569b057e421..5ac3463fd7a 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/designer-canvas.component.tsx +++ b/packages/mobile-ui-vue/components/designer-canvas/src/designer-canvas.component.tsx @@ -8,8 +8,9 @@ import { DesignerHostService, UseDragula } from './composition/types'; import FDesignerItem from './components/designer-item.component'; import './composition/class/designer-canvas.css'; import './composition/class/control.css'; -import { loadDesignerRegister, loadDesignerRegisterByComponents } from './components/maps'; -import { F_MODAL_SERVICE_TOKEN } from '../../modal'; +import { loadDesignerRegister } from './components/maps'; +import { FM_MODAL_SERVICE_TOKEN } from '../../modal'; +import { FM_UI_PROVIDER_SERVICE_TOKEN } from '@/components'; export default defineComponent({ name: 'FDesignerCanvas', @@ -35,17 +36,15 @@ export default defineComponent({ metadataService: inject('Meatdata_Http_Service_Token'), schemaService: inject('schemaService'), useFormCommand: inject('useFormCommand'), - modalService: inject(F_MODAL_SERVICE_TOKEN), - formStateMachineUtils: inject('useFormStateMachine') + modalService: inject(FM_MODAL_SERVICE_TOKEN), + formStateMachineUtils: inject('useFormStateMachine'), + uiProviderService: inject(FM_UI_PROVIDER_SERVICE_TOKEN), + }; provide('designer-host-service', designerHostService); const useDragulaComposition = useDragula(designerHostService); - if(props.components){ - loadDesignerRegisterByComponents(props.components); - }else{ - loadDesignerRegister(); - } + loadDesignerRegister(); provide('canvas-dragula', useDragulaComposition); provide('design-item-context', { diff --git a/packages/mobile-ui-vue/components/designer-toolbox/index.ts b/packages/mobile-ui-vue/components/designer-toolbox/index.ts new file mode 100644 index 00000000000..6616581e20b --- /dev/null +++ b/packages/mobile-ui-vue/components/designer-toolbox/index.ts @@ -0,0 +1,5 @@ +import FDesignerToolbox from './src/toolbox.component'; + +export * from './src/types'; + +export { FDesignerToolbox }; diff --git a/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.component.tsx b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.component.tsx new file mode 100644 index 00000000000..b28fc46df04 --- /dev/null +++ b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.component.tsx @@ -0,0 +1,153 @@ +import { defineComponent, ref, watch } from 'vue'; +import { ToolboxPropsType, toolboxProps } from './toolbox.props'; +import { ToolboxCategory, ToolboxItem } from './types'; + +import toolboxItems from './toolbox.json'; +import './toolbox.css'; + +export default defineComponent({ + name: 'FDesignerToolbox', + props: toolboxProps, + emits: [], + setup(props: ToolboxPropsType) { + const controlCategoryList = props.toolboxItems ? ref(props.toolboxItems as ToolboxCategory[]) : ref(toolboxItems); + const dragularCompostion = ref(props.dragula); + + function onClickCardHeader(payload: MouseEvent, category: any) { + category.isHide = !category.isHide; + } + + function getCardHeaderIconClass(category: any) { + const classObject = { + 'f-icon': true, + 'f-icon-arrow-60-down': !category.isHide, + 'f-icon-arrow-e': category.isHide + } as Record; + return classObject; + } + + function renderCategoryCardHeader(category: ToolboxCategory) { + return ( +
onClickCardHeader(payload, category)}> +
+
+
+
+ +
+
+ {category.name} +
+
+
+
+
+ ); + } + + function getControlTileClass(toolboxItem: ToolboxItem) { + const classObject = { + 'd-none': toolboxItem.dependentParent || toolboxItem.hideInControlBox, + controlPanel: true, + 'drag-copy': true, + 'no-drag': toolboxItem.disable, + 'updating': toolboxItem.updating + } as Record; + return classObject; + } + + function getToolboxItemClass(toolboxItem: ToolboxItem) { + const classObject = { + farrisControlIcon: true, + 'fd-i-Family': true + } as Record; + const toolboxItemTypicalClassName = `fd_pc-${toolboxItem.icon || toolboxItem.type}`; + classObject[toolboxItemTypicalClassName] = true; + return classObject; + } + + function renderControlTile(toolboxItem: ToolboxItem, category: ToolboxCategory) { + return ( + + ); + } + + function renderCategoryCardBody(category: ToolboxCategory) { + return ( +
+ {category.items.map((toolboxItem: any) => renderControlTile(toolboxItem, category))} +
+ ); + } + + function renderCategoryCard(category: ToolboxCategory) { + return ( + !category.hideInControlBox && ( +
+ {renderCategoryCardHeader(category)} + {renderCategoryCardBody(category)} +
+ ) + ); + } + + /** + * 将工具箱各容器添加到dragula的拖拽列表中 + */ + function attachToolboxToDragulaContainer(dragulaInstance: any) { + if (!dragulaInstance) { + return; + } + const controlPanels = document.getElementsByClassName('controlCategory'); + if (!controlPanels) { + return; + } + + dragulaInstance.containers = dragulaInstance.containers.filter( + (element: HTMLElement) => !element.className.includes('controlCategory') + ); + + Array.from(controlPanels).forEach((panelElement) => { + dragulaInstance.containers.push(panelElement); + }); + + } + + watch( + () => props.dragula, + (newValue: any) => { + dragularCompostion.value = newValue; + if (dragularCompostion.value?.getDragulaInstance) { + attachToolboxToDragulaContainer(dragularCompostion.value?.getDragulaInstance()); + } + } + ); + + return () => { + return ( +
+
+ {controlCategoryList.value.map((category: any) => { + return renderCategoryCard(category); + })} +
+
+ ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.css b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.css new file mode 100644 index 00000000000..bdc92e87307 --- /dev/null +++ b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.css @@ -0,0 +1,75 @@ +.controlBox { + font-size: 13px !important; +} + +.controlBox .farris-panel { + border: none; +} + +.controlBox .farris-panel .card-header { + padding: 10px 0px !important; + background-color: #fcfdff !important; +} + +.controlBox .farris-panel .card-header .col-form-label { + font-size: 13px; + margin-bottom: 0px; + color: #3f4764; + opacity: 0.65; +} + +.controlBox .farris-panel .card-header .col-form-label .f-icon { + font-size: 10.8px; + color: #3f4764; +} + +.controlBox .farris-panel .card-body { + display: flex; + flex-wrap: wrap; + background: #fcfdff !important; +} + +.controlPanel:nth-child(-n + 3) { + margin-top: 0 !important; +} + +.controlPanel .farrisControlIcon { + font-size: 27px; +} + +.controlPanel { + font-size: 13px; + cursor: grab; + display: flex; + background: #fff; + align-items: center; + width: 33.333%; + background-color: #fcfdff; + border: 1px solid #edf1f5; + height: 76px !important; + text-align: center; + margin: -1px 0 0 -1px !important; + color: #6080ad; + /* overflow: hidden; */ + text-overflow: ellipsis; + word-break: keep-all; + -webkit-user-select: none; + user-select: none; +} + +.controlPanel.updating { + color: #707070; +} + +.controlPanel > div { + margin: auto; + overflow: hidden; +} + +.gu-mirror.undroppable.controlPanel { + cursor: no-drop; +} + +.controlBox .farris-panel .card-header .col-form-label .icon-panel .f-icon { + font-size: 16px; +} diff --git a/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json new file mode 100644 index 00000000000..3f3386d8a1d --- /dev/null +++ b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json @@ -0,0 +1,110 @@ +[ + { + "type": "input", + "name": "输入类控件", + "items": [ + { + "id": "TextBox", + "type": "input-group", + "name": "文本", + "category": "input" + }, + { + "id": "MultiTextBox", + "type": "textarea", + "name": "多行文本", + "category": "input" + }, + { + "id": "DateBox", + "type": "date-picker", + "name": "日期", + "category": "input" + }, + { + "id": "EnumField", + "type": "combo-list", + "name": "下拉列表", + "category": "input" + }, + { + "id": "NumericBox", + "type": "number-spinner", + "name": "数值", + "category": "input" + }, + { + "id": "CheckBox", + "type": "check-box", + "name": "复选框", + "category": "input" + }, + { + "id": "CheckBoxGroup", + "type": "check-group", + "name": "复选框组", + "category": "input" + }, + { + "id": "RadioGroup", + "type": "radio-group", + "name": "单选组", + "category": "input" + }, + { + "id": "SwitchField", + "type": "switch", + "name": "开关", + "category": "input" + }, + { + "id": "LookupEdit", + "type": "lookup", + "name": "帮助", + "category": "input" + } + ] + }, + { + "type": "dataCollection", + "name": "数据集合类控件", + "items": [ + { + "id": "ResponseForm", + "type": "form", + "name": "卡片面板", + "category": "dataCollection" + }, + { + "id": "DataGrid", + "type": "data-grid", + "name": "表格", + "category": "dataCollection" + } + ] + }, + { + "type": "container", + "name": "容器类控件", + "items": [ + { + "id": "Tab", + "type": "tabs", + "name": "标签页区域", + "category": "container" + } + ] + }, + { + "type": "business", + "name": "业务类控件", + "items": [ + { + "id": "QuerySolution", + "type": "query-solution", + "name": "筛选方案", + "category": "container" + } + ] + } +] \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.props.ts b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.props.ts new file mode 100644 index 00000000000..ddf9559cc14 --- /dev/null +++ b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.props.ts @@ -0,0 +1,10 @@ +import { ExtractPropTypes } from 'vue'; + +export const toolboxProps = { + id: { type: String, default: '' }, + dragula: { type: Object }, + toolboxItems: { type: Object } + +}; + +export type ToolboxPropsType = ExtractPropTypes; diff --git a/packages/mobile-ui-vue/components/designer-toolbox/src/types.ts b/packages/mobile-ui-vue/components/designer-toolbox/src/types.ts new file mode 100644 index 00000000000..52436075af5 --- /dev/null +++ b/packages/mobile-ui-vue/components/designer-toolbox/src/types.ts @@ -0,0 +1,22 @@ +export interface ToolboxItem { + id: string; + type: string; + name: string; + category: string; + icon?: string; + feature?: any; + dependentParent?: boolean; + hideInControlBox?: boolean; + disable?: boolean; + fieldType?: string; + templateCategory?: string; + updating?: boolean; +} + +export interface ToolboxCategory { + type: string; + name: string; + items: ToolboxItem[]; + hideInControlBox?: boolean; + isHide?: boolean; +}; diff --git a/packages/mobile-ui-vue/components/designer.ts b/packages/mobile-ui-vue/components/designer.ts index 3aaf39102fc..6118ec98be8 100644 --- a/packages/mobile-ui-vue/components/designer.ts +++ b/packages/mobile-ui-vue/components/designer.ts @@ -1,3 +1,5 @@ export * from './designer-canvas'; export * from './dynamic-resolver'; - +export { FDesignerToolbox } from './designer-toolbox'; +export { default as FModal, FModalService, FM_MODAL_SERVICE_TOKEN } from './modal'; +export { FM_UI_PROVIDER_SERVICE_TOKEN } from './common'; diff --git a/packages/mobile-ui-vue/components/float-container/index.ts b/packages/mobile-ui-vue/components/float-container/index.ts index 47454ca63a9..3b6178781c2 100644 --- a/packages/mobile-ui-vue/components/float-container/index.ts +++ b/packages/mobile-ui-vue/components/float-container/index.ts @@ -2,6 +2,7 @@ import { Plugin } from 'vue'; import { withInstall } from '@components/common'; import { propsResolver } from './src/float-container.props'; import FloatContainerInstallless from './src/float-container.component'; +import FloatContainerDesign from './src/designer/float-container.design.component'; const FLOAT_CONTAINER_REGISTERED_NAME = 'float-container'; @@ -15,6 +16,15 @@ FloatContainer.register = ( propsResolverMap[FLOAT_CONTAINER_REGISTERED_NAME] = propsResolver; }; +FloatContainer.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[FLOAT_CONTAINER_REGISTERED_NAME] = FloatContainerDesign; + propsResolverMap[FLOAT_CONTAINER_REGISTERED_NAME] = propsResolver; +}; + + export * from './src/float-container.props'; export { FloatContainer }; export default FloatContainer as typeof FloatContainer & Plugin; diff --git a/packages/mobile-ui-vue/components/float-container/src/designer/float-container.design.component.tsx b/packages/mobile-ui-vue/components/float-container/src/designer/float-container.design.component.tsx new file mode 100644 index 00000000000..959f7cde474 --- /dev/null +++ b/packages/mobile-ui-vue/components/float-container/src/designer/float-container.design.component.tsx @@ -0,0 +1,31 @@ +import { SetupContext, defineComponent, inject, onMounted, ref } from 'vue'; +import { FloatContainerProps, floatContainerProps } from '../float-container.props'; +import { useDesignerRules } from './use-designer-rules'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; + +export default defineComponent({ + name: 'FmFloatContainerDesign', + props: floatContainerProps, + emits: [], + setup(props: FloatContainerProps, context: SetupContext) { + const elementRef = ref(); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerHostService = inject('designer-host-service'); + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + context.expose(componentInstance.value); + + return () => { + return ( +
+ {context.slots.default?.()} +
+ ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..6f2d9115c56 --- /dev/null +++ b/packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts @@ -0,0 +1,99 @@ +import { ref } from "vue"; +import { ComponentSchema, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; +import { FloatContainerProperty } from "../property-config/float-container.property-config"; + +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const triggerBelongedComponentToMoveWhenMoved = ref(false); + + const triggerBelongedComponentToDeleteWhenDeleted = ref(false); + + const hideNestedPadding = true; + + const schema = ref(designItemContext.schema) + + function canAccepts(draggingContext: DraggingResolveContext): boolean { + const acceptableControlTypes = [ + 'navbar', + 'content-container', + 'html-template', + ]; + const uniqueControlTypes = [ + 'navbar', + ]; + const { sourceType, parentComponentInstance } = draggingContext; + if (!acceptableControlTypes.includes(sourceType)) { + return false; + } + const shouldBeUnique = uniqueControlTypes.includes(sourceType); + if (shouldBeUnique) { + const parentComponent = parentComponentInstance?.parent?.value; + const contents: any[] = parentComponent?.contents || []; + const hasSameTypeControl = !!contents.find((content) => content.type === sourceType); + if (hasSameTypeControl) { + return false; + } + } + return true; + } + + function checkCanMoveComponent() { + return false; + } + function checkCanDeleteComponent() { + return true; + } + + function hideNestedPaddingInDesginerView() { + return hideNestedPadding; + } + + function getDesignerClass(): string { + return ' position-absolute z-index-99 '; + } + + function getStyles(): string { + let style = '' + if (schema.value.position) { + style += Object.keys(schema.value.position).map(key => { + return `${key}: ${schema.value.position[key]}px;` + }).join('') + } + if (schema.value.padding) { + style += Object.keys(schema.value.padding).map(key => { + return `padding-${key}: ${schema.padding[key]}px;` + }).join('') + } + if (schema.value.margin) { + style += Object.keys(schema.value.margin).map(key => { + return `margin-${key}: ${schema.value.margin[key]}px;` + }).join('') + } + return style + } + + + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new FloatContainerProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + + + return { + canAccepts, + triggerBelongedComponentToMoveWhenMoved, + triggerBelongedComponentToDeleteWhenDeleted, + checkCanMoveComponent, + checkCanDeleteComponent, + hideNestedPaddingInDesginerView, + getDesignerClass, + getStyles, + getPropsConfig + }; +} diff --git a/packages/mobile-ui-vue/components/float-container/src/property-config/float-container.property-config.ts b/packages/mobile-ui-vue/components/float-container/src/property-config/float-container.property-config.ts new file mode 100644 index 00000000000..3ad2a788fe1 --- /dev/null +++ b/packages/mobile-ui-vue/components/float-container/src/property-config/float-container.property-config.ts @@ -0,0 +1,15 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class FloatContainerProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/form-item/index.ts b/packages/mobile-ui-vue/components/form-item/index.ts index af7481fd11f..c52eef2821f 100644 --- a/packages/mobile-ui-vue/components/form-item/index.ts +++ b/packages/mobile-ui-vue/components/form-item/index.ts @@ -1,6 +1,7 @@ import { withInstall } from '@components/common'; import { propsResolver } from './src/form-item.props'; import FormItemInstallless from './src/form-item.component'; +import FormItemDesign from './src/designer/form-item.design.component'; const FORM_REGISTERED_NAME = 'form-item'; @@ -14,6 +15,14 @@ FormItem.register = ( propsResolverMap[FORM_REGISTERED_NAME] = propsResolver; }; +FormItem.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[FORM_REGISTERED_NAME] = FormItemDesign; + propsResolverMap[FORM_REGISTERED_NAME] = propsResolver; +}; + export * from './src/form-item.props'; export { FormItem }; export default FormItem; diff --git a/packages/mobile-ui-vue/components/form-item/src/designer/form-item-use-designer-rules.ts b/packages/mobile-ui-vue/components/form-item/src/designer/form-item-use-designer-rules.ts new file mode 100644 index 00000000000..305fcbdbd85 --- /dev/null +++ b/packages/mobile-ui-vue/components/form-item/src/designer/form-item-use-designer-rules.ts @@ -0,0 +1,85 @@ +import { DesignerItemContext, DesignerHostService, UseDesignerRules, DesignerComponentInstance, ComponentSchema } from "@/components/designer-canvas"; +import { FormGroupProperty } from "../property-config/form-group.property-config"; + +export function useDesignerRulesForFormItem(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { + const schema = designItemContext.schema as ComponentSchema; + + function checkCanMoveComponent() { + return true; + } + function checkCanDeleteComponent() { + return true; + } + + function canAccepts() { + return false; + } + + function hideNestedPaddingInDesginerView() { + return true; + } + /** + * 若控件有绑定信息,删除控件时需要同步移除viewmodel中的记录 + */ + function removeBindingFromViewModel(bindingFieldId: string) { + const designViewModelUtils = designerHostService?.designViewModelUtils; + const formSchemaUtils = designerHostService?.formSchemaUtils; + const belongedComponentId = designItemContext?.componentInstance.value?.belongedComponentId; + if (!belongedComponentId || !designViewModelUtils || !formSchemaUtils) { + return; + } + const belongedviewModelId = formSchemaUtils.getViewModelIdByComponentId(belongedComponentId); + const dgViewModel = designViewModelUtils.getDgViewModel(belongedviewModelId); + + if (dgViewModel) { + dgViewModel.removeField([bindingFieldId]); + } + } + /** + * 若控件配置了表达式,删除控件时需要同步移除表达式 + */ + function removeExpression(bindingFieldId: string) { + const formSchemaUtils = designerHostService?.formSchemaUtils; + + if (formSchemaUtils.getExpressions().length) { + const expFieldIndex = formSchemaUtils.getExpressions().findIndex(e => e.fieldId === bindingFieldId); + if (expFieldIndex > -1) { + formSchemaUtils.getExpressions().splice(expFieldIndex, 1); + } + + } + } + + function getDesignerClass(): string { + return ' fm-input-wrapper '; + } + + /** + * 控件删除后事件 + */ + function onRemoveComponent() { + const { schema } = designItemContext; + const bindingFieldId = schema.binding && schema.binding.field; + if (bindingFieldId) { + removeBindingFromViewModel(bindingFieldId); + removeExpression(bindingFieldId); + } + } + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const inputGroupProps = new FormGroupProperty(componentId, designerHostService); + return inputGroupProps.getPropertyConfig(schema, componentInstance); + } + + + return { + canAccepts, + checkCanDeleteComponent, + checkCanMoveComponent, + hideNestedPaddingInDesginerView, + onRemoveComponent, + getDesignerClass, + getPropsConfig + }; +} 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 new file mode 100644 index 00000000000..251d704b9ea --- /dev/null +++ b/packages/mobile-ui-vue/components/form-item/src/designer/form-item.design.component.tsx @@ -0,0 +1,137 @@ +/** + * 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 { computed, defineComponent, inject, onMounted, ref, SetupContext, watch } from 'vue'; +import { useBem } from '@components/common'; +import FmCell from '@components/cell'; +import { FORM_ITEM_NAME, FormItemProps, formItemProps } from '../form-item.props'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; +import { propertyConfigSchemaMap } from '@/components/dynamic-resolver'; +import { useDesignerRulesForFormItem } from './form-item-use-designer-rules'; +import { useTypeResolverDesign } from '@/components/dynamic-form/src/composition/use-type-resolver-design'; + +export default defineComponent({ + name: 'FmFormItemDesign', + props: formItemProps, + + setup(props: FormItemProps, context: SetupContext) { + const { slots, expose } = context; + + const label = ref(props.label); + const labelAlign = ref(props.labelAlign); + const shouldShowRequired = ref(props.required); + const { bem } = useBem(FORM_ITEM_NAME); + const editor = ref(props.editor); + const { resolveEditorProps, resolveEditorType } = useTypeResolverDesign(); + + const elementRef = ref(); + const editorRef = ref(); + + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerHostService = inject('designer-host-service'); + const designerRulesComposition = useDesignerRulesForFormItem(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + + const renderLabel = () => { + if (slots.label) { + return [slots.label()]; + } + return ; + }; + + const contentClass = computed(() => { + let contentAlign = props.contentAlign || 'right'; + if (labelAlign.value === 'top') { + contentAlign = 'left'; + } + return { + [bem('content')]: true, + [bem('content', contentAlign)]: true + }; + }); + const renderContent = () => { + const renderConditionEditor = computed(() => { + const editorType = editor.value.type || 'input-group'; + const Component = resolveEditorType(editorType); + const editorProps = resolveEditorProps(editorType, editor.value); + return () => ; + }); + + + return
{renderConditionEditor.value()}
; + }; + + + const formItemClass = computed(() => { + const direction = labelAlign.value === 'top' ? 'vertical' : 'horizontal'; + return { + [bem()]: true, + [bem('', direction)]: true + }; + }); + + const labelClass = computed(() => { + const labelClasses = [bem('label'), bem('label', labelAlign.value)]; + if (shouldShowRequired.value === true) { + labelClasses.push(bem('label', 'required')); + } + return labelClasses.join(' '); + }); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + + componentInstance.value.getPropConfig = (...args) => { + let propertyConfigSchema = propertyConfigSchemaMap[props.editor.type]; + if (propertyConfigSchema && Object.keys(propertyConfigSchema).length === 0 && editorRef && editorRef.value && editorRef.value?.getPropConfig) { + propertyConfigSchema = editorRef.value.getPropConfig(...args, componentInstance.value); + } + return propertyConfigSchema; + + }; + }); + + watch([ + () => props.label, + ], + ([newLabel])=>{ + label.value = newLabel; + } + + ) + + context.expose(componentInstance.value); + + return () => { + const innerSlots = { + title: renderLabel, + default: renderContent, + leftIcon: slots.leftIcon, + rightIcon: slots.rightIcon, + extra: slots.extra + }; + + return ( + + + ); + }; + + } +}); 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 new file mode 100644 index 00000000000..bb3a52d2f72 --- /dev/null +++ b/packages/mobile-ui-vue/components/form-item/src/designer/response-form-use-designer-rules.ts @@ -0,0 +1,103 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerHostService, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; +import { getSchemaByType } from "@/components/dynamic-resolver"; +import { ref } from "vue"; +import { ResponseFormProperty } from "../property-config/response-form.property-config"; + +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { + const schema = designItemContext.schema as ComponentSchema; + + const triggerBelongedComponentToMoveWhenMoved = ref(false); + + const triggerBelongedComponentToDeleteWhenDeleted = ref(false); + + const hideNestedPadding = true; + + const isInFixedContextRules = true; + + function canAccepts(draggingContext: DraggingResolveContext): boolean { + + return true; + } + + + function checkCanMoveComponent() { + return true + } + function checkCanDeleteComponent() { + return true; + } + + function hideNestedPaddingInDesginerView() { + return hideNestedPadding; + } + + + function onResolveNewComponentSchema(resolveContext: DraggingResolveContext, componentSchema: ComponentSchema): ComponentSchema { + const { label } = resolveContext; + let formGroupElementSchema; + // 控件若有绑定信息,则根据绑定信息创建控件 + if (resolveContext.bindingSourceContext?.entityFieldNode) { + const controlCreatorUtils = designerHostService?.controlCreatorUtils; + formGroupElementSchema = controlCreatorUtils.setFormFieldProperty(resolveContext.bindingSourceContext?.entityFieldNode, componentSchema.type); + } else { + formGroupElementSchema = getSchemaByType('form-item') as ComponentSchema; + formGroupElementSchema.editor = componentSchema; + formGroupElementSchema.label = label; + } + + syncFieldToViewModel(resolveContext, componentSchema.type); + + return formGroupElementSchema; + } + + + + /** + * 添加输入类控件后,将绑定信息同步到视图模型 + */ + function syncFieldToViewModel(resolveContext: DraggingResolveContext, editorType: string) { + const { bindingSourceContext, parentComponentInstance } = resolveContext; + if (bindingSourceContext?.entityFieldNode && parentComponentInstance) { + const designViewModelUtils = designerHostService?.designViewModelUtils; + const formSchemaUtils = designerHostService?.formSchemaUtils; + const viewModelId = formSchemaUtils.getViewModelIdByComponentId(parentComponentInstance.belongedComponentId); + + const dgViewModel = designViewModelUtils.getDgViewModel(viewModelId); + dgViewModel.removeField([bindingSourceContext.entityFieldNode.id]); + dgViewModel.addField(bindingSourceContext.designViewModelField); + if (editorType) { + dgViewModel.changeField(bindingSourceContext.entityFieldNode.id, { editor: { $type: editorType } }); + } + } + + } + + function getStyles(): string { + return ' '; + } + + function getDesignerClass(): string { + return ' '; + } + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const inputGroupProps = new ResponseFormProperty(componentId, designerHostService); + return inputGroupProps.getPropertyConfig(schema, componentInstance); + } + + + return { + canAccepts, + triggerBelongedComponentToMoveWhenMoved, + triggerBelongedComponentToDeleteWhenDeleted, + checkCanMoveComponent, + checkCanDeleteComponent, + hideNestedPaddingInDesginerView, + getStyles, + getDesignerClass, + onResolveNewComponentSchema, + getPropsConfig + }; +} diff --git a/packages/mobile-ui-vue/components/form-item/src/designer/response-form.design.component.tsx b/packages/mobile-ui-vue/components/form-item/src/designer/response-form.design.component.tsx new file mode 100644 index 00000000000..47b8f94a399 --- /dev/null +++ b/packages/mobile-ui-vue/components/form-item/src/designer/response-form.design.component.tsx @@ -0,0 +1,46 @@ +import { computed, defineComponent, inject, onMounted, ref } from 'vue'; +import { useDesignerRules } from './response-form-use-designer-rules'; +import { FormProps, formProps } from '../form.props'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; + +export default defineComponent({ + name: 'FResponseFormDesign', + props: formProps, + emits: [], + setup(props: FormProps, context) { + const elementRef = ref(); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerHostService = inject('designer-host-service'); + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + context.expose(componentInstance.value); + + const responseFormClass = computed(() => { + const customClassArray = []; + const classObject = { + 'drag-container': true + } as Record; + customClassArray.reduce((result: Record, classString: string) => { + result[classString] = true; + return result; + }, classObject); + return classObject; + }); + + + return () => { + return ( + +
+ {context.slots.default && context.slots.default()} +
+ + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/form-item/src/form-item.props.ts b/packages/mobile-ui-vue/components/form-item/src/form-item.props.ts index a50759b8f7a..2952c339967 100644 --- a/packages/mobile-ui-vue/components/form-item/src/form-item.props.ts +++ b/packages/mobile-ui-vue/components/form-item/src/form-item.props.ts @@ -35,7 +35,9 @@ export const formItemProps = { showErrorMessage: { type: Boolean, default: undefined }, /** 错误信息位置 */ - errorMessageAlign: { type: String as PropType, deafult: undefined } + errorMessageAlign: { type: String as PropType, deafult: undefined }, + + editor: { type: Object as PropType, default: {} }, }; diff --git a/packages/mobile-ui-vue/components/form-item/src/property-config/form-group.property-config.ts b/packages/mobile-ui-vue/components/form-item/src/property-config/form-group.property-config.ts new file mode 100644 index 00000000000..46c7790226c --- /dev/null +++ b/packages/mobile-ui-vue/components/form-item/src/property-config/form-group.property-config.ts @@ -0,0 +1,16 @@ +import { DesignerComponentInstance } from "@/components/designer-canvas"; +import { BaseControlProperty } from "@/components/property-panel"; + +export class FormGroupProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any, componentInstance: DesignerComponentInstance) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/form-item/src/property-config/response-form.property-config.ts b/packages/mobile-ui-vue/components/form-item/src/property-config/response-form.property-config.ts new file mode 100644 index 00000000000..d035881f762 --- /dev/null +++ b/packages/mobile-ui-vue/components/form-item/src/property-config/response-form.property-config.ts @@ -0,0 +1,16 @@ +import { DesignerComponentInstance } from "@/components/designer-canvas"; +import { BaseControlProperty } from "@/components/property-panel"; + +export class ResponseFormProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any, componentInstance: DesignerComponentInstance) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/form/index.ts b/packages/mobile-ui-vue/components/form/index.ts index c62036c1587..f7cb3ad778c 100644 --- a/packages/mobile-ui-vue/components/form/index.ts +++ b/packages/mobile-ui-vue/components/form/index.ts @@ -18,6 +18,7 @@ import { Plugin } from 'vue'; import { withInstall } from '@components/common'; import { propsResolver } from '@components/form-item/src/form.props'; import FormInstallless from '@components/form-item/src/form.component'; +import FormInstalllessDesign from '../form-item/src/designer/response-form.design.component'; const FORM_REGISTERED_NAME = 'form'; @@ -31,6 +32,14 @@ Form.register = ( propsResolverMap[FORM_REGISTERED_NAME] = propsResolver; }; +Form.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[FORM_REGISTERED_NAME] = FormInstalllessDesign; + propsResolverMap[FORM_REGISTERED_NAME] = propsResolver; +}; + export * from '@components/form-item/src/form.props'; export { Form }; export default Form as typeof Form & Plugin; diff --git a/packages/mobile-ui-vue/components/input-group/index.ts b/packages/mobile-ui-vue/components/input-group/index.ts index 6217bc10ace..30385677fe3 100644 --- a/packages/mobile-ui-vue/components/input-group/index.ts +++ b/packages/mobile-ui-vue/components/input-group/index.ts @@ -1,6 +1,7 @@ import { withInstall } from '@components/common'; import { propsResolver } from './src/input-group.props'; import InputGroupInstallless from './src/input-group.component'; +import InputGroupDesign from './src/designer/input-group.design.component'; const INPUT_GROUP_REGISTERED_NAME = 'input-group'; @@ -13,6 +14,15 @@ InputGroup.register = ( componentMap[INPUT_GROUP_REGISTERED_NAME] = InputGroup; propsResolverMap[INPUT_GROUP_REGISTERED_NAME] = propsResolver; }; + +InputGroup.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[INPUT_GROUP_REGISTERED_NAME] = InputGroupDesign; + propsResolverMap[INPUT_GROUP_REGISTERED_NAME] = propsResolver; +}; + export * from './src/input-group.props'; export * from './src/types'; export { InputGroup }; diff --git a/packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx b/packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx new file mode 100644 index 00000000000..10ef1a9b3f7 --- /dev/null +++ b/packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx @@ -0,0 +1,50 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; +import { InputGroup, InputProps, inputProps } from '../..'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; +import { useInputGroupDesignerRules } from './use-designer-rules'; + +export default defineComponent({ + name: 'FmInputGroupDesign', + props: inputProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: InputProps, context: SetupContext) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useInputGroupDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + const inputGroupProps = computed(() => ({ + ...props, + editable: false + })); + + context.expose(componentInstance.value); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/input-group/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/input-group/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..c6684e06dd7 --- /dev/null +++ b/packages/mobile-ui-vue/components/input-group/src/designer/use-designer-rules.ts @@ -0,0 +1,15 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { InputGroupProperty } from "../property-config/input-group.property-config"; +export function useInputGroupDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const inputGroupProps = new InputGroupProperty(componentId, designerHostService); + return inputGroupProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/input-group/src/property-config/input-group.property-config.ts b/packages/mobile-ui-vue/components/input-group/src/property-config/input-group.property-config.ts new file mode 100644 index 00000000000..34037ac64d8 --- /dev/null +++ b/packages/mobile-ui-vue/components/input-group/src/property-config/input-group.property-config.ts @@ -0,0 +1,34 @@ +import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; + +export class InputGroupProperty extends InputBaseProperty { + + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + + getEditorProperties(propertyData: any) { + const self = this; + const editorProperties = self.getComponentConfig(propertyData, { type: "radio-group" }, { + placeholder: { + description: "空值时,输入控件内的占位文本", + title: "提示文本", + type: "string" + } + }); + editorProperties['setPropertyRelates'] = function (changeObject) { + if (!changeObject) { + return; + } + switch (changeObject.propertyID) { + case 'data': { + + break; + } + } + }; + return editorProperties; + } + + +} diff --git a/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json b/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json index 4801efdefbc..03a53f1db63 100644 --- a/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json +++ b/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json @@ -36,6 +36,38 @@ "description": "值变化事件", "type": "string", "default": "" + }, + "disable": { + "type": "string", + "default": false + }, + "readonly": { + "type": "string", + "default": false + }, + "title": { + "description": "", + "type": "string", + "default": "" + }, + "label": { + "description": "", + "type": "string", + "default": "" + }, + "lableWidth": { + "description": "", + "type": "number" + }, + "placeholder": { + "description": "", + "type": "string", + "default": "" + }, + "visible": { + "description": "", + "type": "boolean", + "default": true } }, "events": [ @@ -43,6 +75,8 @@ ], "required": [ "id", - "type" + "type", + "appearance", + "binding" ] } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/list-view/index.ts b/packages/mobile-ui-vue/components/list-view/index.ts index 5e571fa8982..acf70aef1b2 100644 --- a/packages/mobile-ui-vue/components/list-view/index.ts +++ b/packages/mobile-ui-vue/components/list-view/index.ts @@ -1,23 +1,29 @@ import { withInstall } from '@components/common'; import ListViewInstallless from './src/list-view.component'; -import ListViewDesignInstallless from './src/designer/list-view.design.component'; +import ListViewDesign from './src/designer/list-view.design.component'; import { propsResolver } from './src/list-view.props'; const LIST_VIEW_REGISTER_NAME = 'list-view'; const ListView = withInstall(ListViewInstallless); -const ListViewDesign = withInstall(ListViewDesignInstallless); export * from './src/list-view.props'; -export { ListView, ListViewDesign }; +ListView.register = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[LIST_VIEW_REGISTER_NAME] = ListView; + propsResolverMap[LIST_VIEW_REGISTER_NAME] = propsResolver; +} -export default { - register(componentMap: Record, propsResolverMap: Record, configResolverMap: Record): void { - componentMap[LIST_VIEW_REGISTER_NAME] = ListView; - propsResolverMap[LIST_VIEW_REGISTER_NAME] = propsResolver; - }, - registerDesigner(componentMap: Record, propsResolverMap: Record, configResolverMap: Record): void { - componentMap[LIST_VIEW_REGISTER_NAME] = ListViewDesign; - propsResolverMap[LIST_VIEW_REGISTER_NAME] = propsResolver; - } -}; +ListView.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[LIST_VIEW_REGISTER_NAME] = ListViewDesign; + propsResolverMap[LIST_VIEW_REGISTER_NAME] = propsResolver; +} + + +export { ListView }; +export default ListView ; diff --git a/packages/mobile-ui-vue/components/list-view/src/designer/list-view.design.component.tsx b/packages/mobile-ui-vue/components/list-view/src/designer/list-view.design.component.tsx index a8d0e4a15db..613a425325f 100644 --- a/packages/mobile-ui-vue/components/list-view/src/designer/list-view.design.component.tsx +++ b/packages/mobile-ui-vue/components/list-view/src/designer/list-view.design.component.tsx @@ -1,9 +1,9 @@ import { SetupContext, defineComponent, inject, onMounted, ref, computed } from 'vue'; -import { ListViewProps, listViewProps } from '../list-view.props'; +import { LIST_VIEW_NAME, ListViewProps, listViewProps } from '../list-view.props'; import { useDesignerRules } from './use-designer-rules'; -import { DesignerItemContext } from '../../../designer-canvas/src/types'; -import { useDesignerComponent } from '../../../designer-canvas/src/composition/function/use-designer-component'; -import ListView from '../list-view.component'; +import List from '@/components/list'; +import { useBem } from '@/components/common'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas'; export default defineComponent({ name: 'FmListViewDesign', @@ -11,8 +11,9 @@ export default defineComponent({ emits: [], setup(props: ListViewProps, context: SetupContext) { const elementRef = ref(); - const designItemContext = inject('design-item-context'); - const designerRulesComposition = useDesignerRules(designItemContext.schema, designItemContext.parent?.schema); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); onMounted(() => { @@ -26,10 +27,33 @@ export default defineComponent({ finished: true, })); + const { bem } = useBem(LIST_VIEW_NAME); + + const listViewClass = { + [bem()]: true, + [bem('', 'fill')]: true, + }; + + const listContentClass = { + [bem('content')]: true, + [bem('content', 'split')]: false, + }; + return () => ( -
- +
+
+ +
+
+
+ +
+
+ ); } }); diff --git a/packages/mobile-ui-vue/components/list-view/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/list-view/src/designer/use-designer-rules.ts index 2ea4e7382a8..66f9e80cd93 100644 --- a/packages/mobile-ui-vue/components/list-view/src/designer/use-designer-rules.ts +++ b/packages/mobile-ui-vue/components/list-view/src/designer/use-designer-rules.ts @@ -1,8 +1,9 @@ -import { nextTick, ref } from "vue"; -import { DesignerHTMLElement, DraggingResolveContext, UseDesignerRules } from "../../../designer-canvas/src/composition/types"; -import { ComponentSchema } from "../../../designer-canvas/src/types"; +import { ref } from "vue"; +import { DesignerHostService, DraggingResolveContext, UseDesignerRules } from "../../../designer-canvas/src/composition/types"; +import { ComponentProperty } from "../property-config/component.property-config"; +import { DesignerItemContext } from "@/components/designer-canvas"; -export function useDesignerRules(schema: ComponentSchema, parentSchema?: ComponentSchema): UseDesignerRules { +export function useDesignerRules(designItemContext: DesignerItemContext,designerHostService?: DesignerHostService): UseDesignerRules { const triggerBelongedComponentToMoveWhenMoved = ref(false); @@ -30,12 +31,20 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone } function getStyles(): string { - if (schema.fill) { - return 'flex: 1'; - } - return ''; + return 'flex: 1'; + + } + + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new ComponentProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); } + return { canAccepts, triggerBelongedComponentToMoveWhenMoved, @@ -44,5 +53,6 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone checkCanDeleteComponent, hideNestedPaddingInDesginerView, getStyles, + getPropsConfig }; } diff --git a/packages/mobile-ui-vue/components/list-view/src/property-config/component.property-config.ts b/packages/mobile-ui-vue/components/list-view/src/property-config/component.property-config.ts new file mode 100644 index 00000000000..b1ea32df738 --- /dev/null +++ b/packages/mobile-ui-vue/components/list-view/src/property-config/component.property-config.ts @@ -0,0 +1,51 @@ +import { BaseControlProperty } from "@/components/property-panel"; + + +export class ComponentProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + // 事件 + this.getEventPropConfig(propertyData); + return this.propertyConfig; + } + private getEventPropConfig(propertyData: any) { + const events = [ + { + label: "listClick", + name: "行点击事件", + } + ]; + const self = this; + const initialData = self.eventsEditorUtils['formProperties'](propertyData, self.viewModelId, events); + const properties = {}; + properties[self.viewModelId] = { + type: 'events-editor', + editor: { + initialData + } + }; + this.propertyConfig.categories['eventsEditor'] = { + title: '事件', + hideTitle: true, + properties, + // 这个属性,标记当属性变更得时候触发重新更新属性 + refreshPanelAfterChanged: true, + tabId: 'commands', + tabName: '交互', + setPropertyRelates(changeObject: any, data: any) { + const parameters = changeObject.propertyValue; + delete propertyData[self.viewModelId]; + if (parameters) { + parameters.setPropertyRelates = this.setPropertyRelates; // 添加自定义方法后,调用此回调方法,用于处理联动属性 + self.eventsEditorUtils.saveRelatedParameters(propertyData, self.viewModelId, parameters['events'], parameters); + } + } + }; + } +} diff --git a/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.json b/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.json index 49292d31b76..75c9494bb38 100644 --- a/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.json +++ b/packages/mobile-ui-vue/components/list-view/src/property-config/list-view.property-config.json @@ -16,11 +16,7 @@ "type": { "description": "组件类型", "title": "控件类型", - "type": "select", - "editor": { - "type": "container", - "enum": [] - } + "type": "string" } } }, diff --git a/packages/mobile-ui-vue/components/modal/index.ts b/packages/mobile-ui-vue/components/modal/index.ts index cea142d232b..ad48a036b87 100644 --- a/packages/mobile-ui-vue/components/modal/index.ts +++ b/packages/mobile-ui-vue/components/modal/index.ts @@ -19,12 +19,12 @@ import FModalService from './src/composition/modal.service'; export * from './src/modal.props'; -export const F_MODAL_SERVICE_TOKEN = Symbol('FModalService'); +export const FM_MODAL_SERVICE_TOKEN = Symbol('FModalService'); FModal.install = (app: App) => { app.component(FModal.name as string, FModal); const modalInstance = new FModalService(app); - app.provide(F_MODAL_SERVICE_TOKEN, modalInstance); + app.provide(FM_MODAL_SERVICE_TOKEN, modalInstance); app.provide('FModalService', modalInstance); }; diff --git a/packages/mobile-ui-vue/components/navbar/index.ts b/packages/mobile-ui-vue/components/navbar/index.ts index 2e20484d4c5..9860ea71a68 100644 --- a/packages/mobile-ui-vue/components/navbar/index.ts +++ b/packages/mobile-ui-vue/components/navbar/index.ts @@ -1,6 +1,7 @@ import { withInstall } from '@components/common'; import { propsResolver } from './src/navbar.props'; import NavbarInstallless from './src/navbar.component'; +import NavbarDesign from './src/designer/nav.design.component'; const NAVBAR_REGISTERED_NAME = 'navigation-bar'; @@ -10,5 +11,10 @@ Navbar.register = (componentMap: Record, propsResolverMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record) => { + componentMap[NAVBAR_REGISTERED_NAME] = NavbarDesign; + propsResolverMap[NAVBAR_REGISTERED_NAME] = propsResolver; +}; export { Navbar }; export default Navbar; diff --git a/packages/mobile-ui-vue/components/navbar/src/designer/nav.design.component.tsx b/packages/mobile-ui-vue/components/navbar/src/designer/nav.design.component.tsx new file mode 100644 index 00000000000..81d1d0cd355 --- /dev/null +++ b/packages/mobile-ui-vue/components/navbar/src/designer/nav.design.component.tsx @@ -0,0 +1,51 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, ref, SetupContext } from 'vue'; + +import Navbar from '../..'; +import { navbarProps, NavbarProps } from '../navbar.props'; +import { useDesignerRules } from './use-designer-rules'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; + +export default defineComponent({ + name: 'FNavDesign', + props: navbarProps, + emits: ['nav'] as (string[] & ThisType) | undefined, + setup(props: NavbarProps, context: SetupContext) { + const elementRef = ref(); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerHostService = inject('designer-host-service'); + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext,designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + context.expose(componentInstance.value); + + const navbarProps = computed(() => ({ + ...props, + })); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/navbar/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/navbar/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..00566e382cc --- /dev/null +++ b/packages/mobile-ui-vue/components/navbar/src/designer/use-designer-rules.ts @@ -0,0 +1,63 @@ +import { DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; +import { nextTick, ref } from "vue"; +import { NavBarProperty } from "../property-config/navbar.property-config"; + +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const triggerBelongedComponentToMoveWhenMoved = ref(false); + + const triggerBelongedComponentToDeleteWhenDeleted = ref(false); + + const hideNestedPadding = true; + + const isInFixedContextRules = true; + + function canAccepts(draggingContext: DraggingResolveContext): boolean { + + return false; + } + + + function checkCanMoveComponent() { + return true; + } + function checkCanDeleteComponent() { + return true; + } + + function hideNestedPaddingInDesginerView() { + return true; + } + + function getStyles(): string { + // return 'border-radius: 12px'; + return ' '; + } + + function getDesignerClass(): string { + return ' '; + } + + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new NavBarProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + + return { + canAccepts, + triggerBelongedComponentToMoveWhenMoved, + triggerBelongedComponentToDeleteWhenDeleted, + checkCanMoveComponent, + checkCanDeleteComponent, + hideNestedPaddingInDesginerView, + getStyles, + getDesignerClass, + getPropsConfig + }; +} diff --git a/packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts b/packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts new file mode 100644 index 00000000000..ca841d84dc6 --- /dev/null +++ b/packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts @@ -0,0 +1,31 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class NavBarProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + //行为 + this.propertyConfig.categories['behavior'] = this.getBehaviorConfig(propertyData); + + return this.propertyConfig; + } + + private getBehaviorConfig(propertyData) { + return { + description: "基本信息", + title: "行为", + properties: { + title: { + title: "标题", + type: "string", + } + } + }; + } + +} diff --git a/packages/mobile-ui-vue/components/page-body-container/index.ts b/packages/mobile-ui-vue/components/page-body-container/index.ts index c6cfd478abb..7d141367928 100644 --- a/packages/mobile-ui-vue/components/page-body-container/index.ts +++ b/packages/mobile-ui-vue/components/page-body-container/index.ts @@ -16,7 +16,7 @@ */ import { withInstall } from '@components/common'; import PageBodyContainerInstallless from './src/page-body-container.component'; -import PageBodyContainerDesignInstallless from './src/designer/page-body-container.design.component'; +import PageBodyContainerDesign from './src/designer/page-body-container.design.component'; import { propsResolver } from './src/page-body-container.props'; const PAGE_BODY_CONTAINER_REGISTER_NAME = 'page-body-container'; @@ -27,13 +27,12 @@ PageBodyContainer.register = (componentMap: Record, propsResolverMa propsResolverMap[PAGE_BODY_CONTAINER_REGISTER_NAME] = propsResolver; }; -const PageBodyContainerDesign = withInstall(PageBodyContainerDesignInstallless); -PageBodyContainerDesign.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record): void => { +PageBodyContainer.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record): void => { componentMap[PAGE_BODY_CONTAINER_REGISTER_NAME] = PageBodyContainerDesign; propsResolverMap[PAGE_BODY_CONTAINER_REGISTER_NAME] = propsResolver; }; export * from './src/page-body-container.props'; -export { PageBodyContainer, PageBodyContainerDesign }; +export { PageBodyContainer }; export default PageBodyContainer; diff --git a/packages/mobile-ui-vue/components/page-body-container/src/designer/page-body-container.design.component.tsx b/packages/mobile-ui-vue/components/page-body-container/src/designer/page-body-container.design.component.tsx index a34c85bccae..8662cedfd43 100644 --- a/packages/mobile-ui-vue/components/page-body-container/src/designer/page-body-container.design.component.tsx +++ b/packages/mobile-ui-vue/components/page-body-container/src/designer/page-body-container.design.component.tsx @@ -1,8 +1,7 @@ import { SetupContext, defineComponent, inject, onMounted, ref } from 'vue'; import { PageBodyContainerProps, pageBodyContainerProps } from '../page-body-container.props'; import { useDesignerRules } from './use-designer-rules'; -import { DesignerItemContext } from '../../../designer-canvas/src/types'; -import { useDesignerComponent } from '../../../designer-canvas/src/composition/function/use-designer-component'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; export default defineComponent({ name: 'FmPageBodyContainerDesign', @@ -10,8 +9,9 @@ export default defineComponent({ emits: [], setup(props: PageBodyContainerProps, context: SetupContext) { const elementRef = ref(); - const designItemContext = inject('design-item-context'); - const designerRulesComposition = useDesignerRules(designItemContext.schema, designItemContext.parent?.schema); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); onMounted(() => { diff --git a/packages/mobile-ui-vue/components/page-body-container/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/page-body-container/src/designer/use-designer-rules.ts index 8cfec6e7f99..f5fd184a249 100644 --- a/packages/mobile-ui-vue/components/page-body-container/src/designer/use-designer-rules.ts +++ b/packages/mobile-ui-vue/components/page-body-container/src/designer/use-designer-rules.ts @@ -1,9 +1,10 @@ import { nextTick, ref } from "vue"; -import { DesignerHTMLElement, DraggingResolveContext, UseDesignerRules } from "../../../designer-canvas/src/composition/types"; -import { ComponentSchema } from "../../../designer-canvas/src/types"; import { PAGE_BODY_CONTAINER_NAME } from '../page-body-container.props'; +import { DesignerHostService, DraggingResolveContext, UseDesignerRules } from "@/components/designer-canvas/src/composition/types"; +import { DesignerItemContext } from "@/components/designer-canvas"; +import { PageBodyContainerProperty } from "../property-config/page-body-container.property-config"; -export function useDesignerRules(schema: ComponentSchema, parentSchema?: ComponentSchema): UseDesignerRules { +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { const triggerBelongedComponentToMoveWhenMoved = ref(false); @@ -21,8 +22,8 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone 'float-container', 'navbar', ]; - const { controlType } = draggingContext; - if (unAcceptableControlTypes.includes(controlType)) { + const { componentType } = draggingContext; + if (unAcceptableControlTypes.includes(componentType)) { return false; } return true; @@ -30,10 +31,10 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone function checkCanMoveComponent() { - return !isInFixedContextRules; + return true; } function checkCanDeleteComponent() { - return !isInFixedContextRules; + return true; } function hideNestedPaddingInDesginerView() { @@ -44,6 +45,16 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone return PAGE_BODY_CONTAINER_NAME; } + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new PageBodyContainerProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + return { canAccepts, triggerBelongedComponentToMoveWhenMoved, @@ -52,5 +63,6 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone checkCanDeleteComponent, hideNestedPaddingInDesginerView, getDesignerClass, + getPropsConfig }; } diff --git a/packages/mobile-ui-vue/components/page-body-container/src/page-body-container.props.ts b/packages/mobile-ui-vue/components/page-body-container/src/page-body-container.props.ts index bcca60bfc7b..4a4089bf75c 100644 --- a/packages/mobile-ui-vue/components/page-body-container/src/page-body-container.props.ts +++ b/packages/mobile-ui-vue/components/page-body-container/src/page-body-container.props.ts @@ -2,7 +2,6 @@ import { ExtractPropTypes } from 'vue'; import { createPropsResolver } from '../../dynamic-resolver'; import { schemaMapper } from './schema/schema-mapper'; import pageBodyContainerSchema from './schema/page-body-container.schema.json'; -import pageBodyContainerPropertyConfig from './property-config/page-body-container.property-config.json'; import { schemaResolver } from './schema/schema-resolver'; export const PAGE_BODY_CONTAINER_NAME = 'fm-page-body-container'; @@ -17,6 +16,5 @@ export const propsResolver = createPropsResolver( pageBodyContainerProps, pageBodyContainerSchema, schemaMapper, - schemaResolver, - pageBodyContainerPropertyConfig, + schemaResolver ); diff --git a/packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.json b/packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.json deleted file mode 100644 index e7b0c65f4e6..00000000000 --- a/packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "title": "page-body-container", - "description": "A Farris Container Component", - "type": "object", - "categories": { - "basic": { - "description": "Basic Infomation", - "title": "基本信息", - "properties": { - "id": { - "description": "组件标识", - "title": "标识", - "type": "string", - "readonly": true - }, - "type": { - "description": "组件类型", - "title": "控件类型", - "type": "select", - "editor": { - "type": "container", - "enum": [] - } - } - } - }, - "behavior": { - "description": "", - "title": "行为", - "properties": { - "visible": { - "description": "运行时组件是否可见", - "type": "boolean", - "title": "是否可见", - "editor": { - "type": "combo-list", - "data": [ - { - "value": true, - "name": "是" - }, - { - "value": false, - "name": "否" - } - ] - } - } - } - } - } -} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.ts b/packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.ts new file mode 100644 index 00000000000..077bd5883ae --- /dev/null +++ b/packages/mobile-ui-vue/components/page-body-container/src/property-config/page-body-container.property-config.ts @@ -0,0 +1,15 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class PageBodyContainerProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/page-container/index.ts b/packages/mobile-ui-vue/components/page-container/index.ts index 00d8d010d3f..4438af465e2 100644 --- a/packages/mobile-ui-vue/components/page-container/index.ts +++ b/packages/mobile-ui-vue/components/page-container/index.ts @@ -16,7 +16,7 @@ */ import { withInstall } from '@components/common'; import PageContainerInstallless from './src/page-container.component'; -import PageContainerDesignInstallless from './src/designer/page-container.design.component'; +import PageContainerDesign from './src/designer/page-container.design.component'; import { propsResolver } from './src/page-container.props'; const PAGE_CONTAINER_REGISTERED_NAME = 'page-container'; @@ -29,8 +29,7 @@ PageContainer.register = ( propsResolverMap[PAGE_CONTAINER_REGISTERED_NAME] = propsResolver; }; -const PageContainerDesign = withInstall(PageContainerDesignInstallless); -PageContainerDesign.registerDesigner = ( +PageContainer.registerDesigner = ( componentMap: Record, propsResolverMap: Record, configResolverMap: Record ): void => { componentMap[PAGE_CONTAINER_REGISTERED_NAME] = PageContainerDesign; @@ -38,5 +37,5 @@ PageContainerDesign.registerDesigner = ( }; export * from './src/page-container.props'; -export { PageContainer, PageContainerDesign }; +export { PageContainer }; export default PageContainer; diff --git a/packages/mobile-ui-vue/components/page-container/src/designer/page-container.design.component.tsx b/packages/mobile-ui-vue/components/page-container/src/designer/page-container.design.component.tsx index 5751301030d..f265911ef32 100644 --- a/packages/mobile-ui-vue/components/page-container/src/designer/page-container.design.component.tsx +++ b/packages/mobile-ui-vue/components/page-container/src/designer/page-container.design.component.tsx @@ -1,8 +1,7 @@ import { SetupContext, defineComponent, inject, onMounted, ref } from 'vue'; import { PageContainerProps, pageContainerProps } from '../page-container.props'; import { useDesignerRules } from './use-designer-rules'; -import { DesignerItemContext } from '../../../designer-canvas/src/types'; -import { useDesignerComponent } from '../../../designer-canvas/src/composition/function/use-designer-component'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; export default defineComponent({ name: 'FmPageContainerDesign', @@ -10,8 +9,9 @@ export default defineComponent({ emits: [], setup(props: PageContainerProps, context: SetupContext) { const elementRef = ref(); - const designItemContext = inject('design-item-context'); - const designerRulesComposition = useDesignerRules(designItemContext.schema, designItemContext.parent?.schema); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); onMounted(() => { diff --git a/packages/mobile-ui-vue/components/page-container/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/page-container/src/designer/use-designer-rules.ts index 4b6ed1d438f..dd317403bcc 100644 --- a/packages/mobile-ui-vue/components/page-container/src/designer/use-designer-rules.ts +++ b/packages/mobile-ui-vue/components/page-container/src/designer/use-designer-rules.ts @@ -1,9 +1,10 @@ -import { nextTick, ref } from "vue"; -import { DesignerHTMLElement, DraggingResolveContext, UseDesignerRules } from "../../../designer-canvas/src/composition/types"; -import { ComponentSchema } from "../../../designer-canvas/src/types"; +import { ref } from "vue"; import { PAGE_CONTAINER_NAME } from '../page-container.props'; +import { DesignerHostService, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; +import { PageContainerProperty } from "../property-config/page-container.property-config"; -export function useDesignerRules(schema: ComponentSchema, parentSchema?: ComponentSchema): UseDesignerRules { +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { const triggerBelongedComponentToMoveWhenMoved = ref(false); @@ -25,15 +26,15 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone 'page-footer-container', 'page-body-container', ]; - const { controlType, parentComponentInstance } = draggingContext; - if (!acceptableControlTypes.includes(controlType)) { + const { componentType, parentComponentInstance } = draggingContext; + if (!acceptableControlTypes.includes(componentType)) { return false; } - const shouldBeUnique = uniqueControlTypes.includes(controlType); + const shouldBeUnique = uniqueControlTypes.includes(componentType); if (shouldBeUnique) { - const parentComponent = parentComponentInstance?.value; + const parentComponent = parentComponentInstance; const contents: any[] = parentComponent?.contents || []; - const hasSameTypeControl = !!contents.find((content) => content.type === controlType); + const hasSameTypeControl = !!contents.find((content) => content.type === componentType); if (hasSameTypeControl) { return false; } @@ -43,7 +44,7 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone function checkCanMoveComponent() { - return !isInFixedContextRules; + return true; } function checkCanDeleteComponent() { return !isInFixedContextRules; @@ -54,13 +55,25 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone } function getStyles(): string { - return 'border-radius: 12px'; + // return 'border-radius: 12px'; + return ' '; } function getDesignerClass(): string { return PAGE_CONTAINER_NAME; } + + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new PageContainerProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + return { canAccepts, triggerBelongedComponentToMoveWhenMoved, @@ -70,5 +83,6 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone hideNestedPaddingInDesginerView, getStyles, getDesignerClass, + getPropsConfig }; } diff --git a/packages/mobile-ui-vue/components/page-container/src/page-container.props.ts b/packages/mobile-ui-vue/components/page-container/src/page-container.props.ts index e981a24e019..c7a084830eb 100644 --- a/packages/mobile-ui-vue/components/page-container/src/page-container.props.ts +++ b/packages/mobile-ui-vue/components/page-container/src/page-container.props.ts @@ -2,7 +2,6 @@ import { ExtractPropTypes } from 'vue'; import { createPropsResolver } from '../../dynamic-resolver'; import { schemaMapper } from './schema/schema-mapper'; import pageContainerSchema from './schema/page-container.schema.json'; -import pageContainerPropertyConfig from './property-config/page-container.property-config.json'; import { schemaResolver } from './schema/schema-resolver'; export const PAGE_CONTAINER_NAME = 'fm-page-container'; @@ -17,6 +16,5 @@ export const propsResolver = createPropsResolver( pageContainerProps, pageContainerSchema, schemaMapper, - schemaResolver, - pageContainerPropertyConfig, + schemaResolver ); diff --git a/packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.json b/packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.json deleted file mode 100644 index 7bc1352b999..00000000000 --- a/packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "title": "page-container", - "description": "A Farris Container Component", - "type": "object", - "categories": { - "basic": { - "description": "Basic Infomation", - "title": "基本信息", - "properties": { - "id": { - "description": "组件标识", - "title": "标识", - "type": "string", - "readonly": true - }, - "type": { - "description": "组件类型", - "title": "控件类型", - "type": "select", - "editor": { - "type": "container", - "enum": [] - } - } - } - }, - "behavior": { - "description": "", - "title": "行为", - "properties": { - "visible": { - "description": "运行时组件是否可见", - "type": "boolean", - "title": "是否可见", - "editor": { - "type": "combo-list", - "data": [ - { - "value": true, - "name": "是" - }, - { - "value": false, - "name": "否" - } - ] - } - } - } - } - } -} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.ts b/packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.ts new file mode 100644 index 00000000000..9771ba1d932 --- /dev/null +++ b/packages/mobile-ui-vue/components/page-container/src/property-config/page-container.property-config.ts @@ -0,0 +1,15 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class PageContainerProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/page-footer-container/index.ts b/packages/mobile-ui-vue/components/page-footer-container/index.ts index 1f3f9fcbbc2..e8cec7710ae 100644 --- a/packages/mobile-ui-vue/components/page-footer-container/index.ts +++ b/packages/mobile-ui-vue/components/page-footer-container/index.ts @@ -16,7 +16,7 @@ */ import { withInstall } from '@components/common'; import PageFooterContainerInstallless from './src/page-footer-container.component'; -import PageFooterContainerDesignInstallless from './src/designer/page-footer-container.design.component'; +import PageFooterContainerDesign from './src/designer/page-footer-container.design.component'; import { propsResolver } from './src/page-footer-container.props'; const COMPONENT_TYPE = 'page-footer-container'; @@ -30,8 +30,7 @@ PageFooterContainer.register = ( propsResolverMap[COMPONENT_TYPE] = propsResolver; }; -const PageFooterContainerDesign = withInstall(PageFooterContainerDesignInstallless); -PageFooterContainerDesign.registerDesigner = ( +PageFooterContainer.registerDesigner = ( componentMap: Record, propsResolverMap: Record, configResolverMap: Record ): void => { @@ -40,5 +39,5 @@ PageFooterContainerDesign.registerDesigner = ( }; export * from './src/page-footer-container.props'; -export { PageFooterContainer, PageFooterContainerDesign }; +export { PageFooterContainer }; export default PageFooterContainer; diff --git a/packages/mobile-ui-vue/components/page-footer-container/src/designer/page-footer-container.design.component.tsx b/packages/mobile-ui-vue/components/page-footer-container/src/designer/page-footer-container.design.component.tsx index b91bd86138b..8a2a1978665 100644 --- a/packages/mobile-ui-vue/components/page-footer-container/src/designer/page-footer-container.design.component.tsx +++ b/packages/mobile-ui-vue/components/page-footer-container/src/designer/page-footer-container.design.component.tsx @@ -1,8 +1,7 @@ import { SetupContext, defineComponent, inject, onMounted, ref } from 'vue'; import { PageFooterContainerProps, pageFooterContainerProps } from '../page-footer-container.props'; import { useDesignerRules } from './use-designer-rules'; -import { DesignerItemContext } from '../../../designer-canvas/src/types'; -import { useDesignerComponent } from '../../../designer-canvas/src/composition/function/use-designer-component'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; export default defineComponent({ name: 'FmPageFooterContainerDesign', @@ -10,8 +9,9 @@ export default defineComponent({ emits: [], setup(props: PageFooterContainerProps, context: SetupContext) { const elementRef = ref(); - const designItemContext = inject('design-item-context'); - const designerRulesComposition = useDesignerRules(designItemContext.schema, designItemContext.parent?.schema); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); onMounted(() => { diff --git a/packages/mobile-ui-vue/components/page-footer-container/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/page-footer-container/src/designer/use-designer-rules.ts index 646004bdb6d..d3d813ebed1 100644 --- a/packages/mobile-ui-vue/components/page-footer-container/src/designer/use-designer-rules.ts +++ b/packages/mobile-ui-vue/components/page-footer-container/src/designer/use-designer-rules.ts @@ -1,9 +1,10 @@ import { ref } from "vue"; -import { DesignerHTMLElement, DraggingResolveContext, UseDesignerRules } from "../../../designer-canvas/src/composition/types"; -import { ComponentSchema } from "../../../designer-canvas/src/types"; import { PAGE_FOOTER_CONTAINER_NAME } from '../page-footer-container.props'; +import { DesignerHostService, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; +import { PageFooterContainerProperty } from "../property-config/page-footer-container.property-config"; -export function useDesignerRules(schema: ComponentSchema, parentSchema?: ComponentSchema): UseDesignerRules { +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService?: DesignerHostService): UseDesignerRules { const triggerBelongedComponentToMoveWhenMoved = ref(false); @@ -18,8 +19,8 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone 'content-container', 'html-template', ]; - const { controlType } = draggingContext; - if (!acceptableControlTypes.includes(controlType)) { + const { componentType } = draggingContext; + if (!acceptableControlTypes.includes(componentType)) { return false; } return true; @@ -27,7 +28,7 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone function checkCanMoveComponent() { - return false; + return true; } function checkCanDeleteComponent() { return true; @@ -41,6 +42,16 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone return PAGE_FOOTER_CONTAINER_NAME; } + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new PageFooterContainerProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + + return { canAccepts, triggerBelongedComponentToMoveWhenMoved, @@ -49,5 +60,6 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone checkCanDeleteComponent, hideNestedPaddingInDesginerView, getDesignerClass, + getPropsConfig }; } diff --git a/packages/mobile-ui-vue/components/page-footer-container/src/page-footer-container.props.ts b/packages/mobile-ui-vue/components/page-footer-container/src/page-footer-container.props.ts index 6ed1c2031fc..79bc601420a 100644 --- a/packages/mobile-ui-vue/components/page-footer-container/src/page-footer-container.props.ts +++ b/packages/mobile-ui-vue/components/page-footer-container/src/page-footer-container.props.ts @@ -2,7 +2,6 @@ import { ExtractPropTypes } from 'vue'; import { createPropsResolver } from '../../dynamic-resolver'; import { schemaMapper } from './schema/schema-mapper'; import pageFooterContainerSchema from './schema/page-footer-container.schema.json'; -import pageFooterContainerPropertyConfig from './property-config/page-footer-container.property-config.json'; import { schemaResolver } from './schema/schema-resolver'; export const PAGE_FOOTER_CONTAINER_NAME = 'fm-page-footer-container'; @@ -17,6 +16,5 @@ export const propsResolver = createPropsResolver( pageFooterContainerProps, pageFooterContainerSchema, schemaMapper, - schemaResolver, - pageFooterContainerPropertyConfig, + schemaResolver ); diff --git a/packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.json b/packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.json deleted file mode 100644 index a1a581a9ef8..00000000000 --- a/packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "title": "page-footer-container", - "description": "A Farris Container Component", - "type": "object", - "categories": { - "basic": { - "description": "Basic Infomation", - "title": "基本信息", - "properties": { - "id": { - "description": "组件标识", - "title": "标识", - "type": "string", - "readonly": true - }, - "type": { - "description": "组件类型", - "title": "控件类型", - "type": "select", - "editor": { - "type": "container", - "enum": [] - } - } - } - }, - "behavior": { - "description": "", - "title": "行为", - "properties": { - "visible": { - "description": "运行时组件是否可见", - "type": "boolean", - "title": "是否可见", - "editor": { - "type": "combo-list", - "data": [ - { - "value": true, - "name": "是" - }, - { - "value": false, - "name": "否" - } - ] - } - } - } - } - } -} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.ts b/packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.ts new file mode 100644 index 00000000000..066b9d66ca2 --- /dev/null +++ b/packages/mobile-ui-vue/components/page-footer-container/src/property-config/page-footer-container.property-config.ts @@ -0,0 +1,15 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class PageFooterContainerProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/page-header-container/index.ts b/packages/mobile-ui-vue/components/page-header-container/index.ts index 92ddae7dab1..1a36319a7ec 100644 --- a/packages/mobile-ui-vue/components/page-header-container/index.ts +++ b/packages/mobile-ui-vue/components/page-header-container/index.ts @@ -16,7 +16,7 @@ */ import { withInstall } from '@components/common'; import PageHeaderContainerInstallless from './src/page-header-container.component'; -import PageHeaderContainerDesignInstallless from './src/designer/page-header-container.design.component'; +import PageHeaderContainerDesign from './src/designer/page-header-container.design.component'; import { propsResolver } from './src/page-header-container.props'; const PAGE_HEADER_CONTAINER_REGISTERED_NAME = 'page-header-container'; @@ -30,8 +30,7 @@ PageHeaderContainer.register = ( propsResolverMap[PAGE_HEADER_CONTAINER_REGISTERED_NAME] = propsResolver; }; -const PageHeaderContainerDesign = withInstall(PageHeaderContainerDesignInstallless); -PageHeaderContainerDesign.registerDesigner = ( +PageHeaderContainer.registerDesigner = ( componentMap: Record, propsResolverMap: Record, configResolverMap: Record ): void => { componentMap[PAGE_HEADER_CONTAINER_REGISTERED_NAME] = PageHeaderContainerDesign; @@ -39,5 +38,5 @@ PageHeaderContainerDesign.registerDesigner = ( }; export * from './src/page-header-container.props'; -export { PageHeaderContainer, PageHeaderContainerDesign }; +export { PageHeaderContainer }; export default PageHeaderContainer; diff --git a/packages/mobile-ui-vue/components/page-header-container/src/designer/page-header-container.design.component.tsx b/packages/mobile-ui-vue/components/page-header-container/src/designer/page-header-container.design.component.tsx index 9237dcb1f83..b43faef2fb8 100644 --- a/packages/mobile-ui-vue/components/page-header-container/src/designer/page-header-container.design.component.tsx +++ b/packages/mobile-ui-vue/components/page-header-container/src/designer/page-header-container.design.component.tsx @@ -1,8 +1,7 @@ import { SetupContext, defineComponent, inject, onMounted, ref } from 'vue'; import { PageHeaderContainerProps, pageHeaderContainerProps } from '../page-header-container.props'; import { useDesignerRules } from './use-designer-rules'; -import { DesignerItemContext } from '../../../designer-canvas/src/types'; -import { useDesignerComponent } from '../../../designer-canvas/src/composition/function/use-designer-component'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; export default defineComponent({ name: 'FmPageHeaderContainerDesign', @@ -10,8 +9,9 @@ export default defineComponent({ emits: [], setup(props: PageHeaderContainerProps, context: SetupContext) { const elementRef = ref(); - const designItemContext = inject('design-item-context'); - const designerRulesComposition = useDesignerRules(designItemContext.schema, designItemContext.parent?.schema); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerHostService = inject('designer-host-service'); + const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); onMounted(() => { diff --git a/packages/mobile-ui-vue/components/page-header-container/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/page-header-container/src/designer/use-designer-rules.ts index 66ae6778195..9833f1936a9 100644 --- a/packages/mobile-ui-vue/components/page-header-container/src/designer/use-designer-rules.ts +++ b/packages/mobile-ui-vue/components/page-header-container/src/designer/use-designer-rules.ts @@ -1,9 +1,10 @@ import { ref } from "vue"; -import { DraggingResolveContext, UseDesignerRules } from "../../../designer-canvas/src/composition/types"; -import { ComponentSchema } from "../../../designer-canvas/src/types"; import { PAGE_HEADER_CONTAINER_NAME } from '../page-header-container.props'; +import { ComponentSchema, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; +import { PageHeaderContainerProperty } from "../property-config/page-header-container.property-config"; -export function useDesignerRules(schema: ComponentSchema, parentSchema?: ComponentSchema): UseDesignerRules { +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { const triggerBelongedComponentToMoveWhenMoved = ref(false); @@ -20,15 +21,15 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone const uniqueControlTypes = [ 'navbar', ]; - const { controlType, parentComponentInstance } = draggingContext; - if (!acceptableControlTypes.includes(controlType)) { + const { sourceType, parentComponentInstance } = draggingContext; + if (!acceptableControlTypes.includes(sourceType)) { return false; } - const shouldBeUnique = uniqueControlTypes.includes(controlType); + const shouldBeUnique = uniqueControlTypes.includes(sourceType); if (shouldBeUnique) { - const parentComponent = parentComponentInstance?.value; + const parentComponent = parentComponentInstance?.parent?.value; const contents: any[] = parentComponent?.contents || []; - const hasSameTypeControl = !!contents.find((content) => content.type === controlType); + const hasSameTypeControl = !!contents.find((content) => content.type === sourceType); if (hasSameTypeControl) { return false; } @@ -37,7 +38,7 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone } function checkCanMoveComponent() { - return false; + return true; } function checkCanDeleteComponent() { return true; @@ -50,6 +51,16 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone function getDesignerClass(): string { return PAGE_HEADER_CONTAINER_NAME; } + + /** + * 获取属性配置 + */ + function getPropsConfig(componentId: string) { + const componentProp = new PageHeaderContainerProperty(componentId, designerHostService); + const { schema } = designItemContext; + return componentProp.getPropertyConfig(schema); + } + return { canAccepts, @@ -59,5 +70,6 @@ export function useDesignerRules(schema: ComponentSchema, parentSchema?: Compone checkCanDeleteComponent, hideNestedPaddingInDesginerView, getDesignerClass, + getPropsConfig }; } diff --git a/packages/mobile-ui-vue/components/page-header-container/src/page-header-container.props.ts b/packages/mobile-ui-vue/components/page-header-container/src/page-header-container.props.ts index 1e8413a3f85..15901f23a8d 100644 --- a/packages/mobile-ui-vue/components/page-header-container/src/page-header-container.props.ts +++ b/packages/mobile-ui-vue/components/page-header-container/src/page-header-container.props.ts @@ -2,7 +2,6 @@ import { ExtractPropTypes } from 'vue'; import { createPropsResolver } from '../../dynamic-resolver'; import { schemaMapper } from './schema/schema-mapper'; import pageHeaderContainerSchema from './schema/page-header-container.schema.json'; -import pageHeaderContainerPropertyConfig from './property-config/page-header-container.property-config.json'; import { schemaResolver } from './schema/schema-resolver'; export const PAGE_HEADER_CONTAINER_NAME = 'fm-page-header-container'; @@ -17,6 +16,5 @@ export const propsResolver = createPropsResolver( pageHeaderContainerProps, pageHeaderContainerSchema, schemaMapper, - schemaResolver, - pageHeaderContainerPropertyConfig, + schemaResolver ); diff --git a/packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.json b/packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.json deleted file mode 100644 index 9abbd5182e4..00000000000 --- a/packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "title": "page-header-container", - "description": "A Farris Container Component", - "type": "object", - "categories": { - "basic": { - "description": "Basic Infomation", - "title": "基本信息", - "properties": { - "id": { - "description": "组件标识", - "title": "标识", - "type": "string", - "readonly": true - }, - "type": { - "description": "组件类型", - "title": "控件类型", - "type": "select", - "editor": { - "type": "container", - "enum": [] - } - } - } - }, - "behavior": { - "description": "", - "title": "行为", - "properties": { - "visible": { - "description": "运行时组件是否可见", - "type": "boolean", - "title": "是否可见", - "editor": { - "type": "combo-list", - "data": [ - { - "value": true, - "name": "是" - }, - { - "value": false, - "name": "否" - } - ] - } - } - } - } - } -} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.ts b/packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.ts new file mode 100644 index 00000000000..9100e1f3740 --- /dev/null +++ b/packages/mobile-ui-vue/components/page-header-container/src/property-config/page-header-container.property-config.ts @@ -0,0 +1,15 @@ +import { BaseControlProperty } from "@/components/property-panel"; + +export class PageHeaderContainerProperty extends BaseControlProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: any) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + // 外观 + this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); + + return this.propertyConfig; + } +} diff --git a/packages/mobile-ui-vue/components/radio-group/index.ts b/packages/mobile-ui-vue/components/radio-group/index.ts index 70b9fbc5090..4c196194195 100644 --- a/packages/mobile-ui-vue/components/radio-group/index.ts +++ b/packages/mobile-ui-vue/components/radio-group/index.ts @@ -1,9 +1,23 @@ import { withInstall } from '@components/common'; import RadioGroupInstallless from './src/radio-group.component'; +import { propsResolver } from './src/radio-group.props'; +import RadioGroupDesign from './src/designer/radio-group.design.component'; export * from './src/radio-group.props'; +const RADIO_GROUP_REGISTERED_NAME = 'radio-group'; + const RadioGroup = withInstall(RadioGroupInstallless); +RadioGroup.register = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record) => { + componentMap[RADIO_GROUP_REGISTERED_NAME] = RadioGroup; + propsResolverMap[RADIO_GROUP_REGISTERED_NAME] = propsResolver; +}; +RadioGroup.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record) => { + componentMap[RADIO_GROUP_REGISTERED_NAME] = RadioGroupDesign; + propsResolverMap[RADIO_GROUP_REGISTERED_NAME] = propsResolver; +}; + + export { RadioGroup }; export default RadioGroup; diff --git a/packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx b/packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx new file mode 100644 index 00000000000..ab423e6c767 --- /dev/null +++ b/packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx @@ -0,0 +1,63 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; +import RadioGroup, { RadioGroupProps, radioGroupProps } from '../..'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas'; +import { useRadioGroupDesignerRules } from './use-designer-rules'; +; + +export default defineComponent({ + name: 'FmRadioGroupDesign', + props: radioGroupProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: RadioGroupProps, context: SetupContext) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useRadioGroupDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + const inputGroupProps = computed(() => ({ + ...props, + editable: false, + // options:[{ + // disabled: false, + // readonly: false, + // value: '1', + // text: '选项1' + // },{ + // disabled: false, + // readonly: false, + // value: '1', + // text: '选项1' + // }], + // direction:'horizontal' + })); + + context.expose(componentInstance.value); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/radio-group/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/radio-group/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..e16b11842f6 --- /dev/null +++ b/packages/mobile-ui-vue/components/radio-group/src/designer/use-designer-rules.ts @@ -0,0 +1,15 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { RadioGroupProperty } from "../property-config/radio-group.property-config"; +export function useRadioGroupDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const radioGroupProps = new RadioGroupProperty(componentId, designerHostService); + return radioGroupProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts b/packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts new file mode 100644 index 00000000000..d1b24caa387 --- /dev/null +++ b/packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts @@ -0,0 +1,53 @@ +import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; + +export class RadioGroupProperty extends InputBaseProperty { + + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + + getEditorProperties(propertyData: any) { + const self = this; + const editorProperties = self.getComponentConfig(propertyData, { type: "radio-group" }, { + placeholder: { + description: "空值时,输入控件内的占位文本", + title: "提示文本", + type: "string" + }, + direction: { + description: "", + title: "排列方向", + type: "enum", + editor: { + type: "combo-list", + textField: "value", + valueField: "key", + data: [{ "key": "horizontal", "value": "横向" }, { "key": "vertical", "value": "纵向" }] + } + }, + options: { + description: "", + title: "数据", + type: "array", + $converter: "/converter/enum-data.converter", + ...self.getItemCollectionEditor(propertyData, propertyData.editor.valueField, propertyData.editor.textField), + // 这个属性,标记当属性变更得时候触发重新更新属性 + refreshPanelAfterChanged: true, + } + }); + editorProperties['setPropertyRelates'] = function (changeObject) { + if (!changeObject) { + return; + } + switch (changeObject.propertyID) { + case 'data': { + + break; + } + } + }; + return editorProperties; + } + +} diff --git a/packages/mobile-ui-vue/components/radio-group/src/radio-group.props.ts b/packages/mobile-ui-vue/components/radio-group/src/radio-group.props.ts index 2e9da96c198..f246ce170f2 100644 --- a/packages/mobile-ui-vue/components/radio-group/src/radio-group.props.ts +++ b/packages/mobile-ui-vue/components/radio-group/src/radio-group.props.ts @@ -1,6 +1,10 @@ import { ExtractPropTypes, PropType } from 'vue'; import {CheckerShape, CheckerShapeMap } from '@components/checker'; import { CheckboxGroupContext, checkboxGroupProps } from '@components/checkbox-group'; +import { createPropsResolver } from '@/components/dynamic-resolver'; +import inputSchema from './schema/radio-group.schema.json'; +import { schemaMapper } from './schema/schema-mapper'; +import { schemaResolver } from './schema/schema-resolver'; export const RADIO_GROUP_NAME = 'fm-radio-group'; @@ -10,7 +14,7 @@ export const radioGroupProps = { shape: { type: String as PropType, default: CheckerShapeMap.Round }, modelValue: { type: [String, Number] , default: '' } -}; +} as Record; export type RadioGroupProps = ExtractPropTypes; @@ -19,3 +23,5 @@ type Merge = { }; export type RadioGroupContext = Merge void }>; + +export const propsResolver = createPropsResolver(radioGroupProps, inputSchema, schemaMapper, schemaResolver); diff --git a/packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json b/packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json new file mode 100644 index 00000000000..c24da46e4b0 --- /dev/null +++ b/packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/radio-group.schema.json", + "title": "radio-group", + "description": "A Farris Input Component", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a Input Group", + "type": "string" + }, + "type": { + "description": "The type string of Input Group component", + "type": "string", + "default": "radio-group" + }, + "appearance": { + "description": "", + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "default": {} + }, + "binding": { + "description": "", + "type": "object", + "default": {} + }, + "disable": { + "type": "string", + "default": false + }, + "readonly": { + "type": "string", + "default": false + }, + "title": { + "description": "", + "type": "string", + "default": "" + }, + "label": { + "description": "", + "type": "string", + "default": "" + }, + "lableWidth": { + "description": "", + "type": "number" + }, + "visible": { + "description": "", + "type": "boolean", + "default": true + }, + "options": { + "description": "", + "type": "array", + "default": [] + }, + "direction": { + "description": "", + "type": "string", + "default": "horizontal" + } + }, + "required": [ + "type", + "options", + "direction" + ], + "ignore": [ + "id", + "type", + "appearance", + "binding", + "visible" + ] +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts new file mode 100644 index 00000000000..abb57152ea8 --- /dev/null +++ b/packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts @@ -0,0 +1,5 @@ +import { MapperFunction, resolveAppearance } from '@/components/dynamic-resolver'; + +export const schemaMapper = new Map([ + ['appearance', resolveAppearance] +]); diff --git a/packages/mobile-ui-vue/components/radio-group/src/schema/schema-resolver.ts b/packages/mobile-ui-vue/components/radio-group/src/schema/schema-resolver.ts new file mode 100644 index 00000000000..660e1e609e1 --- /dev/null +++ b/packages/mobile-ui-vue/components/radio-group/src/schema/schema-resolver.ts @@ -0,0 +1,5 @@ +import { DynamicResolver } from "@/components/dynamic-resolver"; + +export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record): Record { + return schema; +} diff --git a/packages/mobile-ui-vue/components/textarea/index.ts b/packages/mobile-ui-vue/components/textarea/index.ts index 0926050f7e5..b41ca39b337 100644 --- a/packages/mobile-ui-vue/components/textarea/index.ts +++ b/packages/mobile-ui-vue/components/textarea/index.ts @@ -1,9 +1,23 @@ import { withInstall } from '@components/common'; import TextareaInstallless from './src/textarea.component'; +import TextareaDesign from './src/designer/textarea.design.component'; +import { propsResolver } from './src/textarea.props'; export * from './src/textarea.props'; +const TEXTAREA_REGISTERED_NAME = 'textarea'; + const Textarea = withInstall(TextareaInstallless); +Textarea.register = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record) => { + componentMap[TEXTAREA_REGISTERED_NAME] = Textarea; + propsResolverMap[TEXTAREA_REGISTERED_NAME] = propsResolver; +}; +Textarea.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record) => { + componentMap[TEXTAREA_REGISTERED_NAME] = TextareaDesign; + propsResolverMap[TEXTAREA_REGISTERED_NAME] = propsResolver; +}; + + export { Textarea }; export default Textarea; diff --git a/packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx b/packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx new file mode 100644 index 00000000000..9302b3507b3 --- /dev/null +++ b/packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx @@ -0,0 +1,51 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';import { TEXTAREA_NAME, textareaProps, TextareaProps } from '../textarea.props'; +import { useTextareaDesignerRules } from './use-designer-rules'; +import Textarea from '../..'; + + +export default defineComponent({ + name: 'FmTextareaDesign', + props: textareaProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: TextareaProps, context: SetupContext) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useTextareaDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + const inputGroupProps = computed(() => ({ + ...props, + editable: false + })); + + context.expose(componentInstance.value); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/textarea/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/textarea/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..76cd82b5e68 --- /dev/null +++ b/packages/mobile-ui-vue/components/textarea/src/designer/use-designer-rules.ts @@ -0,0 +1,20 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { TextareaProperty } from "../property-config/textarea.property-config"; +export function useTextareaDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + /** + * 构造属性配置方法 + * @param componentId + * @param componentInstance + * @returns + */ + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const inputGroupProps = new TextareaProperty(componentId, designerHostService); + return inputGroupProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts b/packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts new file mode 100644 index 00000000000..7269a0228aa --- /dev/null +++ b/packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts @@ -0,0 +1,34 @@ +import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; + +export class TextareaProperty extends InputBaseProperty { + + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + getEditorProperties(propertyData: any) { + return this.getComponentConfig(propertyData, { type: "textarea" }, { + placeholder: { + description: "空值时,输入控件内的占位文本", + title: "提示文本", + type: "string" + }, + rows: { + description: "", + title: "文本区域可见的行数", + type: "number", + editor: { + min: 0, + nullable:true + } + }, + showWordLimit: { + description: "", + title: "展示输入文本数量", + type: "boolean" + } + }); + } + + +} diff --git a/packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json b/packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json new file mode 100644 index 00000000000..1425b3ede9c --- /dev/null +++ b/packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/textarea.schema.json", + "title": "textarea", + "description": "A Farris Input Component", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a Input Group", + "type": "string" + }, + "type": { + "description": "The type string of Input Group component", + "type": "string", + "default": "textarea" + }, + "appearance": { + "description": "", + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "default": {} + }, + "binding": { + "description": "", + "type": "object", + "default": {} + }, + "disable": { + "type": "string", + "default": false + }, + "readonly": { + "type": "string", + "default": false + }, + "title": { + "description": "", + "type": "string", + "default": "" + }, + "label": { + "description": "", + "type": "string", + "default": "" + }, + "lableWidth": { + "description": "", + "type": "number" + }, + "placeholder": { + "description": "", + "type": "string", + "default": "" + }, + "visible": { + "description": "", + "type": "boolean", + "default": true + } + }, + "required": [ + "id", + "type", + "appearance", + "binding", + "visible" + ] +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts new file mode 100644 index 00000000000..abb57152ea8 --- /dev/null +++ b/packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts @@ -0,0 +1,5 @@ +import { MapperFunction, resolveAppearance } from '@/components/dynamic-resolver'; + +export const schemaMapper = new Map([ + ['appearance', resolveAppearance] +]); diff --git a/packages/mobile-ui-vue/components/textarea/src/schema/schema-resolver.ts b/packages/mobile-ui-vue/components/textarea/src/schema/schema-resolver.ts new file mode 100644 index 00000000000..660e1e609e1 --- /dev/null +++ b/packages/mobile-ui-vue/components/textarea/src/schema/schema-resolver.ts @@ -0,0 +1,5 @@ +import { DynamicResolver } from "@/components/dynamic-resolver"; + +export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record): Record { + return schema; +} diff --git a/packages/mobile-ui-vue/components/textarea/src/textarea.props.ts b/packages/mobile-ui-vue/components/textarea/src/textarea.props.ts index 7f06a76323c..9472bad5408 100644 --- a/packages/mobile-ui-vue/components/textarea/src/textarea.props.ts +++ b/packages/mobile-ui-vue/components/textarea/src/textarea.props.ts @@ -1,5 +1,9 @@ import { ExtractPropTypes } from 'vue'; import { inputCommonProps } from '@/components/input-group'; +import { createPropsResolver } from '@/components/dynamic-resolver'; +import textareaSchema from './schema/input.schema.json'; +import { schemaMapper } from './schema/schema-mapper'; +import { schemaResolver } from './schema/schema-resolver'; export const TEXTAREA_NAME = 'FmTextarea'; @@ -15,6 +19,8 @@ export const textareaProps = { minHeight: { type: Number, default: undefined }, showWordLimit: { type: Boolean, default: undefined } -}; +} as Record; export type TextareaProps = ExtractPropTypes; + +export const propsResolver = createPropsResolver(textareaProps, textareaSchema, schemaMapper, schemaResolver); -- Gitee From a089cfc990589576cdf2447ecdf504f4a47bd1e0 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 25 Feb 2025 16:39:14 +0800 Subject: [PATCH 02/34] =?UTF-8?q?chore:=20=E7=A7=BB=E5=8A=A8=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=BA=93=E4=BB=A3=E7=A0=81=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/designer/button.design.component.tsx | 3 +- .../property-config/button.property-config.ts | 2 +- .../date-picker.property-config.ts | 13 +----- .../src/designer/use-designer-rules.ts | 29 +++++++++----- .../response-form-use-designer-rules.ts | 40 +++++++++---------- .../property-config/navbar.property-config.ts | 2 +- 6 files changed, 41 insertions(+), 48 deletions(-) diff --git a/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx b/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx index 88fa36811c4..2e886c10725 100644 --- a/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx +++ b/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-use-before-define */ /** * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. * @@ -36,7 +37,7 @@ export default defineComponent({ context.expose(componentInstance.value); - const schema = componentInstance.value.schema; + const{ schema } = componentInstance.value; const inputProps = computed(() => ({ ...props, diff --git a/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts b/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts index 797c3b7aae6..cf3fd87a769 100644 --- a/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts +++ b/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts @@ -9,7 +9,7 @@ export class ButtonProperty extends BaseControlProperty { this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); // 外观 this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); - //行为 + // 行为 this.propertyConfig.categories['behavior'] = this.getBehaviorConfig(propertyData); return this.propertyConfig; diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts index c0551502470..4f7ea85b3a5 100644 --- a/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts +++ b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts @@ -32,18 +32,7 @@ export class DatePickerProperty extends InputBaseProperty { data: valueFormatOptions } } - }, this.setEditorPropertyRelates); - } - - private setEditorPropertyRelates(changeObject: any, propertyData: any) { - if (!changeObject || !propertyData.editor) { - return; - } - switch (changeObject.propertyID) { - case 'showTime': { - - } - } + }); } private getAllShowType() { diff --git a/packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts index 6f2d9115c56..e036eeb86b9 100644 --- a/packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts +++ b/packages/mobile-ui-vue/components/float-container/src/designer/use-designer-rules.ts @@ -1,3 +1,19 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { ref } from "vue"; import { ComponentSchema, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; import { DraggingResolveContext } from "@/components/designer-canvas/src/composition/types"; @@ -5,10 +21,6 @@ import { FloatContainerProperty } from "../property-config/float-container.prope export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { - const triggerBelongedComponentToMoveWhenMoved = ref(false); - - const triggerBelongedComponentToDeleteWhenDeleted = ref(false); - const hideNestedPadding = true; const schema = ref(designItemContext.schema) @@ -62,7 +74,7 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe } if (schema.value.padding) { style += Object.keys(schema.value.padding).map(key => { - return `padding-${key}: ${schema.padding[key]}px;` + return `padding-${key}: ${schema.value.padding[key]}px;` }).join('') } if (schema.value.margin) { @@ -72,8 +84,7 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe } return style } - - + /** * 获取属性配置 */ @@ -83,12 +94,8 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe return componentProp.getPropertyConfig(schema); } - - return { canAccepts, - triggerBelongedComponentToMoveWhenMoved, - triggerBelongedComponentToDeleteWhenDeleted, checkCanMoveComponent, checkCanDeleteComponent, hideNestedPaddingInDesginerView, 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 bb3a52d2f72..66a89f6d3b0 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 @@ -32,27 +32,6 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe return hideNestedPadding; } - - function onResolveNewComponentSchema(resolveContext: DraggingResolveContext, componentSchema: ComponentSchema): ComponentSchema { - const { label } = resolveContext; - let formGroupElementSchema; - // 控件若有绑定信息,则根据绑定信息创建控件 - if (resolveContext.bindingSourceContext?.entityFieldNode) { - const controlCreatorUtils = designerHostService?.controlCreatorUtils; - formGroupElementSchema = controlCreatorUtils.setFormFieldProperty(resolveContext.bindingSourceContext?.entityFieldNode, componentSchema.type); - } else { - formGroupElementSchema = getSchemaByType('form-item') as ComponentSchema; - formGroupElementSchema.editor = componentSchema; - formGroupElementSchema.label = label; - } - - syncFieldToViewModel(resolveContext, componentSchema.type); - - return formGroupElementSchema; - } - - - /** * 添加输入类控件后,将绑定信息同步到视图模型 */ @@ -73,6 +52,24 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe } + function onResolveNewComponentSchema(resolveContext: DraggingResolveContext, componentSchema: ComponentSchema): ComponentSchema { + const { label } = resolveContext; + let formGroupElementSchema; + // 控件若有绑定信息,则根据绑定信息创建控件 + if (resolveContext.bindingSourceContext?.entityFieldNode) { + const controlCreatorUtils = designerHostService?.controlCreatorUtils; + formGroupElementSchema = controlCreatorUtils.setFormFieldProperty(resolveContext.bindingSourceContext?.entityFieldNode, componentSchema.type); + } else { + formGroupElementSchema = getSchemaByType('form-item') as ComponentSchema; + formGroupElementSchema.editor = componentSchema; + formGroupElementSchema.label = label; + } + + syncFieldToViewModel(resolveContext, componentSchema.type); + + return formGroupElementSchema; + } + function getStyles(): string { return ' '; } @@ -87,7 +84,6 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe return inputGroupProps.getPropertyConfig(schema, componentInstance); } - return { canAccepts, triggerBelongedComponentToMoveWhenMoved, diff --git a/packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts b/packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts index ca841d84dc6..e6a0c287c42 100644 --- a/packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts +++ b/packages/mobile-ui-vue/components/navbar/src/property-config/navbar.property-config.ts @@ -9,7 +9,7 @@ export class NavBarProperty extends BaseControlProperty { this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); // 外观 this.propertyConfig.categories['appearance'] = this.getAppearanceConfig(propertyData); - //行为 + // 行为 this.propertyConfig.categories['behavior'] = this.getBehaviorConfig(propertyData); return this.propertyConfig; -- Gitee From 6bf79732562d284a492b7f27f076cca493f94b96 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Wed, 26 Feb 2025 19:02:07 +0800 Subject: [PATCH 03/34] =?UTF-8?q?chore:=20=E7=A7=BB=E5=8A=A8=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=8E=A7=E4=BB=B6=E8=AE=BE=E8=AE=A1=E6=97=B6=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../property-config/button.property-config.ts | 16 +- .../button/src/schema/button.schema.json | 16 +- .../components/checkbox-group/index.ts | 15 ++ .../src/checkbox-group.props.ts | 9 +- .../checkbox-group.design.component.tsx | 74 +++++++++ .../src/designer/use-designer-rules.ts | 15 ++ .../checkbox-group.property-config.ts | 48 ++++++ .../src/schema/checkbox-group.schema.json | 78 +++++++++ .../src/schema/schema-mapper.ts | 7 + .../src/schema/schema-resolver.ts | 5 + .../designer/date-picker.design.component.tsx | 4 +- .../src/property-config/date-format.ts | 79 +++++++++ .../date-picker.property-config.ts | 49 ++---- .../src/schema/schema-mapper.ts | 3 +- .../date-picker-input/src/schema/schema.json | 24 +-- .../designer-canvas/src/components/maps.ts | 9 +- .../src/composition/dg-control.ts | 2 + .../designer-toolbox/src/toolbox.json | 153 ++++++++++++------ .../components/dynamic-resolver/index.ts | 2 + .../src/common/data-resolver.ts | 52 ++++++ .../designer/form-item.design.component.tsx | 11 +- .../src/schema/form-item.schema.json | 8 +- .../designer/input-group.design.component.tsx | 12 +- .../src/schema/input-group.schema.json | 7 +- .../components/picker-input/index.ts | 14 ++ .../enum-field-input.design.component.tsx | 74 +++++++++ .../src/designer/use-designer-rules.ts | 15 ++ .../picker-input/src/picker-input.props.ts | 8 +- .../enum-field-input.property-config.ts | 47 ++++++ .../src/schema/enum-field-input.schema.json | 83 ++++++++++ .../picker-input/src/schema/schema-mapper.ts | 7 + .../src/schema/schema-resolver.ts | 5 + .../designer/radio-group.design.component.tsx | 39 +++-- .../radio-group.property-config.ts | 7 +- .../src/schema/radio-group.schema.json | 11 +- .../radio-group/src/schema/schema-mapper.ts | 5 +- .../mobile-ui-vue/components/switch/index.ts | 23 +++ .../src/designer/switch.design.component.tsx | 51 ++++++ .../switch/src/designer/use-designer-rules.ts | 15 ++ .../property-config/switch.property-config.ts | 55 +++++++ .../switch/src/schema/schema-mapper.ts | 9 ++ .../switch/src/schema/schema-resolver.ts | 5 + .../switch/src/schema/switch.schema.json | 95 +++++++++++ .../components/switch/src/switch.props.ts | 11 ++ .../designer/textarea.design.component.tsx | 3 +- .../textarea.property-config.ts | 7 +- .../textarea/src/schema/input.schema.json | 28 ++-- .../textarea/src/schema/schema-mapper.ts | 4 +- 48 files changed, 1151 insertions(+), 168 deletions(-) create mode 100644 packages/mobile-ui-vue/components/checkbox-group/src/designer/checkbox-group.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/checkbox-group/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/checkbox-group/src/property-config/checkbox-group.property-config.ts create mode 100644 packages/mobile-ui-vue/components/checkbox-group/src/schema/checkbox-group.schema.json create mode 100644 packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-mapper.ts create mode 100644 packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-resolver.ts create mode 100644 packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-format.ts create mode 100644 packages/mobile-ui-vue/components/dynamic-resolver/src/common/data-resolver.ts create mode 100644 packages/mobile-ui-vue/components/picker-input/src/designer/enum-field-input.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/picker-input/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/picker-input/src/property-config/enum-field-input.property-config.ts create mode 100644 packages/mobile-ui-vue/components/picker-input/src/schema/enum-field-input.schema.json create mode 100644 packages/mobile-ui-vue/components/picker-input/src/schema/schema-mapper.ts create mode 100644 packages/mobile-ui-vue/components/picker-input/src/schema/schema-resolver.ts create mode 100644 packages/mobile-ui-vue/components/switch/src/designer/switch.design.component.tsx create mode 100644 packages/mobile-ui-vue/components/switch/src/designer/use-designer-rules.ts create mode 100644 packages/mobile-ui-vue/components/switch/src/property-config/switch.property-config.ts create mode 100644 packages/mobile-ui-vue/components/switch/src/schema/schema-mapper.ts create mode 100644 packages/mobile-ui-vue/components/switch/src/schema/schema-resolver.ts create mode 100644 packages/mobile-ui-vue/components/switch/src/schema/switch.schema.json diff --git a/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts b/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts index cf3fd87a769..81df157ea73 100644 --- a/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts +++ b/packages/mobile-ui-vue/components/button/src/property-config/button.property-config.ts @@ -23,6 +23,7 @@ export class ButtonProperty extends BaseControlProperty { visible: { title: "可见", type: "boolean", + visible:false }, disabled: { title: "只读", @@ -30,7 +31,20 @@ export class ButtonProperty extends BaseControlProperty { }, displayType: { title: "按钮类型", - type: "string", + type: 'select', + editor: { + type: 'combo-list', + textField: 'name', + valueField: 'value', + editable: false, + data: [{ value:'primary' , name: '主要按钮' }, + { value:'secondary' , name: '次要按钮' }, + { value:'success' , name: '成功按钮' }, + { value:'warning' , name: '警告按钮' }, + { value:'danger' , name: '危险按钮' }, + { value:'info' , name: '提示按钮' }, + ] + } }, block: { title: "是否占满整行", diff --git a/packages/mobile-ui-vue/components/button/src/schema/button.schema.json b/packages/mobile-ui-vue/components/button/src/schema/button.schema.json index c97693e7758..686c10702c5 100644 --- a/packages/mobile-ui-vue/components/button/src/schema/button.schema.json +++ b/packages/mobile-ui-vue/components/button/src/schema/button.schema.json @@ -27,7 +27,7 @@ "round": { "description": "是否为圆形", "type": "boolean", - "default": false, + "default": true, "isEvent": true }, "text": { @@ -40,6 +40,16 @@ "type": "boolean", "default": true }, + "visible": { + "description": "", + "type": "boolean", + "default": true + }, + "disabled": { + "description": "", + "type": "boolean", + "default": false + }, "appearance": { "description": "外观", "type": "object", @@ -65,8 +75,8 @@ "type", "visible", "round", - "disabled", "text", - "icon" + "icon", + "displayType" ] } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/checkbox-group/index.ts b/packages/mobile-ui-vue/components/checkbox-group/index.ts index c4b3c3a134d..98107fb53f8 100644 --- a/packages/mobile-ui-vue/components/checkbox-group/index.ts +++ b/packages/mobile-ui-vue/components/checkbox-group/index.ts @@ -1,9 +1,24 @@ import { withInstall } from '@components/common'; import CheckboxGroupInstallless from './src/checkbox-group.component'; +import { propsResolver } from './src/checkbox-group.props'; +import CheckBoxGroupDesign from './src/designer/checkbox-group.design.component'; export * from './src/composition'; export * from './src/checkbox-group.props'; + + +const CHECH_GROUP_REGISTERED_NAME = 'check-group'; + const CheckboxGroup = withInstall(CheckboxGroupInstallless); +CheckboxGroup.register = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record) => { + componentMap[CHECH_GROUP_REGISTERED_NAME] = CheckboxGroup; + propsResolverMap[CHECH_GROUP_REGISTERED_NAME] = propsResolver; +}; +CheckboxGroup.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record) => { + componentMap[CHECH_GROUP_REGISTERED_NAME] = CheckBoxGroupDesign; + propsResolverMap[CHECH_GROUP_REGISTERED_NAME] = propsResolver; +}; + export { CheckboxGroup }; export default CheckboxGroup; diff --git a/packages/mobile-ui-vue/components/checkbox-group/src/checkbox-group.props.ts b/packages/mobile-ui-vue/components/checkbox-group/src/checkbox-group.props.ts index 0e6996410e4..2a9cf19699d 100644 --- a/packages/mobile-ui-vue/components/checkbox-group/src/checkbox-group.props.ts +++ b/packages/mobile-ui-vue/components/checkbox-group/src/checkbox-group.props.ts @@ -1,5 +1,9 @@ import { ExtractPropTypes, PropType } from 'vue'; import { CheckerShape, CheckerShapeMap, CheckerType, CheckerTypeMap } from '@components/checker'; +import { schemaMapper } from './schema/schema-mapper'; +import { schemaResolver } from './schema/schema-resolver'; +import inputSchema from './schema/checkbox-group.schema.json'; +import { createPropsResolver } from '@/components/dynamic-resolver'; export type CheckboxItem = { disabled: boolean; @@ -36,7 +40,7 @@ export const checkboxGroupProps = { textField: { type: String, default: 'text' }, showDisabledItem: { type: Boolean, default: true }, -}; +} as Record; export type CheckboxGroupProps = ExtractPropTypes; @@ -45,3 +49,6 @@ export type CheckboxGroupContext = { getChecked: (name: any) => boolean; updateChecked: (value: string | number, checked: boolean) => void; }; + +export const propsResolver = createPropsResolver(checkboxGroupProps, inputSchema, schemaMapper, schemaResolver); + diff --git a/packages/mobile-ui-vue/components/checkbox-group/src/designer/checkbox-group.design.component.tsx b/packages/mobile-ui-vue/components/checkbox-group/src/designer/checkbox-group.design.component.tsx new file mode 100644 index 00000000000..23b094b47ee --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox-group/src/designer/checkbox-group.design.component.tsx @@ -0,0 +1,74 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; +import { CheckboxGroup, checkboxGroupProps, CheckboxGroupProps } from '../..'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas'; +import { useCheckBoxGroupProperty } from './use-designer-rules';; + +export default defineComponent({ + name: 'FmEnumFieldInputDesign', + props: checkboxGroupProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: CheckboxGroupProps, context: SetupContext) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useCheckBoxGroupProperty(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + /** + * 解决在设计时,数据为空数组,界面不显示内容的问题 + */ + const realEnumData = computed(() => { + if (!props.options || props.options.length === 0) { + const result = [] as any; + [ + { value: 'example1', name: '示例一' }, + { value: 'example2', name: '示例二' } + ].map(item => { + const tempData = {}; + tempData[props.valueField] = item['value']; + tempData[props.textField] = item['name']; + result.push(tempData); + }); + return result; + } + return props.options; + }); + + const inputGroupProps = computed(() => ({ + ...props, + editable: false, + readonly: true, + modelValue:null, + options:realEnumData.value, + type:null + })); + + context.expose(componentInstance.value); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/checkbox-group/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/checkbox-group/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..4ced3151e4b --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox-group/src/designer/use-designer-rules.ts @@ -0,0 +1,15 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { CheckBoxGroupProperty } from "../property-config/checkbox-group.property-config"; +export function useCheckBoxGroupProperty(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const radioGroupProps = new CheckBoxGroupProperty(componentId, designerHostService); + return radioGroupProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/checkbox-group/src/property-config/checkbox-group.property-config.ts b/packages/mobile-ui-vue/components/checkbox-group/src/property-config/checkbox-group.property-config.ts new file mode 100644 index 00000000000..12eba097050 --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox-group/src/property-config/checkbox-group.property-config.ts @@ -0,0 +1,48 @@ +import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; + +export class CheckBoxGroupProperty extends InputBaseProperty { + + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + + getEditorProperties(propertyData: any) { + const self = this; + const editorProperties = self.getComponentConfig(propertyData, { type: "radio-group" }, { + direction: { + description: "", + title: "排列方向", + type: "enum", + editor: { + type: "combo-list", + textField: "value", + valueField: "key", + data: [{ "key": "horizontal", "value": "横向" }, { "key": "vertical", "value": "纵向" }] + } + }, + data: { + description: "", + title: "数据", + type: "array", + $converter: "/converter/enum-data.converter", + ...self.getItemCollectionEditor(propertyData, propertyData.editor.valueField, propertyData.editor.textField), + // 这个属性,标记当属性变更得时候触发重新更新属性 + refreshPanelAfterChanged: true, + } + }); + editorProperties['setPropertyRelates'] = function (changeObject) { + if (!changeObject) { + return; + } + switch (changeObject.propertyID) { + case 'data': { + + break; + } + } + }; + return editorProperties; + } + +} diff --git a/packages/mobile-ui-vue/components/checkbox-group/src/schema/checkbox-group.schema.json b/packages/mobile-ui-vue/components/checkbox-group/src/schema/checkbox-group.schema.json new file mode 100644 index 00000000000..7cbd3c17fe8 --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox-group/src/schema/checkbox-group.schema.json @@ -0,0 +1,78 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/check-group.schema.json", + "title": "check-group", + "description": "A Farris Input Component", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a Input Group", + "type": "string" + }, + "type": { + "description": "The type string of Input Group component", + "type": "string", + "default": "check-group" + }, + "appearance": { + "description": "", + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "default": {} + }, + "binding": { + "description": "", + "type": "object", + "default": {} + }, + "readonly": { + "type": "string", + "default": false + }, + "title": { + "description": "", + "type": "string", + "default": "" + }, + "label": { + "description": "", + "type": "string", + "default": "" + }, + "lableWidth": { + "description": "", + "type": "number" + }, + "visible": { + "description": "", + "type": "boolean", + "default": true + }, + "data": { + "description": "", + "type": "array", + "default": [] + }, + "direction": { + "description": "", + "type": "string", + "default": "horizontal" + } + }, + "required": [ + "type" + ], + "ignore": [ + "id", + "appearance", + "binding", + "visible" + ] +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-mapper.ts new file mode 100644 index 00000000000..d8ccde7885d --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-mapper.ts @@ -0,0 +1,7 @@ +import { MapperFunction, resolveAppearance, resolveData } from '@/components/dynamic-resolver'; + +export const schemaMapper = new Map([ + ['appearance', resolveAppearance], + ['data', resolveData], +]); + diff --git a/packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-resolver.ts b/packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-resolver.ts new file mode 100644 index 00000000000..660e1e609e1 --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox-group/src/schema/schema-resolver.ts @@ -0,0 +1,5 @@ +import { DynamicResolver } from "@/components/dynamic-resolver"; + +export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record): Record { + return schema; +} diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx b/packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx index a0aa71bb439..6ebdca0fc0f 100644 --- a/packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx +++ b/packages/mobile-ui-vue/components/date-picker-input/src/designer/date-picker.design.component.tsx @@ -41,8 +41,8 @@ export default defineComponent({ const inputProps = computed(() => ({ ...props, editable: false, - readonly: true - + readonly: true, + modelValue:null })); return () => { diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-format.ts b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-format.ts new file mode 100644 index 00000000000..7a962b1db6a --- /dev/null +++ b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-format.ts @@ -0,0 +1,79 @@ +export function DATE_FORMATS() { + + let languageCode = 'zh-CHS'; + if (window && window.top && window.top.localStorage && window.top.localStorage.languageCode) { + ({ languageCode } = window.top.localStorage); + } + + const timeFormats = [ + { id: 'yyyy-MM-dd HH:mm:ss', name: 'yyyy-MM-dd HH:mm:ss' }, + { id: 'yyyy/MM/dd HH:mm:ss', name: 'yyyy/MM/dd HH:mm:ss' }, + { id: 'yyyyMMddHHmmss', name: 'yyyyMMddHHmmss' }, + { id: 'yyyy-MM-dd HH:mm', name: 'yyyy-MM-dd HH:mm' }, + { id: 'yyyy/MM/dd HH:mm', name: 'yyyy/MM/dd HH:mm' }, + { id: 'yyyyMMddHHmm', name: 'yyyyMMddHHmm' } + ]; + const yMdFormats = [ + { id: 'yyyy-MM-dd', name: 'yyyy-MM-dd' }, + { id: 'yyyy/MM/dd', name: 'yyyy/MM/dd' }, + { id: 'yyyyMMdd', name: 'yyyyMMdd' }, + { id: 'MM/dd/yyyy', name: 'MM/dd/yyyy' } + ]; + const yMFormats = [ + { id: 'yyyy-MM', name: 'yyyy-MM' }, + { id: 'yyyy/MM', name: 'yyyy/MM' }, + { id: 'yyyyMM', name: 'yyyyMM' } + ]; + + const mdFormats = [ + { id: 'MM/dd', name: 'MM/dd' }, + { id: 'MMdd', name: 'MMdd' }, + { id: 'MM-dd', name: 'MM-dd' } + ]; + + const yFormats = [ + { id: 'yyyy', name: 'yyyy' } + ]; + + // 区分语言 + if (languageCode === 'zh-CHS') { + timeFormats.push( + { id: 'yyyy年MM月dd日 HH时mm分ss秒', name: 'yyyy年MM月dd日 HH时mm分ss秒' }, + { id: 'yyyy年MM月dd日 HH时mm分', name: 'yyyy年MM月dd日 HH时mm分' } + ); + yMdFormats.push( + { id: 'yyyy年MM月dd日', name: 'yyyy年MM月dd日' } + ); + yMFormats.push( + { id: 'yyyy年MM月', name: 'yyyy年MM月' } + ); + mdFormats.push( + { id: 'MM月dd日', name: 'MM月dd日' } + ); + yFormats.push( + { id: 'yyyy年', name: 'yyyy年' } + ); + } + if (languageCode === 'zh-CHT') { + timeFormats.push( + { id: 'yyyy年MM月dd日 HH時mm分ss秒', name: 'yyyy年MM月dd日 HH時mm分ss秒' }, + { id: 'yyyy年MM月dd日 HH時mm分', name: 'yyyy年MM月dd日 HH時mm分' } + ); + yMdFormats.push( + { id: 'yyyy年MM月dd日', name: 'yyyy年MM月dd日' } + ); + yMFormats.push( + { id: 'yyyy年MM月', name: 'yyyy年MM月' } + ); + mdFormats.push( + { id: 'MM月dd日', name: 'MM月dd日' } + ); + yFormats.push( + { id: 'yyyy年', name: 'yyyy年' } + ); + } + + + return { timeFormats, yMFormats, yMdFormats, mdFormats, yFormats }; + +} diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts index 4f7ea85b3a5..0dad89b0fb1 100644 --- a/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts +++ b/packages/mobile-ui-vue/components/date-picker-input/src/property-config/date-picker.property-config.ts @@ -1,4 +1,5 @@ import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; +import { DATE_FORMATS } from "./date-format"; export class DatePickerProperty extends InputBaseProperty { @@ -8,56 +9,36 @@ export class DatePickerProperty extends InputBaseProperty { getEditorProperties(propertyData: any) { - const displayFormatOptions = this.getAllShowType(); - const valueFormatOptions = this.getAllFormat(); + const displayFormatOptions = this.getDateFormatOptions(propertyData?.editor); return this.getComponentConfig(propertyData, { type: "year-month-day" }, { placeholder: { description: "空值时,输入控件内的占位文本", title: "提示文本", type: "string" }, - showType: { - description: "", - title: "选择类型", - type: "enum", - editor: { - data: displayFormatOptions - } - }, - format: { + displayFormat: { description: "", title: "显示格式", type: "enum", editor: { - data: valueFormatOptions + data: displayFormatOptions } } }); } - private getAllShowType() { - return [ - { id: "year", name: "年月日" }, - { id: "datetime", name: "年月日时分" }, - { id: "datehour", name: "年月日时" }, - { id: "year-month", name: "年月" }, - { id: "month-day", name: "月日" } - ]; - } + private getDateFormatOptions(editorData: any) { + let formats: any[] = []; + const { timeFormats, yMdFormats, yMFormats, mdFormats, yFormats } = DATE_FORMATS(); - /** - * 存储格式枚举项 - */ - getAllFormat(): any[] { - return [ - { id: 'YYYY-MM-dd HH:mm', name: 'YYYY-MM-dd HH:mm' }, - { id: 'MM/dd/YYYY HH:mm', name: 'MM/dd/YYYY HH:mm' }, - { id: 'YYYY年MM月dd日 HH:mm', name: 'YYYY年MM月dd日 HH:mm' }, - { id: 'YYYY-MM-dd HH:mm:ss', name: 'YYYY-MM-dd HH:mm:ss' }, - { id: 'MM/dd/YYYY HH:mm:ss', name: 'MM/dd/YYYY HH:mm:ss' }, - { id: 'YYYY年MM月dd日 HH:mm:ss', name: 'YYYY年MM月dd日 HH:mm:ss' }, - ]; - } + formats = formats.concat(timeFormats); + formats = formats.concat(yMdFormats); + formats = formats.concat(yMFormats); + formats = formats.concat(yFormats); + formats = formats.concat(mdFormats); + + return formats; + } } diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts index abb57152ea8..ea8ec8b6d82 100644 --- a/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts +++ b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema-mapper.ts @@ -1,5 +1,6 @@ import { MapperFunction, resolveAppearance } from '@/components/dynamic-resolver'; export const schemaMapper = new Map([ - ['appearance', resolveAppearance] + ['appearance', resolveAppearance], + ['displayFormat','format'] ]); diff --git a/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json index a98542bf4ee..1674a23b089 100644 --- a/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json +++ b/packages/mobile-ui-vue/components/date-picker-input/src/schema/schema.json @@ -32,10 +32,6 @@ "type": "object", "default": {} }, - "disable": { - "type": "string", - "default": false - }, "title": { "description": "", "type": "string", @@ -59,14 +55,24 @@ "description": "", "type": "boolean", "default": true + }, + "displayFormat": { + "description": "", + "type": "string", + "default": "YYYY-MM-DD" + }, + "readonly": { + "type": "string", + "default": false } }, "required": [ + "type" + ], + "ignore": [ "id", - "type", - "visible", - "label", - "placeholder", - "appearance" + "appearance", + "binding", + "visible" ] } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts b/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts index 474da277cb0..8c1e55a382d 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts +++ b/packages/mobile-ui-vue/components/designer-canvas/src/components/maps.ts @@ -1,10 +1,10 @@ -import { ContentContainer, DatePickerInput, FormItem, PageHeaderContainer, RadioGroup } from "@/components"; +import { CheckboxGroup, ContentContainer, DatePickerInput, FormItem, PageHeaderContainer, PickerInput, RadioGroup, Switch } from "@/components"; import Button from "@/components/button"; import Component from "@/components/component"; import FloatContainer from "@/components/float-container"; import Form from "@/components/form"; import InputGroup from "@/components/input-group"; -import { ListView } from "@/components/list-view"; +import ListView from "@/components/list-view"; import Navbar from "@/components/navbar"; import PageBodyContainer from "@/components/page-body-container"; import PageContainer from "@/components/page-container"; @@ -39,7 +39,10 @@ function loadDesignerRegister() { DatePickerInput.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); Textarea.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); RadioGroup.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); - + Switch.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + PickerInput.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + CheckboxGroup.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + } } diff --git a/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts b/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts index e3d215a7141..bc35a129a09 100644 --- a/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts +++ b/packages/mobile-ui-vue/components/designer-canvas/src/composition/dg-control.ts @@ -43,4 +43,6 @@ export const DgControl = { 'navigation-bar': { type: 'navigation-bar', name: '导航栏', icon: 'NavBar' }, + 'enum-field': { type: 'enum-field', name: '选择器', icon: 'EnumField' }, + }; diff --git a/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json index 3f3386d8a1d..e160cd632e8 100644 --- a/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json +++ b/packages/mobile-ui-vue/components/designer-toolbox/src/toolbox.json @@ -1,4 +1,24 @@ [ + { + "type": "basic", + "name": "基础类控件", + "items": [ + { + "id": "Button", + "type": "button", + "name": "按钮", + "category": "basic", + "icon": "button" + }, + { + "id": "ButtonGroup", + "type": "button-group", + "name": "按钮组", + "category": "basic", + "icon": "button-group" + } + ] + }, { "type": "input", "name": "输入类控件", @@ -6,80 +26,71 @@ { "id": "TextBox", "type": "input-group", - "name": "文本", - "category": "input" + "name": "文本框", + "category": "input", + "icon": "input-group" }, { "id": "MultiTextBox", "type": "textarea", "name": "多行文本", - "category": "input" + "category": "input", + "icon": "textarea" }, { "id": "DateBox", "type": "date-picker", - "name": "日期", - "category": "input" + "name": "日期选择", + "category": "input", + "icon": "date-picker" }, { "id": "EnumField", - "type": "combo-list", - "name": "下拉列表", - "category": "input" + "type": "enum-field", + "name": "选择器", + "category": "input", + "icon": "input-group" }, { "id": "NumericBox", "type": "number-spinner", "name": "数值", - "category": "input" + "category": "input", + "icon": "number-spinner" }, { - "id": "CheckBox", - "type": "check-box", - "name": "复选框", - "category": "input" + "id": "RadioGroup", + "type": "radio-group", + "name": "单选组", + "category": "input", + "icon": "radio-group" }, { "id": "CheckBoxGroup", "type": "check-group", "name": "复选框组", - "category": "input" - }, - { - "id": "RadioGroup", - "type": "radio-group", - "name": "单选组", - "category": "input" + "category": "input", + "icon": "check-group" }, { "id": "SwitchField", "type": "switch", "name": "开关", - "category": "input" - }, - { - "id": "LookupEdit", - "type": "lookup", - "name": "帮助", - "category": "input" + "category": "input", + "icon": "switch" } ] }, { - "type": "dataCollection", - "name": "数据集合类控件", + "type": "navigation", + "name": "导航类控件", "items": [ { - "id": "ResponseForm", - "type": "form", - "name": "卡片面板", - "category": "dataCollection" - }, - { - "id": "DataGrid", - "type": "data-grid", - "name": "表格", - "category": "dataCollection" + "id": "NavigationBar", + "type": "navigation-bar", + "name": "导航栏", + "category": "navigation", + "icon": "nav-tab" } ] }, @@ -88,22 +99,66 @@ "name": "容器类控件", "items": [ { - "id": "Tab", - "type": "tabs", - "name": "标签页区域", - "category": "container" + "id": "PageHeaderContainer", + "type": "page-header-container", + "name": "页头容器", + "category": "container", + "icon": "content-container" + }, + { + "id": "PageBodyContainer", + "type": "page-body-container", + "name": "页面主体容器", + "category": "container", + "icon": "content-container" + }, + { + "id": "PageFooterContainer", + "type": "page-footer-container", + "name": "页尾容器", + "category": "container", + "icon": "content-container" + }, + { + "id": "ContentContainer", + "type": "content-container", + "name": "通用容器", + "category": "container", + "icon": "content-container" + }, + { + "id": "FloatContainer", + "type": "float-container", + "name": "浮动容器", + "category": "container", + "icon": "content-container" + }, + { + "id": "Form", + "type": "form", + "name": "字段卡片", + "category": "container", + "icon": "response-form" + }, + { + "id": "Card", + "type": "card", + "name": "卡片", + "category": "container", + "icon": "section" } ] }, { - "type": "business", - "name": "业务类控件", + "type": "display", + "name": "展示类控件", "items": [ { - "id": "QuerySolution", - "type": "query-solution", - "name": "筛选方案", - "category": "container" + "id": "ListView", + "type": "list-view", + "name": "列表", + "category": "display", + "icon": "list-view" } ] } diff --git a/packages/mobile-ui-vue/components/dynamic-resolver/index.ts b/packages/mobile-ui-vue/components/dynamic-resolver/index.ts index 5ee690b0cd7..78edba9a400 100644 --- a/packages/mobile-ui-vue/components/dynamic-resolver/index.ts +++ b/packages/mobile-ui-vue/components/dynamic-resolver/index.ts @@ -2,6 +2,7 @@ export * from './src/types'; export * from './src/props-resolver'; export * from './src/common/appearance-resolver'; export * from './src/common/toolbar-resolver'; +export * from './src/common/data-resolver'; export * from './src/binding-resolver'; export * from './src/events-resolver'; export * from './src/selection-item-resolver'; @@ -10,4 +11,5 @@ export * from './src/visible-prop-resolver'; export * from './src/event-handler-resolver'; export * from './src/schema-resolver'; export * from './src/update-columns-resolver'; + export { propertyConfigSchemaMap,getPropertyConfigBySchema } from './src/property-config-resolver'; diff --git a/packages/mobile-ui-vue/components/dynamic-resolver/src/common/data-resolver.ts b/packages/mobile-ui-vue/components/dynamic-resolver/src/common/data-resolver.ts new file mode 100644 index 00000000000..1f3c9c55856 --- /dev/null +++ b/packages/mobile-ui-vue/components/dynamic-resolver/src/common/data-resolver.ts @@ -0,0 +1,52 @@ + +export function resolveData(key: string, datas: { name: string; value: string }[]) { + const result:{ text: string; value: string }[] = []; + + if(datas && datas.length > 0){ + datas.forEach((data) => { + const newData: { text: string; value: string } = { + text: '', + value: '' + }; + Object.keys(data).map(key => { + if (key === 'name') { + newData['text'] = data[key]; + }else{ + newData[key] = data[key]; + } + }); + + result.push(newData); + }) + } + + return { + options:result + }; +} + +export function resolveDataPicker(key: string, datas: { name: string; value: string }[]) { + const result:{ text: string; value: string }[] = []; + + if(datas && datas.length > 0){ + datas.forEach((data) => { + const newData: { text: string; value: string } = { + text: '', + value: '' + }; + Object.keys(data).map(key => { + if (key === 'name') { + newData['text'] = data[key]; + }else{ + newData[key] = data[key]; + } + }); + + result.push(newData); + }) + } + + return { + columns:result + }; +} 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 251d704b9ea..09d05afe132 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 @@ -29,7 +29,6 @@ export default defineComponent({ setup(props: FormItemProps, context: SetupContext) { const { slots, expose } = context; - const label = ref(props.label); const labelAlign = ref(props.labelAlign); const shouldShowRequired = ref(props.required); const { bem } = useBem(FORM_ITEM_NAME); @@ -49,7 +48,7 @@ export default defineComponent({ if (slots.label) { return [slots.label()]; } - return ; + return ; }; const contentClass = computed(() => { @@ -104,14 +103,6 @@ export default defineComponent({ }; }); - watch([ - () => props.label, - ], - ([newLabel])=>{ - label.value = newLabel; - } - - ) context.expose(componentInstance.value); diff --git a/packages/mobile-ui-vue/components/form-item/src/schema/form-item.schema.json b/packages/mobile-ui-vue/components/form-item/src/schema/form-item.schema.json index cf3da7f92db..e49a2109836 100644 --- a/packages/mobile-ui-vue/components/form-item/src/schema/form-item.schema.json +++ b/packages/mobile-ui-vue/components/form-item/src/schema/form-item.schema.json @@ -36,11 +36,17 @@ "description": "", "type": "obejct", "default": null + }, + "binding": { + "description": "", + "type": "object", + "default": {} } }, "required": [ "id", - "type" + "type", + "editor" ] } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx b/packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx index 10ef1a9b3f7..23cfa3fd840 100644 --- a/packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx +++ b/packages/mobile-ui-vue/components/input-group/src/designer/input-group.design.component.tsx @@ -34,16 +34,18 @@ export default defineComponent({ elementRef.value.componentInstance = componentInstance; }); - const inputGroupProps = computed(() => ({ - ...props, - editable: false - })); + const inputGroupProps = { + editable: false, + }; context.expose(componentInstance.value); return () => { return ( - + ); }; } diff --git a/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json b/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json index 03a53f1db63..260621d8ecf 100644 --- a/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json +++ b/packages/mobile-ui-vue/components/input-group/src/schema/input-group.schema.json @@ -74,9 +74,12 @@ "onUpdate:modelValue" ], "required": [ + "type" + ], + "ignore": [ "id", - "type", "appearance", - "binding" + "binding", + "visible" ] } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/picker-input/index.ts b/packages/mobile-ui-vue/components/picker-input/index.ts index 1bc59b23dd9..02d38dfc325 100644 --- a/packages/mobile-ui-vue/components/picker-input/index.ts +++ b/packages/mobile-ui-vue/components/picker-input/index.ts @@ -1,10 +1,24 @@ import { withInstall } from '@components/common'; import PickerInputInstallless from "./src/picker-input.component"; +import { propsResolver } from './src/picker-input.props'; +import EnumFieldInputDesign from './src/designer/enum-field-input.design.component'; export * from './src/picker-input.props'; export * from './src/composition/use-picker-input-state'; + +const ENUM_FIELD_REGISTERED_NAME = 'enum-field'; + const PickerInput = withInstall(PickerInputInstallless); +PickerInput.register = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record) => { + componentMap[ENUM_FIELD_REGISTERED_NAME] = PickerInput; + propsResolverMap[ENUM_FIELD_REGISTERED_NAME] = propsResolver; +}; +PickerInput.registerDesigner = (componentMap: Record, propsResolverMap: Record, configResolverMap: Record) => { + componentMap[ENUM_FIELD_REGISTERED_NAME] = EnumFieldInputDesign; + propsResolverMap[ENUM_FIELD_REGISTERED_NAME] = propsResolver; +}; + export { PickerInput }; export default PickerInput; diff --git a/packages/mobile-ui-vue/components/picker-input/src/designer/enum-field-input.design.component.tsx b/packages/mobile-ui-vue/components/picker-input/src/designer/enum-field-input.design.component.tsx new file mode 100644 index 00000000000..d2cbcd7b2c0 --- /dev/null +++ b/packages/mobile-ui-vue/components/picker-input/src/designer/enum-field-input.design.component.tsx @@ -0,0 +1,74 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; +import { PickerInput, pickerInputProps, PickerInputProps } from '../..'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas'; +import { useEnumFieldDesignerRules } from './use-designer-rules';; + +export default defineComponent({ + name: 'FmEnumFieldInputDesign', + props: pickerInputProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: PickerInputProps, context: SetupContext) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useEnumFieldDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + /** + * 解决在设计时,数据为空数组,界面不显示内容的问题 + */ + const realEnumData = computed(() => { + if (!props.columns || props.columns.length === 0) { + const result = [] as any; + [ + { value: 'example1', name: '示例一' }, + { value: 'example2', name: '示例二' } + ].map(item => { + const tempData = {}; + tempData[props.valueField] = item['value']; + tempData[props.textField] = item['name']; + result.push(tempData); + }); + return result; + } + return props.columns; + }); + + const inputGroupProps = computed(() => ({ + ...props, + editable: false, + readonly: true, + modelValue:null, + columns:realEnumData.value, + type:null + })); + + context.expose(componentInstance.value); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/picker-input/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/picker-input/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..2257102f287 --- /dev/null +++ b/packages/mobile-ui-vue/components/picker-input/src/designer/use-designer-rules.ts @@ -0,0 +1,15 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { EnumFieldInputProperty } from "../property-config/enum-field-input.property-config"; +export function useEnumFieldDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const radioGroupProps = new EnumFieldInputProperty(componentId, designerHostService); + return radioGroupProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/picker-input/src/picker-input.props.ts b/packages/mobile-ui-vue/components/picker-input/src/picker-input.props.ts index b0344b4a669..20230bd4f50 100644 --- a/packages/mobile-ui-vue/components/picker-input/src/picker-input.props.ts +++ b/packages/mobile-ui-vue/components/picker-input/src/picker-input.props.ts @@ -1,12 +1,18 @@ import { ExtractPropTypes } from 'vue'; import { buttonEditProps } from '@/components/button-edit'; import { pickerProps } from '@/components/picker'; +import { createPropsResolver } from '@/components/dynamic-resolver'; +import inputSchema from './schema/enum-field-input.schema.json'; +import { schemaMapper } from './schema/schema-mapper'; +import { schemaResolver } from './schema/schema-resolver'; export const PICKER_INPUT_NAME = 'FmPickerInput'; export const pickerInputProps = { ...buttonEditProps, ...pickerProps -}; +} as Record; export type PickerInputProps = ExtractPropTypes; + +export const propsResolver = createPropsResolver(pickerInputProps, inputSchema, schemaMapper, schemaResolver); diff --git a/packages/mobile-ui-vue/components/picker-input/src/property-config/enum-field-input.property-config.ts b/packages/mobile-ui-vue/components/picker-input/src/property-config/enum-field-input.property-config.ts new file mode 100644 index 00000000000..4c762434707 --- /dev/null +++ b/packages/mobile-ui-vue/components/picker-input/src/property-config/enum-field-input.property-config.ts @@ -0,0 +1,47 @@ +import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; + +export class EnumFieldInputProperty extends InputBaseProperty { + + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + + getEditorProperties(propertyData: any) { + const self = this; + const editorProperties = self.getComponentConfig(propertyData, { type: "radio-group" }, { + editable: { + description: "", + title: "允许编辑", + type: "boolean" + }, + enableClear: { + description: "", + title: "启用清空", + type: "boolean" + }, + data: { + description: "", + title: "数据", + type: "array", + $converter: "/converter/enum-data.converter", + ...self.getItemCollectionEditor(propertyData, propertyData.editor.valueField, propertyData.editor.textField), + // 这个属性,标记当属性变更得时候触发重新更新属性 + refreshPanelAfterChanged: true, + } + }); + editorProperties['setPropertyRelates'] = function (changeObject) { + if (!changeObject) { + return; + } + switch (changeObject.propertyID) { + case 'data': { + + break; + } + } + }; + return editorProperties; + } + +} diff --git a/packages/mobile-ui-vue/components/picker-input/src/schema/enum-field-input.schema.json b/packages/mobile-ui-vue/components/picker-input/src/schema/enum-field-input.schema.json new file mode 100644 index 00000000000..7cf654531f3 --- /dev/null +++ b/packages/mobile-ui-vue/components/picker-input/src/schema/enum-field-input.schema.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/enum-field.schema.json", + "title": "enum-field", + "description": "A Farris Input Component", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a Input Group", + "type": "string" + }, + "type": { + "description": "The type string of Input Group component", + "type": "string", + "default": "enum-field" + }, + "appearance": { + "description": "", + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "default": {} + }, + "binding": { + "description": "", + "type": "object", + "default": {} + }, + "readonly": { + "type": "string", + "default": false + }, + "title": { + "description": "", + "type": "string", + "default": "" + }, + "label": { + "description": "", + "type": "string", + "default": "" + }, + "lableWidth": { + "description": "", + "type": "number" + }, + "visible": { + "description": "", + "type": "boolean", + "default": true + }, + "data": { + "description": "", + "type": "array", + "default": [] + }, + "enableClear": { + "description": "", + "type": "boolean", + "default": false + }, + "editable": { + "description": "", + "type": "boolean", + "default": false + } + }, + "required": [ + "type" + ], + "ignore": [ + "id", + "appearance", + "binding", + "visible" + ] +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/picker-input/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/picker-input/src/schema/schema-mapper.ts new file mode 100644 index 00000000000..36cb118f9ce --- /dev/null +++ b/packages/mobile-ui-vue/components/picker-input/src/schema/schema-mapper.ts @@ -0,0 +1,7 @@ +import { MapperFunction, resolveAppearance, resolveDataPicker } from '@/components/dynamic-resolver'; + +export const schemaMapper = new Map([ + ['appearance', resolveAppearance], + ['data', resolveDataPicker], +]); + diff --git a/packages/mobile-ui-vue/components/picker-input/src/schema/schema-resolver.ts b/packages/mobile-ui-vue/components/picker-input/src/schema/schema-resolver.ts new file mode 100644 index 00000000000..660e1e609e1 --- /dev/null +++ b/packages/mobile-ui-vue/components/picker-input/src/schema/schema-resolver.ts @@ -0,0 +1,5 @@ +import { DynamicResolver } from "@/components/dynamic-resolver"; + +export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record): Record { + return schema; +} diff --git a/packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx b/packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx index ab423e6c767..414ef0c02fb 100644 --- a/packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx +++ b/packages/mobile-ui-vue/components/radio-group/src/designer/radio-group.design.component.tsx @@ -15,10 +15,9 @@ * limitations under the License. */ import { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; -import RadioGroup, { RadioGroupProps, radioGroupProps } from '../..'; +import { RadioGroup, RadioGroupProps, radioGroupProps } from '../..'; import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas'; import { useRadioGroupDesignerRules } from './use-designer-rules'; -; export default defineComponent({ name: 'FmRadioGroupDesign', @@ -35,21 +34,33 @@ export default defineComponent({ elementRef.value.componentInstance = componentInstance; }); + /** + * 解决在设计时,数据为空数组,界面不显示内容的问题 + */ + const realEnumData = computed(() => { + if (!props.options || props.options.length === 0) { + const result = [] as any; + [ + { value: 'example1', name: '示例一' }, + { value: 'example2', name: '示例二' } + ].map(item => { + const tempData = {}; + tempData[props.valueField] = item['value']; + tempData[props.textField] = item['name']; + result.push(tempData); + }); + return result; + } + return props.options; + }); + const inputGroupProps = computed(() => ({ ...props, editable: false, - // options:[{ - // disabled: false, - // readonly: false, - // value: '1', - // text: '选项1' - // },{ - // disabled: false, - // readonly: false, - // value: '1', - // text: '选项1' - // }], - // direction:'horizontal' + readonly: true, + modelValue:null, + options:realEnumData.value, + type:"default" })); context.expose(componentInstance.value); diff --git a/packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts b/packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts index d1b24caa387..2af44da90f9 100644 --- a/packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts +++ b/packages/mobile-ui-vue/components/radio-group/src/property-config/radio-group.property-config.ts @@ -10,11 +10,6 @@ export class RadioGroupProperty extends InputBaseProperty { getEditorProperties(propertyData: any) { const self = this; const editorProperties = self.getComponentConfig(propertyData, { type: "radio-group" }, { - placeholder: { - description: "空值时,输入控件内的占位文本", - title: "提示文本", - type: "string" - }, direction: { description: "", title: "排列方向", @@ -26,7 +21,7 @@ export class RadioGroupProperty extends InputBaseProperty { data: [{ "key": "horizontal", "value": "横向" }, { "key": "vertical", "value": "纵向" }] } }, - options: { + data: { description: "", title: "数据", type: "array", diff --git a/packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json b/packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json index c24da46e4b0..316b66fc68f 100644 --- a/packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json +++ b/packages/mobile-ui-vue/components/radio-group/src/schema/radio-group.schema.json @@ -32,10 +32,6 @@ "type": "object", "default": {} }, - "disable": { - "type": "string", - "default": false - }, "readonly": { "type": "string", "default": false @@ -59,7 +55,7 @@ "type": "boolean", "default": true }, - "options": { + "data": { "description": "", "type": "array", "default": [] @@ -71,13 +67,10 @@ } }, "required": [ - "type", - "options", - "direction" + "type" ], "ignore": [ "id", - "type", "appearance", "binding", "visible" diff --git a/packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts index abb57152ea8..84d9b46a457 100644 --- a/packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts +++ b/packages/mobile-ui-vue/components/radio-group/src/schema/schema-mapper.ts @@ -1,5 +1,6 @@ -import { MapperFunction, resolveAppearance } from '@/components/dynamic-resolver'; +import { MapperFunction, resolveAppearance, resolveData } from '@/components/dynamic-resolver'; export const schemaMapper = new Map([ - ['appearance', resolveAppearance] + ['appearance', resolveAppearance], + ['data', resolveData], ]); diff --git a/packages/mobile-ui-vue/components/switch/index.ts b/packages/mobile-ui-vue/components/switch/index.ts index 7c345e8c33f..bd7a3b611a2 100644 --- a/packages/mobile-ui-vue/components/switch/index.ts +++ b/packages/mobile-ui-vue/components/switch/index.ts @@ -1,7 +1,30 @@ import { withInstall } from '@components/common'; import SwitchInstallless from "./src/switch.component"; +import SwitchDesign from './src/designer/switch.design.component'; +import { propsResolver } from './src/switch.props'; + +export * from './src/switch.props'; + + +const SWITCH_REGISTERED_NAME = 'switch'; const Switch = withInstall(SwitchInstallless); +Switch.register = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[SWITCH_REGISTERED_NAME] = Switch; + propsResolverMap[SWITCH_REGISTERED_NAME] = propsResolver; +}; + +Switch.registerDesigner = ( + componentMap: Record, propsResolverMap: Record, + configResolverMap: Record, resolverMap: Record +) => { + componentMap[SWITCH_REGISTERED_NAME] = SwitchDesign; + propsResolverMap[SWITCH_REGISTERED_NAME] = propsResolver; +}; + export { Switch }; export default Switch; diff --git a/packages/mobile-ui-vue/components/switch/src/designer/switch.design.component.tsx b/packages/mobile-ui-vue/components/switch/src/designer/switch.design.component.tsx new file mode 100644 index 00000000000..c52eea1c84b --- /dev/null +++ b/packages/mobile-ui-vue/components/switch/src/designer/switch.design.component.tsx @@ -0,0 +1,51 @@ +/* eslint-disable no-use-before-define */ +/** + * 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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; +import { Switch, SwitchProps, switchProps } from '../..'; +import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@/components/designer-canvas';; +import { useInputGroupDesignerRules } from './use-designer-rules'; + +export default defineComponent({ + name: 'FmSwitchDesign', + props: switchProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: SwitchProps, context: SetupContext) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject('design-item-context') as DesignerItemContext; + const designerRulesComposition = useInputGroupDesignerRules(designItemContext, designerHostService); + const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + const inputGroupProps = computed(() => ({ + ...props, + editable: false, + modelValue:null + })); + + context.expose(componentInstance.value); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/switch/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/switch/src/designer/use-designer-rules.ts new file mode 100644 index 00000000000..7e3baaed1c1 --- /dev/null +++ b/packages/mobile-ui-vue/components/switch/src/designer/use-designer-rules.ts @@ -0,0 +1,15 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@/components/designer-canvas"; +import { SwitchProperty } from "../property-config/switch.property-config"; +export function useInputGroupDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const inputGroupProps = new SwitchProperty(componentId, designerHostService); + return inputGroupProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/switch/src/property-config/switch.property-config.ts b/packages/mobile-ui-vue/components/switch/src/property-config/switch.property-config.ts new file mode 100644 index 00000000000..0aa4d0bd192 --- /dev/null +++ b/packages/mobile-ui-vue/components/switch/src/property-config/switch.property-config.ts @@ -0,0 +1,55 @@ +import { InputBaseProperty } from "@/components/common/src/entity/input-base-property"; + +export class SwitchProperty extends InputBaseProperty { + + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + + getEditorProperties(propertyData: any) { + const self = this; + const editorProperties = self.getComponentConfig(propertyData, { type: "switch" }, { + onBackground: { + description: "", + title: "打开时背景色", + type: "string" + }, + offBackground: { + description: "", + title: "关闭时背景色", + type: "string" + }, + size: { + description: "", + title: "尺寸", + type: "number" + }, + // size:{ + // description: "", + // title: "尺寸", + // type: "enum", + // editor:{ + // data: [ + // { + // id: "small", + // name: "小号" + // }, + // { + // id: "medium", + // name: "中号" + // }, + // { + // id: "large", + // name: "大号" + // } + // ] + // } + // } + }); + + return editorProperties; + } + + +} diff --git a/packages/mobile-ui-vue/components/switch/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/switch/src/schema/schema-mapper.ts new file mode 100644 index 00000000000..df6c8b93d81 --- /dev/null +++ b/packages/mobile-ui-vue/components/switch/src/schema/schema-mapper.ts @@ -0,0 +1,9 @@ +import { resolveAppearance, MapperFunction } from '../../../dynamic-resolver'; + +export const schemaMapper = new Map([ + ['appearance', resolveAppearance], + ['binding', 'modelValue'], + ['offBackground', 'inactiveColor'], + ['onBackground', 'activeColor'] +]); + diff --git a/packages/mobile-ui-vue/components/switch/src/schema/schema-resolver.ts b/packages/mobile-ui-vue/components/switch/src/schema/schema-resolver.ts new file mode 100644 index 00000000000..b02bdf93eec --- /dev/null +++ b/packages/mobile-ui-vue/components/switch/src/schema/schema-resolver.ts @@ -0,0 +1,5 @@ +import { DynamicResolver } from "../../../dynamic-resolver"; + +export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record): Record { + return schema; +} diff --git a/packages/mobile-ui-vue/components/switch/src/schema/switch.schema.json b/packages/mobile-ui-vue/components/switch/src/schema/switch.schema.json new file mode 100644 index 00000000000..075e96d7a81 --- /dev/null +++ b/packages/mobile-ui-vue/components/switch/src/schema/switch.schema.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/switch.schema.json", + "title": "switch", + "description": "", + "type": "object", + "properties": { + "id": { + "description": "", + "type": "string" + }, + "type": { + "description": "", + "type": "string", + "default": "switch" + }, + "appearance": { + "description": "", + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "default": {} + }, + "binding": { + "description": "", + "type": "object", + "default": {} + }, + "onUpdate:modelValue": { + "description": "值变化事件", + "type": "string", + "default": "" + }, + "disable": { + "type": "string", + "default": false + }, + "readonly": { + "type": "string", + "default": false + }, + "title": { + "description": "", + "type": "string", + "default": "" + }, + "label": { + "description": "", + "type": "string", + "default": "" + }, + "lableWidth": { + "description": "", + "type": "number" + }, + "visible": { + "description": "", + "type": "boolean", + "default": true + }, + "onBackground": { + "description": "", + "type": "string", + "default": "" + }, + "offBackground": { + "description": "", + "type": "string", + "default": "" + }, + "size": { + "description": "", + "type": "number", + "default": 22 + } + }, + "events": [ + "onUpdate:modelValue" + ], + "required": [ + "type" + ], + "ignore": [ + "id", + "appearance", + "binding", + "visible" + ] +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/switch/src/switch.props.ts b/packages/mobile-ui-vue/components/switch/src/switch.props.ts index 74624f834b5..d208781ec45 100644 --- a/packages/mobile-ui-vue/components/switch/src/switch.props.ts +++ b/packages/mobile-ui-vue/components/switch/src/switch.props.ts @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { createPropsResolver } from '@/components/dynamic-resolver'; import { ExtractPropTypes } from 'vue'; +import switchSchema from './schema/switch.schema.json'; +import { schemaMapper } from './schema/schema-mapper'; +import { schemaResolver } from './schema/schema-resolver'; export const switchProps = { modelValue: { type: Boolean, default: false }, @@ -36,3 +40,10 @@ export const switchProps = { }; export type SwitchProps = ExtractPropTypes; + +export const propsResolver = createPropsResolver( + switchProps, + switchSchema, + schemaMapper, + schemaResolver +); diff --git a/packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx b/packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx index 9302b3507b3..15ed5219669 100644 --- a/packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx +++ b/packages/mobile-ui-vue/components/textarea/src/designer/textarea.design.component.tsx @@ -37,7 +37,8 @@ export default defineComponent({ const inputGroupProps = computed(() => ({ ...props, - editable: false + editable: false, + modelValue:null })); context.expose(componentInstance.value); diff --git a/packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts b/packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts index 7269a0228aa..3db2084f9a3 100644 --- a/packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts +++ b/packages/mobile-ui-vue/components/textarea/src/property-config/textarea.property-config.ts @@ -22,10 +22,15 @@ export class TextareaProperty extends InputBaseProperty { nullable:true } }, - showWordLimit: { + showCount: { description: "", title: "展示输入文本数量", type: "boolean" + }, + maxLength: { + description: "", + title: "文本最大长度", + type: "number" } }); } diff --git a/packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json b/packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json index 1425b3ede9c..577a7d531f6 100644 --- a/packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json +++ b/packages/mobile-ui-vue/components/textarea/src/schema/input.schema.json @@ -32,42 +32,46 @@ "type": "object", "default": {} }, - "disable": { - "type": "string", - "default": false - }, "readonly": { "type": "string", "default": false }, - "title": { + "label": { "description": "", "type": "string", "default": "" }, - "label": { + "placeholder": { "description": "", "type": "string", "default": "" }, - "lableWidth": { + "visible": { "description": "", - "type": "number" + "type": "boolean", + "default": true }, - "placeholder": { + "rows": { "description": "", - "type": "string", + "type": "number", "default": "" }, - "visible": { + "showCount": { "description": "", "type": "boolean", "default": true + }, + "maxLength": { + "description": "", + "type": "number", + "default": 50 } }, "required": [ + "type" + ], + "ignore": [ "id", - "type", "appearance", "binding", "visible" diff --git a/packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts index abb57152ea8..acb5af1fe4f 100644 --- a/packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts +++ b/packages/mobile-ui-vue/components/textarea/src/schema/schema-mapper.ts @@ -1,5 +1,7 @@ import { MapperFunction, resolveAppearance } from '@/components/dynamic-resolver'; export const schemaMapper = new Map([ - ['appearance', resolveAppearance] + ['appearance', resolveAppearance], + ['showCount','showWordLimit'], + ['maxLength','maxlength'] ]); -- Gitee From fd0ed38c9c60a37de30a90e1239c503aa8228536 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Thu, 27 Feb 2025 15:16:52 +0800 Subject: [PATCH 04/34] =?UTF-8?q?chore:=E7=A7=BB=E5=8A=A8=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E8=AE=BE=E8=AE=A1=E6=97=B6=E7=BB=84=E4=BB=B6=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/designer/button.design.component.tsx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx b/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx index 2e886c10725..58b8267ebd8 100644 --- a/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx +++ b/packages/mobile-ui-vue/components/button/src/designer/button.design.component.tsx @@ -30,28 +30,27 @@ export default defineComponent({ const designItemContext = inject('design-item-context') as DesignerItemContext; const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); - + onMounted(() => { elementRef.value.componentInstance = componentInstance; }); context.expose(componentInstance.value); - const{ schema } = componentInstance.value; + const { schema } = componentInstance.value; - const inputProps = computed(() => ({ - ...props, + const buttonProps = computed(() => ({ + round: props.round, + block: props.block, + icon: props.icon, + type: props.type, })); return () => { return ( - schema.text ? - - : - + ); }; } -- Gitee From 252741a573b63bb67f45a76cd453ff0fd97e6074 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 4 Mar 2025 17:01:13 +0800 Subject: [PATCH 05/34] =?UTF-8?q?feature:=20=E6=94=AF=E6=8C=81=E7=BB=B4?= =?UTF-8?q?=E6=8A=A4=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/package.json | 2 +- .../composition/use-variable-data.ts | 199 ++++++++++++++++++ .../use-variable-datagrid-options.ts | 152 +++++++++++++ .../composition/use-variable-default-value.ts | 58 +++++ .../variable-manager.component.tsx | 102 +++++++++ .../variable-manager.props.ts | 7 + .../variable-manager/variable-manager.scss | 106 ++++++++++ .../view-model-designer.component.tsx | 11 +- .../designer/src/components/types/const.ts | 18 +- .../src/components/types/view-model.ts | 4 + 10 files changed, 646 insertions(+), 13 deletions(-) create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.props.ts create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.scss diff --git a/packages/designer/package.json b/packages/designer/package.json index 532fdd59fe6..ae954e68d4a 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -6,7 +6,7 @@ "dev": "vite --config ./vite.config.dev.ts", "build": "vue-tsc --noEmit && vite build --config ./vite.config.dev.ts", "preview": "vite preview --config ./vite.config.dev.ts", - "build:system": "farris-cli build -c ./vite.config.build.ts" + "build:system": "farris-cli build -c ./farris.config.mjs" }, "dependencies": { "@farris/ui-vue": "workspace:^", diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts new file mode 100644 index 00000000000..75ab58bee79 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -0,0 +1,199 @@ +import { inject, Ref, ref } from "vue"; +import { FormVariable, FormVariableCategory, FormViewModel, UseFormSchema } from "../../../../types"; +import { useVariableDefaultValue } from "./use-variable-default-value"; +import { FNotifyService } from "@farris/ui-vue"; +import { IdService } from "../../method-manager/service/id.service"; + +export function useVariableData(gridComponentInstance: Ref) { + + const useFormSchema = inject('useFormSchema') as UseFormSchema; + const formSchema = useFormSchema.getFormSchema(); + const notifyService: FNotifyService = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + const { resolveDefaultValueInEditor, resolveDefaultValueInViewModel } = useVariableDefaultValue(); + + const variableList = ref([]); + + /** + * 获取表单变量 + */ + function getRemoteVariables(): FormVariable[] { + const result: FormVariable[] = []; + const rootViewModel = formSchema.module.viewmodels[0]; + if (!rootViewModel || !rootViewModel.states) { + return result; + } + + const remoteVariables = rootViewModel.states.filter(state => state.category === FormVariableCategory.remote); + + remoteVariables.forEach(state => { + const nodeData = Object.assign({ + sourceName: '视图对象' + }, state); + + resolveDefaultValueInEditor(nodeData); + result.push(nodeData); + }); + + return result; + + } + + function getViewModelSourceName(viewModel: FormViewModel, state: FormVariable) { + // 表单变量来源于vo + if (state.category === FormVariableCategory.remote) { + return '视图对象'; + } + return '组件'; + // return getViewModelName(viewModel.id, viewModel.name); + } + + /** + * 获取组件变量 + */ + function getLocalVariables(): FormVariable[] { + const result: FormVariable[] = []; + + const viewmodelList = formSchema.module.viewmodels; + + viewmodelList.forEach(viewmodel => { + if (!viewmodel.states || !viewmodel.states.length) { + return; + } + const localVariables = viewmodel.states.filter(state => state.category === FormVariableCategory.locale); + + localVariables.forEach(state => { + const sourceName = getViewModelSourceName(viewmodel, state); + const nodeData = Object.assign({ viewModelId: viewmodel.id, sourceName }, state); + resolveDefaultValueInEditor(nodeData); + result.push(nodeData); + + }); + }); + + return result; + } + + /** + * 加载变量 + */ + function loadVariables() { + const remoteVariableList = getRemoteVariables(); + const loclVariableList = getLocalVariables(); + variableList.value = [...remoteVariableList, ...loclVariableList]; + } + + /** + * 检查变量编号是否唯一 + * @param formVariable + * @returns + */ + function checkUniqueCode(variable: FormVariable) { + if (!variable.code) { + return true; + } + const index = variableList.value.findIndex(variable => variable.code === variable.code + && variable.id !== variable.id); + if (index > -1) { + notifyService.warning('变量编号已存在,请修改。'); + return false; + } + return true; + } + + /** + * 删除变量 + * @returns + */ + function deleteVariables() { + const selectedVariables = gridComponentInstance.value.getSelectedItems(); + + if (!selectedVariables || !selectedVariables.length) { + notifyService.info('请勾选要删除的行'); + return; + } + + const remoteVariableIndex = selectedVariables.findIndex(selectedVariable => selectedVariable.category === FormVariableCategory.remote); + if (remoteVariableIndex > -1) { + notifyService.info('不可删除表单变量'); + } + + selectedVariables.forEach(selectedVariable => { + if (selectedVariable.category === FormVariableCategory.locale) { + variableList.value = variableList.value.filter(variable => variable.id !== selectedVariable.id); + + } + }); + + gridComponentInstance.value.updateDataSource(variableList.value); + gridComponentInstance.value.clearSelection(); + + } + + /** + * 添加变量到表格 + */ + function addVariableToDataGrid() { + variableList.value.push({ + id: new IdService().generate(), + type: 'String', + code: "", + name: "", + category: FormVariableCategory.locale + }); + gridComponentInstance.value.updateDataSource(variableList.value); + } + + /** + * 添加变量到视图模型 + * @param rowData + * @param changeObject + * @returns + */ + function addVariableToViewModel(variable: FormVariable, changeObject: { field: string, value: any }) { + // 校验不通过时,单元格重置为编辑态 + if (changeObject.field === 'code' && !checkUniqueCode(variable)) { + return; + } + const variablCode = variable.code && variable.code.trim(); + const variableName = variable.name && variable.name.trim(); + const variablValue = resolveDefaultValueInViewModel(variable); + if (!variablCode || !variableName || !variable.type) { + return; + } + + // 若当前行已填写完毕,则同步视图模型 + const viewModelId = variable.viewModelId || 'root-viewmodel'; + const viewmodel = useFormSchema.getViewModelById(viewModelId); + if (viewmodel) { + const variableInViewmodel = viewmodel.states.find(state => state.id === variable.id); + if (variableInViewmodel) { + Object.assign(variableInViewmodel, { + code: variablCode, + name: variableName, + type: variable.type, + value: variablValue + }); + } else { + viewmodel.states.push({ + id: variable.id, + code: variablCode, + name: variableName, + type: variable.type, + category: variable.category, + value: variablValue + }); + } + } + // this.syncFormControlsBindingVariable(rowData, changeObject); + } + + return { + variableList, + loadVariables, + checkUniqueCode, + deleteVariables, + addVariableToDataGrid, + addVariableToViewModel + }; +} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts new file mode 100644 index 00000000000..a696178c893 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -0,0 +1,152 @@ +import { DataColumn, VisualData, VisualDataCell } from "@farris/ui-vue"; +import { FormVariableCategories, FormVariableTypes } from "../../../../../components/types"; +import { h, VNode } from "vue"; + +/** + * 获取表格配置 + * @returns + */ +export function useVariableDataGridOptions() { + + // 列配置 + const columnOption = { + fitColumns: true, + fitMode: 'percentage' + }; + + // 选择行配置 + const selectionOption = { + enableSelectRow: true, + multiSelect: true, + showCheckbox: true, + showSelectAll: true + }; + + function formatData(cell: VisualDataCell, row: VisualData) { + const { field, data } = cell; + + let displayText = data; + + if (field === 'type') { + const formVariableType = FormVariableTypes.find(c => c.value === data); + if (formVariableType) { + displayText = formVariableType.text; + } + } else if (field === 'category') { + const formVariableCategory = FormVariableCategories.find(c => c.value === data); + if (formVariableCategory) { + displayText = formVariableCategory.text; + + } + } + return displayText; + } + + function cellFormatter(cell: VisualDataCell, row: VisualData) { + const icons: VNode[] = []; + const { field, data } = cell; + + if (field === 'type') { + icons.push(h('span', { class: 'f-icon f-icon-drop-down_line' })); + } + if (['code', 'name', 'value'].includes(field) && row.raw.category === 'locale') { + icons.push(h('span', { class: 'f-icon f-icon-edit-cardview' })); + } + + return h('div', { class: 'cell-wrapper' }, [ + h('span', { class: 'shown-value', title: data }, formatData(cell, row)), + ...icons + ]); + } + + /** + * 表格列配置 + */ + const columns: DataColumn[] = [ + { + field: 'code', + title: "变量编号", + dataType: 'string', + width: 120, + resizable: true, + formatter: cellFormatter + }, + { + field: 'name', + title: "变量名称", + dataType: 'string', + width: 120, + resizable: true, + formatter: cellFormatter + + }, + { + field: 'type', + title: '变量类型', + dataType: 'enum', + valign: 'middle', + formatter: cellFormatter, + editor: { + type: 'combo-list', + data: [ + { id: 'String', name: '字符串' }, + { id: 'Number', name: '数字' }, + { id: 'Boolean', name: '布尔' }, + { id: 'Date', name: '日期' }, + { id: '日DateTime', name: '期时间' }, + { id: 'Text', name: '文本' }, + { id: 'Object', name: '对象' }, + { id: 'Array', name: '数组' } + ], + } + }, + { + field: 'value', + title: "默认值", + dataType: 'string', + width: 120, + resizable: true, + formatter: cellFormatter, + }, + { + field: 'category', + title: "变量类型", + formatter: { + type: 'enum', + data: [ + { value: 'locale', name: '组件变量' }, + { value: 'remote', name: '表单变量' }, + ], + }, + editor: { + type: "combo-list", + valueField: 'id', + textField: 'name', + data: [ + { id: 'locale', name: '组件变量' }, + { id: 'remote', name: '表单变量' }, + ] + }, + dataType: 'string', + width: 120, + resizable: true, + readonly: true + + }, + { + field: 'sourceName', + title: '来源', + dataType: 'string', + width: 120, + resizable: true, + readonly: true + } + ] + + + return { + columns, + columnOption, + selectionOption + }; +} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts new file mode 100644 index 00000000000..185375edb40 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts @@ -0,0 +1,58 @@ +import { FNotifyService } from "@farris/ui-vue"; +import { FormVariable } from "../../../../types"; + +export function useVariableDefaultValue() { + const notifyService: FNotifyService = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + + /** + * 将字符串类型的默认值转换为对象类型,用于DOM存储。 + */ + function resolveDefaultValueInViewModel(variable: FormVariable) { + if (variable.value === undefined || variable.value === null || variable.value === '') { + variable; + } + + if (variable.type === 'Object' || variable.type === 'Array') { + try { + return JSON.parse(variable.value); + + } catch (error) { + console.error(error); + notifyService.error('解析默认值失败'); + return; + } + } + if (typeof (variable.value) === 'string') { + return variable.value.trim().replace(/'/g, ''); + } + return variable.value; + } + + + /** + * 将对象类型的默认值转换为字符串类型,用于列表编辑器显示。 + */ + function resolveDefaultValueInEditor(variable: FormVariable) { + if (!variable || !variable.value) { + return; + } + + if (variable.type === 'Object' || variable.type === 'Array') { + try { + variable.value = JSON.stringify(variable.value); + } catch (error) { + console.error(error); + notifyService.error('解析默认值失败'); + return; + } + } + } + + + return { + resolveDefaultValueInViewModel, + resolveDefaultValueInEditor + } + +} \ No newline at end of file diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx new file mode 100644 index 00000000000..ae3842eb680 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -0,0 +1,102 @@ +import { SetupContext, defineComponent, ref } from "vue"; +import { FDataGrid } from "@farris/ui-vue/components"; +import { variableManagerProps, VariableManagerProps } from "./variable-manager.props"; +import './variable-manager.scss'; +import { useVariableData } from "./composition/use-variable-data"; +import { useVariableDataGridOptions } from "./composition/use-variable-datagrid-options"; + +export default defineComponent({ + name: 'FVariableManager', + props: variableManagerProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: VariableManagerProps, context: SetupContext) { + + /** 表格实例 */ + const gridComponentInstance = ref(); + /** 表格配置 */ + const { columns, columnOption, selectionOption } = useVariableDataGridOptions(); + /** 变量数据相关方法 */ + const { variableList, loadVariables, deleteVariables, addVariableToDataGrid, addVariableToViewModel } = useVariableData(gridComponentInstance); + loadVariables(); + + /** + * 添加变量 + */ + function onAddVariable() { + addVariableToDataGrid(); + } + + /** + * 批量删除变量 + */ + function onDeleteVariables() { + deleteVariables(); + } + + /** + * 刷新表单变量 + */ + function onRefreshVariable() { + } + + /** + * 单元格结束编辑前事件, 用于检查输入内容是否合法 + * @param newVariableData + * @returns + */ + function beforeEndEditCell(newVariableData: any): boolean { + return true; + } + + /** + * 单元格结束编辑事件,用于更新变量到viewModel + * @param cell + */ + function onEndEditCell(cell: any) { + addVariableToViewModel(cell.row.raw, { + field: cell.column.field, + value: cell.newValue, + }); + }; + + return () => { + return ( +
+
+
+
+
+ 添加变量 +
+
+
+
+ 移除变量 +
+
+ +
+
+ 刷新 +
+
+
+ + +
+
+
+ ); + }; + } +}); diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.props.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.props.ts new file mode 100644 index 00000000000..41d8e3b3e8d --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.props.ts @@ -0,0 +1,7 @@ +import { ExtractPropTypes } from "vue"; + +export const variableManagerProps = { + schema: { type: Object, default: {} } +} as Record; + +export type VariableManagerProps = ExtractPropTypes; diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.scss b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.scss new file mode 100644 index 00000000000..2c71a362f88 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.scss @@ -0,0 +1,106 @@ +.f-variable-designer { + display: flex; + flex-grow: 1; + flex-basis: 0; + flex-direction: column !important; + flex-shrink: 1; + overflow: hidden; + height: 100%; + + .view-model-variable-list { + padding: 10px 15px; + } + + .cell-wrapper { + height: 100%; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 13px; + color: #424347; + } + + .cell-wrapper .f-icon { + color: #878D99; + } + + .cell-wrapper .shown-value { + text-overflow: ellipsis; + overflow: hidden; + } + + .view-model-toolbar { + display: flex; + align-items: center; + line-height: 18px; + color: #34495e; + padding-top: 14px; + padding-bottom: 16px; + + + .toolbar-item { + display: flex; + cursor: pointer; + } + + .toolbar-item .toolbar-item-icon { + position: relative; + height: 15px; + width: 15px; + border: 1px solid #5b89fe; + border-radius: 3px; + margin-right: 6px; + } + + .toolbar-item .toolbar-item-icon::after { + content: "T"; + position: absolute; + top: 0; + left: 2px; + font-size: 12px; + line-height: 12px; + color: #4e56c4; + } + + .toolbar-item .toolbar-item-icon::before { + font-family: FarrisIcons; + display: flex; + justify-content: center; + align-items: flex-end; + height: 10px; + width: 10px; + line-height: 8px; + color: #00cdba; + background-color: #fff; + position: absolute; + bottom: -2px; + right: -4px; + } + + .toolbar-item .toolbar-item-icon-add::before { + content: "\e11e"; + } + + .toolbar-item .toolbar-item-icon-delete::before { + content: "\e11b"; + color: #fa6c00; + } + + .toolbar-item .toolbar-item-icon-refresh::before { + content: "\e106"; + } + + .toolbar-item:hover { + color: #5B89FE; + } + + .toolbar-item-spilter { + width: 1px; + height: 12px; + margin: 0 10px; + background-image: linear-gradient(180deg, rgba(40, 60, 93, 0) 0%, rgba(40, 60, 93, 0.1) 23%, rgba(40, 60, 93, 0.1) 52%, rgba(40, 60, 93, 0.1) 84%, rgba(40, 60, 93, 0) 100%); + border-radius: 0.5px; + } + + } +} \ No newline at end of file diff --git a/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx b/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx index 1c66bd5e50d..e74634719da 100644 --- a/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx @@ -1,6 +1,7 @@ import { SetupContext, defineComponent, ref, computed } from "vue"; import { viewModelDesignerProps, ViewModelDesignerProps } from "./view-model-designer.props"; import FMethodManager from '../../components/view-model-designer/method-manager/method-manager.component'; +import FVariableManager from '../../components/view-model-designer/variable-manager/variable-manager.component'; import './view-model-designer.scss'; import { FNotifyService } from "@farris/ui-vue/components"; @@ -11,6 +12,8 @@ export default defineComponent({ emits: [], setup(props: ViewModelDesignerProps, context) { const methodMangerRef = ref(); + const variableMangerRef = ref(); + const selectedModelTab = ref('method'); const modelTabClass = computed(() => (modelType: string) => { return { active: selectedModelTab.value === modelType }; @@ -22,12 +25,7 @@ export default defineComponent({ if (modelType === selectedModelTab.value) { return; } - if (modelType === 'variable') { - const notifyService: any = new FNotifyService(); - notifyService.globalConfig = { position: 'top-center' }; - notifyService.warning('暂不支持'); - return; - } + selectedModelTab.value = modelType; } /** 刷新模型页 */ @@ -53,6 +51,7 @@ export default defineComponent({
+ ); diff --git a/packages/designer/src/components/types/const.ts b/packages/designer/src/components/types/const.ts index b93e2742fb3..b08009f9c24 100644 --- a/packages/designer/src/components/types/const.ts +++ b/packages/designer/src/components/types/const.ts @@ -21,12 +21,18 @@ export const MetadataPathToken = 'Metadata_Path_Token'; */ export const EntityFieldTypeDisplayNamei18n = { String: '字符串', - Number: '数字', + Number: '数字', BigNumber: '大数字', - Boolean: '布尔', - Date: '日期', - DateTime: '日期时间', - Text: '文本', - Enum: '枚举', + Boolean: '布尔', + Date: '日期', + DateTime: '日期时间', + Text: '文本', + Enum: '枚举', MultiLanguage: '多语言' }; + + +export const FormVariableCategories = [ + { text: '组件变量', value: 'locale' }, + { text: '表单变量', value: 'remote' }, +]; diff --git a/packages/designer/src/components/types/view-model.ts b/packages/designer/src/components/types/view-model.ts index ff51ab2dae8..d5ad5ee2b11 100644 --- a/packages/designer/src/components/types/view-model.ts +++ b/packages/designer/src/components/types/view-model.ts @@ -44,6 +44,10 @@ export interface FormVariable { category: FormVariableCategory; + sourceName?: string; + + viewModelId?: string; + fields?: any[]; } -- Gitee From 774f7408f68559cd5f9ed5f8910c3f3e1498d1dd Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 4 Mar 2025 17:17:39 +0800 Subject: [PATCH 06/34] =?UTF-8?q?chore:=20=E5=AE=8C=E5=96=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=88=97=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composition/use-variable-datagrid-options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts index a696178c893..a9e47a47d9e 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -93,7 +93,7 @@ export function useVariableDataGridOptions() { { id: 'Number', name: '数字' }, { id: 'Boolean', name: '布尔' }, { id: 'Date', name: '日期' }, - { id: '日DateTime', name: '期时间' }, + { id: 'DateTime', name: '日期时间' }, { id: 'Text', name: '文本' }, { id: 'Object', name: '对象' }, { id: 'Array', name: '数组' } -- Gitee From 175cb2ca8737d19249e1d84591fd38518342bb3e Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Wed, 5 Mar 2025 09:35:19 +0800 Subject: [PATCH 07/34] =?UTF-8?q?chore:=20=E5=AE=8C=E5=96=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E7=9B=B8=E5=85=B3=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composition/use-variable-data.ts | 83 ++++++++++--------- .../use-variable-datagrid-options.ts | 42 ++++++---- .../composition/use-variable-default-value.ts | 8 +- .../variable-manager.component.tsx | 4 +- 4 files changed, 78 insertions(+), 59 deletions(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts index 75ab58bee79..5e899694961 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -1,7 +1,7 @@ import { inject, Ref, ref } from "vue"; import { FormVariable, FormVariableCategory, FormViewModel, UseFormSchema } from "../../../../types"; import { useVariableDefaultValue } from "./use-variable-default-value"; -import { FNotifyService } from "@farris/ui-vue"; +import { FNotifyService } from "@farris/ui-vue/components"; import { IdService } from "../../method-manager/service/id.service"; export function useVariableData(gridComponentInstance: Ref) { @@ -11,6 +11,7 @@ export function useVariableData(gridComponentInstance: Ref) { const notifyService: FNotifyService = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; const { resolveDefaultValueInEditor, resolveDefaultValueInViewModel } = useVariableDefaultValue(); + const ROOT_VIEW_MODEL_ID = 'root-viewmodel'; const variableList = ref([]); @@ -26,22 +27,27 @@ export function useVariableData(gridComponentInstance: Ref) { const remoteVariables = rootViewModel.states.filter(state => state.category === FormVariableCategory.remote); - remoteVariables.forEach(state => { - const nodeData = Object.assign({ + remoteVariables.forEach(variable => { + const newVariable = Object.assign({ sourceName: '视图对象' - }, state); + }, variable); - resolveDefaultValueInEditor(nodeData); - result.push(nodeData); + resolveDefaultValueInEditor(newVariable); + result.push(newVariable); }); return result; } - function getViewModelSourceName(viewModel: FormViewModel, state: FormVariable) { - // 表单变量来源于vo - if (state.category === FormVariableCategory.remote) { + /** + * 获取视图模型变量来源名称 + * @param viewModel + * @param variable + * @returns + */ + function getViewModelSourceName(viewModel: FormViewModel, variable: FormVariable) { + if (variable.category === FormVariableCategory.remote) { return '视图对象'; } return '组件'; @@ -54,19 +60,19 @@ export function useVariableData(gridComponentInstance: Ref) { function getLocalVariables(): FormVariable[] { const result: FormVariable[] = []; - const viewmodelList = formSchema.module.viewmodels; + const viewModelList = formSchema.module.viewmodels; - viewmodelList.forEach(viewmodel => { - if (!viewmodel.states || !viewmodel.states.length) { + viewModelList.forEach(viewModel => { + if (!viewModel.states || !viewModel.states.length) { return; } - const localVariables = viewmodel.states.filter(state => state.category === FormVariableCategory.locale); + const localVariables = viewModel.states.filter(state => state.category === FormVariableCategory.locale); - localVariables.forEach(state => { - const sourceName = getViewModelSourceName(viewmodel, state); - const nodeData = Object.assign({ viewModelId: viewmodel.id, sourceName }, state); - resolveDefaultValueInEditor(nodeData); - result.push(nodeData); + localVariables.forEach(variable => { + const sourceName = getViewModelSourceName(viewModel, variable); + const newVariable = Object.assign({ viewModelId: viewModel.id, sourceName }, variable); + resolveDefaultValueInEditor(newVariable); + result.push(newVariable); }); }); @@ -79,21 +85,21 @@ export function useVariableData(gridComponentInstance: Ref) { */ function loadVariables() { const remoteVariableList = getRemoteVariables(); - const loclVariableList = getLocalVariables(); - variableList.value = [...remoteVariableList, ...loclVariableList]; + const localVariableList = getLocalVariables(); + variableList.value = [...remoteVariableList, ...localVariableList]; } /** * 检查变量编号是否唯一 - * @param formVariable + * @param variable * @returns */ function checkUniqueCode(variable: FormVariable) { if (!variable.code) { return true; } - const index = variableList.value.findIndex(variable => variable.code === variable.code - && variable.id !== variable.id); + const index = variableList.value.findIndex(currentVariable => currentVariable.code === variable.code + && currentVariable.id !== variable.id); if (index > -1) { notifyService.warning('变量编号已存在,请修改。'); return false; @@ -146,7 +152,7 @@ export function useVariableData(gridComponentInstance: Ref) { /** * 添加变量到视图模型 - * @param rowData + * @param variable * @param changeObject * @returns */ @@ -155,33 +161,32 @@ export function useVariableData(gridComponentInstance: Ref) { if (changeObject.field === 'code' && !checkUniqueCode(variable)) { return; } - const variablCode = variable.code && variable.code.trim(); + const variableCode = variable.code && variable.code.trim(); const variableName = variable.name && variable.name.trim(); - const variablValue = resolveDefaultValueInViewModel(variable); - if (!variablCode || !variableName || !variable.type) { + const variableValue = resolveDefaultValueInViewModel(variable); + if (!variableCode || !variableName || !variable.type) { return; } - // 若当前行已填写完毕,则同步视图模型 - const viewModelId = variable.viewModelId || 'root-viewmodel'; - const viewmodel = useFormSchema.getViewModelById(viewModelId); - if (viewmodel) { - const variableInViewmodel = viewmodel.states.find(state => state.id === variable.id); - if (variableInViewmodel) { - Object.assign(variableInViewmodel, { - code: variablCode, + const viewModelId = variable.viewModelId || ROOT_VIEW_MODEL_ID; + const viewModel = useFormSchema.getViewModelById(viewModelId); + if (viewModel) { + const variableInViewModel = viewModel.states.find(state => state.id === variable.id); + if (variableInViewModel) { + Object.assign(variableInViewModel, { + code: variableCode, name: variableName, type: variable.type, - value: variablValue + value: variableValue }); } else { - viewmodel.states.push({ + viewModel.states.push({ id: variable.id, - code: variablCode, + code: variableCode, name: variableName, type: variable.type, category: variable.category, - value: variablValue + value: variableValue }); } } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts index a9e47a47d9e..fc073a551bf 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -1,20 +1,19 @@ -import { DataColumn, VisualData, VisualDataCell } from "@farris/ui-vue"; +import { DataColumn, VisualData, VisualDataCell } from "@farris/ui-vue/components"; import { FormVariableCategories, FormVariableTypes } from "../../../../../components/types"; import { h, VNode } from "vue"; /** * 获取表格配置 - * @returns */ export function useVariableDataGridOptions() { - // 列配置 + /** 列配置 */ const columnOption = { fitColumns: true, fitMode: 'percentage' }; - // 选择行配置 + /** 选择行配置 */ const selectionOption = { enableSelectRow: true, multiSelect: true, @@ -22,18 +21,23 @@ export function useVariableDataGridOptions() { showSelectAll: true }; - function formatData(cell: VisualDataCell, row: VisualData) { - const { field, data } = cell; + /** + * 格式化单元格数据 + * @param visualDataCell + * @returns + */ + function formatCellData(visualDataCell: VisualDataCell) { + const { field, data } = visualDataCell; let displayText = data; if (field === 'type') { - const formVariableType = FormVariableTypes.find(c => c.value === data); + const formVariableType = FormVariableTypes.find(vriableType => vriableType.value === data); if (formVariableType) { displayText = formVariableType.text; } } else if (field === 'category') { - const formVariableCategory = FormVariableCategories.find(c => c.value === data); + const formVariableCategory = FormVariableCategories.find(variableCategory => variableCategory.value === data); if (formVariableCategory) { displayText = formVariableCategory.text; @@ -42,20 +46,26 @@ export function useVariableDataGridOptions() { return displayText; } - function cellFormatter(cell: VisualDataCell, row: VisualData) { - const icons: VNode[] = []; - const { field, data } = cell; + /** + * 单元格格式化,给单元格添加编辑或下拉图标 + * @param visualDataCell + * @param visualDataRow + * @returns + */ + function cellFormatter(visualDataCell: VisualDataCell, visualDataRow: VisualData) { + const iconsNode: VNode[] = []; + const { field, data } = visualDataCell; if (field === 'type') { - icons.push(h('span', { class: 'f-icon f-icon-drop-down_line' })); + iconsNode.push(h('span', { class: 'f-icon f-icon-drop-down_line' })); } - if (['code', 'name', 'value'].includes(field) && row.raw.category === 'locale') { - icons.push(h('span', { class: 'f-icon f-icon-edit-cardview' })); + if (['code', 'name', 'value'].includes(field) && visualDataRow.raw.category === 'locale') { + iconsNode.push(h('span', { class: 'f-icon f-icon-edit-cardview' })); } return h('div', { class: 'cell-wrapper' }, [ - h('span', { class: 'shown-value', title: data }, formatData(cell, row)), - ...icons + h('span', { class: 'shown-value', title: data }, formatCellData(visualDataCell)), + ...iconsNode ]); } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts index 185375edb40..015b984f7e2 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts @@ -1,4 +1,4 @@ -import { FNotifyService } from "@farris/ui-vue"; +import { FNotifyService } from "@farris/ui-vue/components"; import { FormVariable } from "../../../../types"; export function useVariableDefaultValue() { @@ -7,6 +7,8 @@ export function useVariableDefaultValue() { /** * 将字符串类型的默认值转换为对象类型,用于DOM存储。 + * @param variable + * @returns */ function resolveDefaultValueInViewModel(variable: FormVariable) { if (variable.value === undefined || variable.value === null || variable.value === '') { @@ -31,7 +33,9 @@ export function useVariableDefaultValue() { /** - * 将对象类型的默认值转换为字符串类型,用于列表编辑器显示。 + * 将对象类型的默认值转换为字符串类型,用于编辑器展示。 + * @param variable + * @returns */ function resolveDefaultValueInEditor(variable: FormVariable) { if (!variable || !variable.value) { diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index ae3842eb680..ae4efd2c5b3 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -44,12 +44,12 @@ export default defineComponent({ * @param newVariableData * @returns */ - function beforeEndEditCell(newVariableData: any): boolean { + function beforeEndEditCell(cell: any): boolean { return true; } /** - * 单元格结束编辑事件,用于更新变量到viewModel + * 单元格结束编辑事件,用于添加变量到视图模型 * @param cell */ function onEndEditCell(cell: any) { -- Gitee From 90011ccaf3e64ad80c91764bdf2694b56c37a27e Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Wed, 5 Mar 2025 09:47:54 +0800 Subject: [PATCH 08/34] =?UTF-8?q?chore:=20=E5=AE=8C=E5=96=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../variable-manager/composition/use-variable-data.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts index 5e899694961..ce7efdd7429 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -41,12 +41,12 @@ export function useVariableData(gridComponentInstance: Ref) { } /** - * 获取视图模型变量来源名称 + * 获取变量来源名称 * @param viewModel * @param variable * @returns */ - function getViewModelSourceName(viewModel: FormViewModel, variable: FormVariable) { + function getVariableSourceName(viewModel: FormViewModel, variable: FormVariable) { if (variable.category === FormVariableCategory.remote) { return '视图对象'; } @@ -69,7 +69,7 @@ export function useVariableData(gridComponentInstance: Ref) { const localVariables = viewModel.states.filter(state => state.category === FormVariableCategory.locale); localVariables.forEach(variable => { - const sourceName = getViewModelSourceName(viewModel, variable); + const sourceName = getVariableSourceName(viewModel, variable); const newVariable = Object.assign({ viewModelId: viewModel.id, sourceName }, variable); resolveDefaultValueInEditor(newVariable); result.push(newVariable); -- Gitee From ec6acb0a144bcd1986b7cef3e5ee41ed67a7595e Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Thu, 6 Mar 2025 15:58:00 +0800 Subject: [PATCH 09/34] =?UTF-8?q?chore:=20=E5=8F=98=E9=87=8F=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E7=9A=84=E5=8D=95=E5=85=83=E6=A0=BC=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/variable-cell.component.tsx | 48 +++++++++++++++ .../use-variable-datagrid-options.ts | 61 ++----------------- .../composition/use-variable-default-value.ts | 2 +- 3 files changed, 55 insertions(+), 56 deletions(-) create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx new file mode 100644 index 00000000000..2dc774e6755 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx @@ -0,0 +1,48 @@ +import { FormVariableCategories, FormVariableCategory, FormVariableTypes } from "../../../../../components/types"; +import { VisualData, VisualDataCell } from '@farris/ui-vue/components'; + +/** + * 变量表格的单元格 + */ +export default function (visualDataCell: VisualDataCell, visualDataRow: VisualData) { + + const { field, data } = visualDataCell; + const { category } = visualDataRow.raw; + const isLocalVariable = category === FormVariableCategory.locale; + + const showDropDownIcon = field === 'type' && isLocalVariable; + const showEditIcon = (['code', 'name'].includes(field) && isLocalVariable) || field === 'value'; + + /** + * 格式化单元格数据 + * @param visualDataCell + * @returns + */ + function formatCellData(visualDataCell: VisualDataCell) { + const { field, data } = visualDataCell; + + let displayText = data; + + if (field === 'type') { + const formVariableType = FormVariableTypes.find(vriableType => vriableType.value === data); + if (formVariableType) { + displayText = formVariableType.text; + } + } else if (field === 'category') { + const formVariableCategory = FormVariableCategories.find(variableCategory => variableCategory.value === data); + if (formVariableCategory) { + displayText = formVariableCategory.text; + } + } + return displayText; + } + + return ( +
+ {formatCellData(visualDataCell)} + {showDropDownIcon && } + {showEditIcon && } +
+ ); + +} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts index fc073a551bf..042db6705b0 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -1,6 +1,5 @@ -import { DataColumn, VisualData, VisualDataCell } from "@farris/ui-vue/components"; -import { FormVariableCategories, FormVariableTypes } from "../../../../../components/types"; -import { h, VNode } from "vue"; +import { DataColumn } from "@farris/ui-vue/components"; +import renderVariableCell from "../components/variable-cell.component"; /** * 获取表格配置 @@ -21,54 +20,6 @@ export function useVariableDataGridOptions() { showSelectAll: true }; - /** - * 格式化单元格数据 - * @param visualDataCell - * @returns - */ - function formatCellData(visualDataCell: VisualDataCell) { - const { field, data } = visualDataCell; - - let displayText = data; - - if (field === 'type') { - const formVariableType = FormVariableTypes.find(vriableType => vriableType.value === data); - if (formVariableType) { - displayText = formVariableType.text; - } - } else if (field === 'category') { - const formVariableCategory = FormVariableCategories.find(variableCategory => variableCategory.value === data); - if (formVariableCategory) { - displayText = formVariableCategory.text; - - } - } - return displayText; - } - - /** - * 单元格格式化,给单元格添加编辑或下拉图标 - * @param visualDataCell - * @param visualDataRow - * @returns - */ - function cellFormatter(visualDataCell: VisualDataCell, visualDataRow: VisualData) { - const iconsNode: VNode[] = []; - const { field, data } = visualDataCell; - - if (field === 'type') { - iconsNode.push(h('span', { class: 'f-icon f-icon-drop-down_line' })); - } - if (['code', 'name', 'value'].includes(field) && visualDataRow.raw.category === 'locale') { - iconsNode.push(h('span', { class: 'f-icon f-icon-edit-cardview' })); - } - - return h('div', { class: 'cell-wrapper' }, [ - h('span', { class: 'shown-value', title: data }, formatCellData(visualDataCell)), - ...iconsNode - ]); - } - /** * 表格列配置 */ @@ -79,7 +30,7 @@ export function useVariableDataGridOptions() { dataType: 'string', width: 120, resizable: true, - formatter: cellFormatter + formatter: renderVariableCell }, { field: 'name', @@ -87,7 +38,7 @@ export function useVariableDataGridOptions() { dataType: 'string', width: 120, resizable: true, - formatter: cellFormatter + formatter: renderVariableCell }, { @@ -95,7 +46,7 @@ export function useVariableDataGridOptions() { title: '变量类型', dataType: 'enum', valign: 'middle', - formatter: cellFormatter, + formatter: renderVariableCell, editor: { type: 'combo-list', data: [ @@ -116,7 +67,7 @@ export function useVariableDataGridOptions() { dataType: 'string', width: 120, resizable: true, - formatter: cellFormatter, + formatter: renderVariableCell, }, { field: 'category', diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts index 015b984f7e2..6a2fe1ccb77 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts @@ -12,7 +12,7 @@ export function useVariableDefaultValue() { */ function resolveDefaultValueInViewModel(variable: FormVariable) { if (variable.value === undefined || variable.value === null || variable.value === '') { - variable; + return variable.value; } if (variable.type === 'Object' || variable.type === 'Array') { -- Gitee From 37b05f4007a13e8d665c87f77c84bb5ff14d0733 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Thu, 6 Mar 2025 17:04:15 +0800 Subject: [PATCH 10/34] =?UTF-8?q?feature:=20=E6=94=AF=E6=8C=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5vo=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../array-object-editor.component.tsx | 60 ++++++++++ .../composition/use-variable-data.ts | 66 +++++++++-- .../use-variable-datagrid-options.ts | 111 +++++++++++++++++- .../composition/use-variable-default-value.ts | 94 ++++++++++++++- .../variable-manager.component.tsx | 64 ++++++++-- .../view-model-designer.component.tsx | 1 + .../components/composition/use-form-schema.ts | 3 +- .../designer/src/components/types/metadata.ts | 2 +- packages/ui-vue/components/components.ts | 1 + .../src/schema/input-group.schema.json | 12 +- 10 files changed, 388 insertions(+), 26 deletions(-) create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx new file mode 100644 index 00000000000..e870fa72fcd --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx @@ -0,0 +1,60 @@ +import { inject, ref } from 'vue'; +import MonacoEditor from '../../../monaco-editor/monaco-editor.component'; +import { F_MODAL_SERVICE_TOKEN, FModalService } from '@farris/ui-vue/components'; + +/** + * 数组和对象编辑器 + */ +export default function () { + + const monacoEditorRef = ref(); + const modalService: FModalService | null = inject(F_MODAL_SERVICE_TOKEN, null); + + function renderEditor(value) { + return () => { + return ( + + ); + }; + } + + /** + * 弹出数组和对象编辑器 + * @param value + * @param confirmHandler + */ + function showArrayObjectEditor(value: any, confirmHandler: (value: any) => boolean) { + const monacoEditorModal = modalService?.open({ + fitContent: false, + width: 840, + height: 445, + title: '默认值编辑器', + render: renderEditor(value), + buttons: [ + { + class: 'btn btn-light', + iconClass: 'f-icon f-icon-close', + text: '取消', + handle: () => { + monacoEditorModal?.destroy(); + } + }, + { + class: 'btn btn-primary', + text: '确定', + iconClass: 'f-icon f-icon-check', + handle: () => { + const newValue = monacoEditorRef.value.getContent(); + const result = confirmHandler(newValue); + if (result) { + monacoEditorModal?.destroy(); + } + } + } + ] + }); + } + + return { showArrayObjectEditor }; + +} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts index ce7efdd7429..92bd70f6e2d 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -1,17 +1,22 @@ import { inject, Ref, ref } from "vue"; -import { FormVariable, FormVariableCategory, FormViewModel, UseFormSchema } from "../../../../types"; +import { FormSchema, FormVariable, FormVariableCategory, FormViewModel, UseFormSchema, UseSchemaService } from "../../../../types"; import { useVariableDefaultValue } from "./use-variable-default-value"; import { FNotifyService } from "@farris/ui-vue/components"; import { IdService } from "../../method-manager/service/id.service"; +import { useViewModelName } from '../../method-manager/composition/use-view-model-name'; export function useVariableData(gridComponentInstance: Ref) { const useFormSchema = inject('useFormSchema') as UseFormSchema; + const schemaService = inject('schemaService') as UseSchemaService; const formSchema = useFormSchema.getFormSchema(); const notifyService: FNotifyService = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; - const { resolveDefaultValueInEditor, resolveDefaultValueInViewModel } = useVariableDefaultValue(); const ROOT_VIEW_MODEL_ID = 'root-viewmodel'; + + const { getViewModelName } = useViewModelName(); + const { resolveDefaultValueInEditor, resolveDefaultValueInViewModel } = useVariableDefaultValue(); + const { convertViewObjectToEntitySchema } = schemaService; const variableList = ref([]); @@ -50,8 +55,7 @@ export function useVariableData(gridComponentInstance: Ref) { if (variable.category === FormVariableCategory.remote) { return '视图对象'; } - return '组件'; - // return getViewModelName(viewModel.id, viewModel.name); + return getViewModelName(viewModel.id, viewModel.name); } /** @@ -107,6 +111,18 @@ export function useVariableData(gridComponentInstance: Ref) { return true; } + /** + * 从视图模型中删除变量 + * @param variable + */ + function deleteVariableFromViewModel(variable: FormVariable) { + const viewModelId = variable.viewModelId || ROOT_VIEW_MODEL_ID; + const viewModel = useFormSchema.getViewModelById(viewModelId); + if (viewModel) { + viewModel.states = viewModel.states.filter(state => state.id !== variable.id); + } + } + /** * 删除变量 * @returns @@ -127,6 +143,7 @@ export function useVariableData(gridComponentInstance: Ref) { selectedVariables.forEach(selectedVariable => { if (selectedVariable.category === FormVariableCategory.locale) { variableList.value = variableList.value.filter(variable => variable.id !== selectedVariable.id); + deleteVariableFromViewModel(selectedVariable); } }); @@ -151,12 +168,12 @@ export function useVariableData(gridComponentInstance: Ref) { } /** - * 添加变量到视图模型 + * 更新变量到视图模型 * @param variable * @param changeObject * @returns */ - function addVariableToViewModel(variable: FormVariable, changeObject: { field: string, value: any }) { + function updateVariableToViewModel(variable: FormVariable, changeObject: { field: string, value: any }) { // 校验不通过时,单元格重置为编辑态 if (changeObject.field === 'code' && !checkUniqueCode(variable)) { return; @@ -193,12 +210,47 @@ export function useVariableData(gridComponentInstance: Ref) { // this.syncFormControlsBindingVariable(rowData, changeObject); } + /** + * 刷新表单变量 + */ + function refreshRemoteVariables() { + const schema = useFormSchema.getSchemas(); + if (!schema) { + notifyService.error('表单Schema不存在!'); + return; + } + const viewModelId = schema.id; + + convertViewObjectToEntitySchema(viewModelId, '').then((newSchema: FormSchema | undefined) => { + if (!newSchema) { + notifyService.error('未获取到表单Schema!'); + return; + } + const newVariables = newSchema.variables || []; + + // 更新表单Schema中的变量 + schema.variables = newVariables; + + // 更新视图模型中的变量 + useFormSchema.updateRemoteVariables(newVariables); + + // 更新表格数据,并取消选中 + loadVariables(); + gridComponentInstance.value.updateDataSource(variableList.value); + gridComponentInstance.value.clearSelection(); + + notifyService.success('更新成功!'); + }); + + } + return { variableList, loadVariables, checkUniqueCode, deleteVariables, addVariableToDataGrid, - addVariableToViewModel + updateVariableToViewModel, + refreshRemoteVariables }; } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts index 042db6705b0..3f3481035f2 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -1,10 +1,18 @@ -import { DataColumn } from "@farris/ui-vue/components"; +import { DataColumn, EditorConfig, FNotifyService, VisualData, VisualDataCell } from "@farris/ui-vue/components"; +import { FormVariable, FormVariableCategories, FormVariableCategory, FormVariableTypes, UseFormSchema } from "../../../../../components/types"; +import { inject } from "vue"; import renderVariableCell from "../components/variable-cell.component"; +import { useVariableDefaultValue } from "./use-variable-default-value"; /** * 获取表格配置 */ -export function useVariableDataGridOptions() { +export default function useVariableDataGridOptions() { + const useFormSchema = inject('useFormSchema') as UseFormSchema; + /** 检查默认值格式 */ + const { showDefaultValueEditor } = useVariableDefaultValue(); + const notifyService: FNotifyService = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; /** 列配置 */ const columnOption = { @@ -104,10 +112,107 @@ export function useVariableDataGridOptions() { } ] + /** + * 获取数字类变量的编辑器配置 + */ + function getNumberVariableEditor(variable: FormVariable): EditorConfig { + const editorConfig: EditorConfig = { + type: 'number-spinner', + precision: 2, + max: 100000000 + }; + + // 组件变量没有精度 + if (variable.category === FormVariableCategory.locale) { + return editorConfig; + } + + // 获取表单Schema中记录的表单变量 + const schemas = useFormSchema.getSchemas(); + if (!schemas) { + return editorConfig; + } + const remoteVariables = schemas.variables || []; + + const remoteVariable = remoteVariables.find(remoteVariable => remoteVariable.id === variable.id); + if (remoteVariable && remoteVariable.type) { + editorConfig.precision = remoteVariable.type.precision; + } + + return editorConfig; + } + + function updateDefaultValueColumnEditor(variable: FormVariable, cell: any) { + const variableType = variable.type; + const defaultValueColumn = columns.find(column => column.field === 'value'); + if (!defaultValueColumn) { + return; + } + switch (variableType) { + case 'Number': { + defaultValueColumn.editor = getNumberVariableEditor(variable); + break; + } + case 'Date': { + defaultValueColumn.editor = { + type: 'date-picker' + }; + break; + } + case 'DateTime': { + defaultValueColumn.editor = { + type: 'date-picker', + showTime: true, + displayFormat: 'yyyy-MM-dd HH:mm:ss', + valueFormat: 'yyyy-MM-dd HH:mm:ss' + }; + break; + } + case 'Boolean': { + defaultValueColumn.editor = { + type: 'switch', + size: 'small' + }; + break; + } + case 'Object': { + defaultValueColumn.editor = { + type: 'input-group', + groupText: '', + editable: false, + showClear: true, + showButtonWhenDisabled: true, + onClickHandle: (e) => { + showDefaultValueEditor(variable, cell); + } + }; + break; + } + case 'Array': { + defaultValueColumn.editor = { + type: 'input-group', + groupText: '', + editable: false, + showClear: true, + showButtonWhenDisabled: true, + onClickHandle: (e) => { + showDefaultValueEditor(variable, cell); + } + }; + break; + } + default: { + defaultValueColumn.editor = { + type: 'input-group' + }; + } + } + } return { columns, columnOption, - selectionOption + selectionOption, + updateDefaultValueColumnEditor }; } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts index 6a2fe1ccb77..23113f5b206 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts @@ -1,9 +1,11 @@ import { FNotifyService } from "@farris/ui-vue/components"; import { FormVariable } from "../../../../types"; +import getArrayObjectEditor from '../components/array-object-editor.component'; export function useVariableDefaultValue() { const notifyService: FNotifyService = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; + const { showArrayObjectEditor } = getArrayObjectEditor(); /** * 将字符串类型的默认值转换为对象类型,用于DOM存储。 @@ -12,7 +14,7 @@ export function useVariableDefaultValue() { */ function resolveDefaultValueInViewModel(variable: FormVariable) { if (variable.value === undefined || variable.value === null || variable.value === '') { - return variable.value; + return undefined; } if (variable.type === 'Object' || variable.type === 'Array') { @@ -44,7 +46,7 @@ export function useVariableDefaultValue() { if (variable.type === 'Object' || variable.type === 'Array') { try { - variable.value = JSON.stringify(variable.value); + variable.value = JSON.stringify(variable.value, null, 4); } catch (error) { console.error(error); notifyService.error('解析默认值失败'); @@ -53,10 +55,96 @@ export function useVariableDefaultValue() { } } + /** + * 清空变量的默认值 + * @param cell + */ + function clearDefaultValue(cell: any) { + if (cell.column.field !== 'type') { + return; + } + // 修改变量类型后,清除变量的默认值 + if (cell.newValue && cell.newValue !== cell.oldValue) { + cell.row.data.value.updateData({ + value: undefined + }); + notifyService.warning('修改变量类型后,自动清除默认值'); + } + + } + + /** + * 校验默认值格式是否正确 + */ + function checkDefaultValueValid(variableType: string, defaultValue: string): string | undefined { + if (!defaultValue) { + return; + } + switch (variableType) { + case 'Object': { + try { + const object = JSON.parse(defaultValue); + if (!object || typeof (object) !== 'object' || Array.isArray(object)) { + return '默认值不是对象格式,请检查。'; + } + } catch (error) { + console.error(error); + return '默认值不是对象格式,请检查。'; + } + break; + } + case 'Array': { + try { + const array = JSON.parse(defaultValue); + if (!array || typeof (array) !== 'object' || !Array.isArray(array)) { + return '默认值不是数组格式,请检查。'; + } + } catch (error) { + console.error(error); + return '默认值不是数组格式,请检查。'; + } + break; + } + case 'String': case 'Text': { + // 若默认值中有单引号,会引起编译错误。这里强制替换掉默认值中的单引号 + if (typeof (defaultValue) === 'string' && defaultValue.indexOf('\'') > -1) { + defaultValue = defaultValue.trim().replace(/'/g, ''); + return; + } + } + } + + } + + + /** + * 打开默认值编辑器 + */ + function showDefaultValueEditor(variable: FormVariable,cell: any) { + const currentValue = variable.value; + // 确认框的回调函数 + const confirmHandler = (value: any):boolean => { + const result = checkDefaultValueValid(variable.type,value); + if(result){ + notifyService.error(result); + return false; + } + + cell.row.data.value.updateData({ + value: value + }); + return true; + }; + // 显示数组和对象的编辑器 + showArrayObjectEditor(currentValue,confirmHandler); + } return { resolveDefaultValueInViewModel, - resolveDefaultValueInEditor + resolveDefaultValueInEditor, + checkDefaultValueValid, + clearDefaultValue, + showDefaultValueEditor } } \ No newline at end of file diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index ae4efd2c5b3..b42aa21a539 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -3,7 +3,9 @@ import { FDataGrid } from "@farris/ui-vue/components"; import { variableManagerProps, VariableManagerProps } from "./variable-manager.props"; import './variable-manager.scss'; import { useVariableData } from "./composition/use-variable-data"; -import { useVariableDataGridOptions } from "./composition/use-variable-datagrid-options"; +import { FormVariable, FormVariableCategory } from "../../../../components/types"; +import useVariableDataGridOptions from "./composition/use-variable-datagrid-options"; +import { useVariableDefaultValue } from "./composition/use-variable-default-value"; export default defineComponent({ name: 'FVariableManager', @@ -14,11 +16,21 @@ export default defineComponent({ /** 表格实例 */ const gridComponentInstance = ref(); /** 表格配置 */ - const { columns, columnOption, selectionOption } = useVariableDataGridOptions(); + const { columns, columnOption, selectionOption, updateDefaultValueColumnEditor } = useVariableDataGridOptions(); + /** 变量默认值相关方法 */ + const { clearDefaultValue } = useVariableDefaultValue(); /** 变量数据相关方法 */ - const { variableList, loadVariables, deleteVariables, addVariableToDataGrid, addVariableToViewModel } = useVariableData(gridComponentInstance); + const { variableList, loadVariables, deleteVariables, addVariableToDataGrid, updateVariableToViewModel, refreshRemoteVariables } = useVariableData(gridComponentInstance); loadVariables(); + /** + * 刷新变量列表 + */ + function refreshVariableManager() { + loadVariables(); + gridComponentInstance.value.updateDataSource(variableList.value); + } + /** * 添加变量 */ @@ -36,29 +48,60 @@ export default defineComponent({ /** * 刷新表单变量 */ - function onRefreshVariable() { + function onRefreshVariables() { + refreshRemoteVariables(); } + /** + * 单元格编辑前事件 + * @param cell + */ + function onBeforeEditCell(cell: any) { + const variable: FormVariable = cell.row.raw; + const { field } = cell.column; + // 编辑默认值单元格前,需要更新默认值单元格的编辑器 + if (field === 'value') { + updateDefaultValueColumnEditor(variable, cell); + return true; + } + + // 表单变量的编号、名称不支持修改 + if (variable.category === FormVariableCategory.remote && ['code', 'name', 'type'].includes(field)) { + return false; + } + + return true; + }; + /** * 单元格结束编辑前事件, 用于检查输入内容是否合法 * @param newVariableData * @returns */ - function beforeEndEditCell(cell: any): boolean { + function onBeforeEndEditCell(cell: any): boolean { return true; } /** - * 单元格结束编辑事件,用于添加变量到视图模型 + * 单元格结束编辑事件 * @param cell */ function onEndEditCell(cell: any) { - addVariableToViewModel(cell.row.raw, { + const variable: FormVariable = cell.row.raw; + // 修改类型列后,清空默认值 + clearDefaultValue(cell); + + // 修改变量后,更新变量到视图模型 + const changedOject = { field: cell.column.field, value: cell.newValue, - }); + } + updateVariableToViewModel(variable, changedOject); }; + context.expose({ refreshVariableManager }) + + return () => { return (
@@ -75,7 +118,7 @@ export default defineComponent({
-
+
刷新
@@ -89,8 +132,9 @@ export default defineComponent({ editable="true" column-option={columnOption} selection={selectionOption} + beforeEditCell={onBeforeEditCell} + beforeEndEditCell={onBeforeEndEditCell} onEndEditCell={onEndEditCell} - beforeEndEditCell={beforeEndEditCell} >
diff --git a/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx b/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx index e74634719da..2b464076f30 100644 --- a/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx @@ -31,6 +31,7 @@ export default defineComponent({ /** 刷新模型页 */ function refreshViewModelDesigner() { methodMangerRef.value?.refreshMethodManager(); + variableMangerRef.value?.refreshVariableManager(); } context.expose({ refreshViewModelDesigner }); diff --git a/packages/designer/src/components/composition/use-form-schema.ts b/packages/designer/src/components/composition/use-form-schema.ts index 6af9c1a7970..e71bd8cfe70 100644 --- a/packages/designer/src/components/composition/use-form-schema.ts +++ b/packages/designer/src/components/composition/use-form-schema.ts @@ -1301,6 +1301,7 @@ export function useFormSchema(): UseFormSchema { setExpressions, deleteComponent, getControlsInCmpWidthBinding, - getVariableById + getVariableById, + updateRemoteVariables }; } diff --git a/packages/designer/src/components/types/metadata.ts b/packages/designer/src/components/types/metadata.ts index 97a3d1f04cb..7c041b38e56 100644 --- a/packages/designer/src/components/types/metadata.ts +++ b/packages/designer/src/components/types/metadata.ts @@ -225,7 +225,7 @@ export interface UseFormSchema { deleteComponent: (componentId: string) => void; getControlsInCmpWidthBinding: (viewModelId: string, fieldId: string) => any; getVariableById: (variableId: string) => FormVariable | undefined; - + updateRemoteVariables: (variables: FormSchemaEntityField[]) => void; } export interface UseSchemaService { diff --git a/packages/ui-vue/components/components.ts b/packages/ui-vue/components/components.ts index 14eac932d15..bae5a28f04f 100644 --- a/packages/ui-vue/components/components.ts +++ b/packages/ui-vue/components/components.ts @@ -22,6 +22,7 @@ export { default as FDatePicker } from './date-picker'; export { default as FDropdown } from './dropdown'; export type { DropdownProps } from './dropdown'; export { FDynamicView } from './dynamic-view'; +export type { EditorConfig } from './dynamic-form'; export * from './data-view'; export type { DataColumn, VisualData, VisualDataCell, RowOptions } from './data-view'; export { default as FInputGroup } from './input-group'; diff --git a/packages/ui-vue/components/input-group/src/schema/input-group.schema.json b/packages/ui-vue/components/input-group/src/schema/input-group.schema.json index b3f83a2d8f4..32132544fa3 100644 --- a/packages/ui-vue/components/input-group/src/schema/input-group.schema.json +++ b/packages/ui-vue/components/input-group/src/schema/input-group.schema.json @@ -205,7 +205,17 @@ "description": "", "type": "string", "default": "" - } + }, + "groupText": { + "description": "", + "type": "string", + "default": "" + }, + "onClickHandle": { + "description": "", + "type": "string", + "default": "" + } }, "required": [ "type" -- Gitee From 5eb326bbd580340a2b50c333b180b115c5d44e1e Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Fri, 7 Mar 2025 15:01:19 +0800 Subject: [PATCH 11/34] =?UTF-8?q?chore:=20=E5=AE=8C=E5=96=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/array-object-editor.component.tsx | 8 +++----- .../composition/use-variable-datagrid-options.ts | 2 +- .../variable-manager/variable-manager.component.tsx | 4 ++-- .../view-model-designer.component.tsx | 12 ++++++------ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx index e870fa72fcd..f65c18b4a22 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx @@ -10,7 +10,7 @@ export default function () { const monacoEditorRef = ref(); const modalService: FModalService | null = inject(F_MODAL_SERVICE_TOKEN, null); - function renderEditor(value) { + function renderEditor(value:any) { return () => { return ( @@ -23,7 +23,7 @@ export default function () { * @param value * @param confirmHandler */ - function showArrayObjectEditor(value: any, confirmHandler: (value: any) => boolean) { + function showArrayObjectEditor(value: any, confirmHandler: (newValue: any) => boolean) { const monacoEditorModal = modalService?.open({ fitContent: false, width: 840, @@ -32,8 +32,7 @@ export default function () { render: renderEditor(value), buttons: [ { - class: 'btn btn-light', - iconClass: 'f-icon f-icon-close', + class: 'btn btn-secondary', text: '取消', handle: () => { monacoEditorModal?.destroy(); @@ -42,7 +41,6 @@ export default function () { { class: 'btn btn-primary', text: '确定', - iconClass: 'f-icon f-icon-check', handle: () => { const newValue = monacoEditorRef.value.getContent(); const result = confirmHandler(newValue); diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts index 3f3481035f2..c0bcc7c4cff 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -7,7 +7,7 @@ import { useVariableDefaultValue } from "./use-variable-default-value"; /** * 获取表格配置 */ -export default function useVariableDataGridOptions() { +export function useVariableDataGridOptions() { const useFormSchema = inject('useFormSchema') as UseFormSchema; /** 检查默认值格式 */ const { showDefaultValueEditor } = useVariableDefaultValue(); diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index b42aa21a539..b7d3c58603d 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -65,7 +65,7 @@ export default defineComponent({ return true; } - // 表单变量的编号、名称不支持修改 + // 表单变量的编号、名称、类型不支持修改 if (variable.category === FormVariableCategory.remote && ['code', 'name', 'type'].includes(field)) { return false; } @@ -75,7 +75,7 @@ export default defineComponent({ /** * 单元格结束编辑前事件, 用于检查输入内容是否合法 - * @param newVariableData + * @param cell * @returns */ function onBeforeEndEditCell(cell: any): boolean { diff --git a/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx b/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx index 2b464076f30..6f45179960d 100644 --- a/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/view-model-designer.component.tsx @@ -11,8 +11,8 @@ export default defineComponent({ props: viewModelDesignerProps, emits: [], setup(props: ViewModelDesignerProps, context) { - const methodMangerRef = ref(); - const variableMangerRef = ref(); + const methodManagerRef = ref(); + const variableManagerRef = ref(); const selectedModelTab = ref('method'); const modelTabClass = computed(() => (modelType: string) => { @@ -30,8 +30,8 @@ export default defineComponent({ } /** 刷新模型页 */ function refreshViewModelDesigner() { - methodMangerRef.value?.refreshMethodManager(); - variableMangerRef.value?.refreshVariableManager(); + methodManagerRef.value?.refreshMethodManager(); + variableManagerRef.value?.refreshVariableManager(); } context.expose({ refreshViewModelDesigner }); @@ -51,8 +51,8 @@ export default defineComponent({ - - + + ); -- Gitee From cee2f408e999ef652d3eff6bf303eb8045655160 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Fri, 7 Mar 2025 16:35:32 +0800 Subject: [PATCH 12/34] =?UTF-8?q?chore:=E8=BF=98=E5=8E=9F=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../input-group/src/schema/input-group.schema.json | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/ui-vue/components/input-group/src/schema/input-group.schema.json b/packages/ui-vue/components/input-group/src/schema/input-group.schema.json index 32132544fa3..b3f83a2d8f4 100644 --- a/packages/ui-vue/components/input-group/src/schema/input-group.schema.json +++ b/packages/ui-vue/components/input-group/src/schema/input-group.schema.json @@ -205,17 +205,7 @@ "description": "", "type": "string", "default": "" - }, - "groupText": { - "description": "", - "type": "string", - "default": "" - }, - "onClickHandle": { - "description": "", - "type": "string", - "default": "" - } + } }, "required": [ "type" -- Gitee From 4b6ea77cb9eebb453195f0e90e223a43adaf7657 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Fri, 7 Mar 2025 17:27:42 +0800 Subject: [PATCH 13/34] =?UTF-8?q?chore:=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../variable-manager/variable-manager.component.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index b7d3c58603d..59695849522 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -4,7 +4,7 @@ import { variableManagerProps, VariableManagerProps } from "./variable-manager.p import './variable-manager.scss'; import { useVariableData } from "./composition/use-variable-data"; import { FormVariable, FormVariableCategory } from "../../../../components/types"; -import useVariableDataGridOptions from "./composition/use-variable-datagrid-options"; +import {useVariableDataGridOptions} from "./composition/use-variable-datagrid-options"; import { useVariableDefaultValue } from "./composition/use-variable-default-value"; export default defineComponent({ -- Gitee From 8ff211436581a72f5e8b9e8abd8c3d3178eb5f8c Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 10 Mar 2025 16:11:45 +0800 Subject: [PATCH 14/34] =?UTF-8?q?chore:=20=E8=B0=83=E6=95=B4=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/variable-cell.component.tsx | 48 ---- .../use-array-and-object-editor.tsx} | 13 +- .../composition/use-variable-data.ts | 269 ++++++++++++------ .../use-variable-datagrid-options.ts | 122 +++++--- .../composition/use-variable-default-value.ts | 130 +++++---- .../code-and-name-column-formatter.tsx | 22 ++ .../default-value-column-formatter.tsx | 19 ++ .../formatters/type-column-formatter.tsx | 41 +++ .../variable-manager.component.tsx | 49 ++-- 9 files changed, 438 insertions(+), 275 deletions(-) delete mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx rename packages/designer/src/components/components/view-model-designer/variable-manager/{components/array-object-editor.component.tsx => composition/use-array-and-object-editor.tsx} (79%) create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/formatters/code-and-name-column-formatter.tsx create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx create mode 100644 packages/designer/src/components/components/view-model-designer/variable-manager/formatters/type-column-formatter.tsx diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx deleted file mode 100644 index 2dc774e6755..00000000000 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/components/variable-cell.component.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { FormVariableCategories, FormVariableCategory, FormVariableTypes } from "../../../../../components/types"; -import { VisualData, VisualDataCell } from '@farris/ui-vue/components'; - -/** - * 变量表格的单元格 - */ -export default function (visualDataCell: VisualDataCell, visualDataRow: VisualData) { - - const { field, data } = visualDataCell; - const { category } = visualDataRow.raw; - const isLocalVariable = category === FormVariableCategory.locale; - - const showDropDownIcon = field === 'type' && isLocalVariable; - const showEditIcon = (['code', 'name'].includes(field) && isLocalVariable) || field === 'value'; - - /** - * 格式化单元格数据 - * @param visualDataCell - * @returns - */ - function formatCellData(visualDataCell: VisualDataCell) { - const { field, data } = visualDataCell; - - let displayText = data; - - if (field === 'type') { - const formVariableType = FormVariableTypes.find(vriableType => vriableType.value === data); - if (formVariableType) { - displayText = formVariableType.text; - } - } else if (field === 'category') { - const formVariableCategory = FormVariableCategories.find(variableCategory => variableCategory.value === data); - if (formVariableCategory) { - displayText = formVariableCategory.text; - } - } - return displayText; - } - - return ( -
- {formatCellData(visualDataCell)} - {showDropDownIcon && } - {showEditIcon && } -
- ); - -} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-array-and-object-editor.tsx similarity index 79% rename from packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx rename to packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-array-and-object-editor.tsx index f65c18b4a22..b84fb3fde5d 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/components/array-object-editor.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-array-and-object-editor.tsx @@ -1,16 +1,17 @@ import { inject, ref } from 'vue'; import MonacoEditor from '../../../monaco-editor/monaco-editor.component'; import { F_MODAL_SERVICE_TOKEN, FModalService } from '@farris/ui-vue/components'; +import { JSX } from 'vue/jsx-runtime'; /** * 数组和对象编辑器 */ -export default function () { +export function useArrayAndObjectEditor() { const monacoEditorRef = ref(); const modalService: FModalService | null = inject(F_MODAL_SERVICE_TOKEN, null); - function renderEditor(value:any) { + function renderEditor(value: any): () => JSX.Element { return () => { return ( @@ -23,7 +24,7 @@ export default function () { * @param value * @param confirmHandler */ - function showArrayObjectEditor(value: any, confirmHandler: (newValue: any) => boolean) { + function showArrayAndObjectEditor(value: any, confirmHandler: (newValue: any) => boolean) { const monacoEditorModal = modalService?.open({ fitContent: false, width: 840, @@ -43,8 +44,8 @@ export default function () { text: '确定', handle: () => { const newValue = monacoEditorRef.value.getContent(); - const result = confirmHandler(newValue); - if (result) { + const checkPassed = confirmHandler(newValue); + if (checkPassed) { monacoEditorModal?.destroy(); } } @@ -53,6 +54,6 @@ export default function () { }); } - return { showArrayObjectEditor }; + return { showArrayAndObjectEditor }; } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts index 92bd70f6e2d..20d3c4ae340 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -13,49 +13,85 @@ export function useVariableData(gridComponentInstance: Ref) { const notifyService: FNotifyService = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; const ROOT_VIEW_MODEL_ID = 'root-viewmodel'; - + const { getViewModelName } = useViewModelName(); const { resolveDefaultValueInEditor, resolveDefaultValueInViewModel } = useVariableDefaultValue(); const { convertViewObjectToEntitySchema } = schemaService; const variableList = ref([]); + /** + * 获取变量来源名称 + * @param viewModel + * @param variable + * @returns + */ + function getVariableSourceName(variable: FormVariable, viewModel: FormViewModel) { + if (variable.category === FormVariableCategory.remote) { + return '视图对象'; + } + return getViewModelName(viewModel.id, viewModel.name); + } + + /** + * 给变量添加信息(变量来源、变量所在视图模型信息) + * @param variable + * @param viewModel + * @returns + */ + function appendInfoToVariable(variable: FormVariable, viewModel: FormViewModel) { + const sourceName = getVariableSourceName(variable, viewModel); + const viewModelId = viewModel.id; + const newVariable = Object.assign({ sourceName, viewModelId }, variable); + return newVariable; + } + /** * 获取表单变量 */ function getRemoteVariables(): FormVariable[] { const result: FormVariable[] = []; + // 1、获取根视图模型,表单变量在根视图模型中 const rootViewModel = formSchema.module.viewmodels[0]; if (!rootViewModel || !rootViewModel.states) { return result; } - const remoteVariables = rootViewModel.states.filter(state => state.category === FormVariableCategory.remote); - - remoteVariables.forEach(variable => { - const newVariable = Object.assign({ - sourceName: '视图对象' - }, variable); + // 2、从根视图模型中找出所有的表单变量 + const allRemoteVariables = rootViewModel.states.filter(state => state.category === FormVariableCategory.remote); - resolveDefaultValueInEditor(newVariable); + // 3、对变量进行加工 + allRemoteVariables.forEach(variable => { + const newVariable = appendInfoToVariable(variable, rootViewModel); + newVariable.value = resolveDefaultValueInEditor(newVariable); result.push(newVariable); }); return result; - } /** - * 获取变量来源名称 + * 从视图模型中获取组件变量 * @param viewModel - * @param variable + * @param result * @returns */ - function getVariableSourceName(viewModel: FormViewModel, variable: FormVariable) { - if (variable.category === FormVariableCategory.remote) { - return '视图对象'; + function getLocalVariable(viewModel: FormViewModel): FormVariable[] { + const result: FormVariable[] = []; + if (!viewModel.states || !viewModel.states.length) { + return result; } - return getViewModelName(viewModel.id, viewModel.name); + // 1、找出视图模型上的组件变量 + const localVariables = viewModel.states.filter(state => state.category === FormVariableCategory.locale); + + // 2、对变量进行加工 + localVariables.forEach(variable => { + const newVariable = appendInfoToVariable(variable, viewModel); + newVariable.value = resolveDefaultValueInEditor(newVariable); + result.push(newVariable); + }); + + return result; } /** @@ -63,22 +99,11 @@ export function useVariableData(gridComponentInstance: Ref) { */ function getLocalVariables(): FormVariable[] { const result: FormVariable[] = []; - const viewModelList = formSchema.module.viewmodels; viewModelList.forEach(viewModel => { - if (!viewModel.states || !viewModel.states.length) { - return; - } - const localVariables = viewModel.states.filter(state => state.category === FormVariableCategory.locale); - - localVariables.forEach(variable => { - const sourceName = getVariableSourceName(viewModel, variable); - const newVariable = Object.assign({ viewModelId: viewModel.id, sourceName }, variable); - resolveDefaultValueInEditor(newVariable); - result.push(newVariable); - - }); + const localVariables = getLocalVariable(viewModel); + result.push(...localVariables); }); return result; @@ -98,13 +123,15 @@ export function useVariableData(gridComponentInstance: Ref) { * @param variable * @returns */ - function checkUniqueCode(variable: FormVariable) { + function checkUniqueCode(variable: FormVariable): boolean { if (!variable.code) { return true; } - const index = variableList.value.findIndex(currentVariable => currentVariable.code === variable.code - && currentVariable.id !== variable.id); - if (index > -1) { + // 两个变量编号相同、内码不同,则认为变量编号重复 + const existSameCodeVariable = variableList.value.findIndex(currentVariable => currentVariable.code === variable.code + && currentVariable.id !== variable.id) > -1; + + if (existSameCodeVariable) { notifyService.warning('变量编号已存在,请修改。'); return false; } @@ -128,118 +155,175 @@ export function useVariableData(gridComponentInstance: Ref) { * @returns */ function deleteVariables() { - const selectedVariables = gridComponentInstance.value.getSelectedItems(); - - if (!selectedVariables || !selectedVariables.length) { + const variablesToBeDeleted = gridComponentInstance.value.getSelectedItems(); + // 1、要删除的变量不能为空 + if (!variablesToBeDeleted || !variablesToBeDeleted.length) { notifyService.info('请勾选要删除的行'); return; } - - const remoteVariableIndex = selectedVariables.findIndex(selectedVariable => selectedVariable.category === FormVariableCategory.remote); - if (remoteVariableIndex > -1) { + // 2、删除表单变量时进行提示 + const existRemoteVariable = variablesToBeDeleted.findIndex(variableToBeDeleted => variableToBeDeleted.category === FormVariableCategory.remote) > -1; + if (existRemoteVariable) { notifyService.info('不可删除表单变量'); } - selectedVariables.forEach(selectedVariable => { - if (selectedVariable.category === FormVariableCategory.locale) { - variableList.value = variableList.value.filter(variable => variable.id !== selectedVariable.id); - deleteVariableFromViewModel(selectedVariable); - - } + // 3、从视图模型中删除变量 + variablesToBeDeleted.forEach(variableToBeDeleted => { + variableList.value = variableList.value.filter(variable => variable.id !== variableToBeDeleted.id); + deleteVariableFromViewModel(variableToBeDeleted); }); + // 4、更新表格的数据,并取消选中 gridComponentInstance.value.updateDataSource(variableList.value); gridComponentInstance.value.clearSelection(); } /** - * 添加变量到表格 + * 添加一个新变量到表格 */ function addVariableToDataGrid() { - variableList.value.push({ + const newVariable = { id: new IdService().generate(), type: 'String', code: "", name: "", category: FormVariableCategory.locale - }); + } + variableList.value.push(newVariable); gridComponentInstance.value.updateDataSource(variableList.value); } /** - * 更新变量到视图模型 + * 变量更新前检查 * @param variable - * @param changeObject * @returns */ - function updateVariableToViewModel(variable: FormVariable, changeObject: { field: string, value: any }) { - // 校验不通过时,单元格重置为编辑态 - if (changeObject.field === 'code' && !checkUniqueCode(variable)) { - return; + function checkVariableBeforeUpdate(variable: FormVariable): boolean { + // 1、修改变量编号时,检查变量编号是否重复 + const checkPassed = checkUniqueCode(variable); + if (!checkPassed) { + return false; } const variableCode = variable.code && variable.code.trim(); const variableName = variable.name && variable.name.trim(); - const variableValue = resolveDefaultValueInViewModel(variable); + // 2、变量编号、名称、类型不能为空 if (!variableCode || !variableName || !variable.type) { + return false; + } + return true; + } + + /** + * 添加变量到视图模型 + * @param variable + * @param viewModel + */ + function addVariable(variable: FormVariable, viewModel: FormViewModel) { + // 1、处理变量默认值,用于DOM存储 + const resolvedDefaultValue = resolveDefaultValueInViewModel(variable); + + // 2、添加变量到视图模型 + const newVariable = { + id: variable.id, + code: variable.code, + name: variable.name, + type: variable.type, + category: variable.category, + value: resolvedDefaultValue + } + viewModel.states.push(newVariable); + } + + /** + * 更新视图模型中的变量信息 + * @param variable + * @param viewModel + */ + function updateVariable(variableInViewModel: FormVariable, newVariable: FormVariable) { + // 1、处理变量默认值,用于DOM存储 + const resolvedDefaultValue = resolveDefaultValueInViewModel(newVariable); + + // 2、更新视图模型中的变量 + Object.assign(variableInViewModel, { + code: newVariable.code, + name: newVariable.name, + type: newVariable.type, + value: resolvedDefaultValue + }); + } + + /** + * 更新变量到视图模型 + * @param variable + * @param changeObject + * @returns + */ + function updateVariableToViewModel(newVariable: FormVariable, changeObject: { field: string, value: any }) { + // 1、检查变量是否符合要求 + const checkPassed = checkVariableBeforeUpdate(newVariable); + if (!checkPassed) { return; } - const viewModelId = variable.viewModelId || ROOT_VIEW_MODEL_ID; + // 2、查找变量对应的视图模型 + const viewModelId = newVariable.viewModelId || ROOT_VIEW_MODEL_ID; const viewModel = useFormSchema.getViewModelById(viewModelId); - if (viewModel) { - const variableInViewModel = viewModel.states.find(state => state.id === variable.id); - if (variableInViewModel) { - Object.assign(variableInViewModel, { - code: variableCode, - name: variableName, - type: variable.type, - value: variableValue - }); - } else { - viewModel.states.push({ - id: variable.id, - code: variableCode, - name: variableName, - type: variable.type, - category: variable.category, - value: variableValue - }); - } + if (!viewModel) { + return; + } + + // 3、变量是否在视图模型中,如果存在则更新,如果不存在则添加 + const variableInViewModel = viewModel.states.find(state => state.id === newVariable.id); + if (variableInViewModel) { + updateVariable(variableInViewModel, newVariable); + } else { + addVariable(newVariable, viewModel); } // this.syncFormControlsBindingVariable(rowData, changeObject); } + /** + * 更新表单变量 + * @param oldSchema + * @param newSchema + */ + function updateRemoteVariables(currentSchema: FormSchema, newSchema: FormSchema) { + // 1、更新表单Schema中的变量 + const newVariables = newSchema.variables || []; + currentSchema.variables = newVariables; + + // 2、更新视图模型中的变量 + useFormSchema.updateRemoteVariables(newVariables); + + // 3、更新表格数据,并取消选中 + loadVariables(); + gridComponentInstance.value.updateDataSource(variableList.value); + gridComponentInstance.value.clearSelection(); + notifyService.success('更新成功!'); + } + /** * 刷新表单变量 */ function refreshRemoteVariables() { - const schema = useFormSchema.getSchemas(); - if (!schema) { + // 1、判断表单Schema是否存在 + const currentSchema = useFormSchema.getSchemas(); + if (!currentSchema) { notifyService.error('表单Schema不存在!'); return; } - const viewModelId = schema.id; - convertViewObjectToEntitySchema(viewModelId, '').then((newSchema: FormSchema | undefined) => { + // 2、获取视图对象内码 + const viewObjectId = currentSchema.id; + + // 3、获取新的表单Schema + convertViewObjectToEntitySchema(viewObjectId, '').then((newSchema: FormSchema | undefined) => { if (!newSchema) { notifyService.error('未获取到表单Schema!'); return; } - const newVariables = newSchema.variables || []; - - // 更新表单Schema中的变量 - schema.variables = newVariables; - - // 更新视图模型中的变量 - useFormSchema.updateRemoteVariables(newVariables); - - // 更新表格数据,并取消选中 - loadVariables(); - gridComponentInstance.value.updateDataSource(variableList.value); - gridComponentInstance.value.clearSelection(); - - notifyService.success('更新成功!'); + updateRemoteVariables(currentSchema, newSchema); }); } @@ -247,7 +331,6 @@ export function useVariableData(gridComponentInstance: Ref) { return { variableList, loadVariables, - checkUniqueCode, deleteVariables, addVariableToDataGrid, updateVariableToViewModel, diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts index c0bcc7c4cff..42dc3a69095 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -1,33 +1,20 @@ -import { DataColumn, EditorConfig, FNotifyService, VisualData, VisualDataCell } from "@farris/ui-vue/components"; -import { FormVariable, FormVariableCategories, FormVariableCategory, FormVariableTypes, UseFormSchema } from "../../../../../components/types"; +import { DataColumn, EditorConfig, FNotifyService } from "@farris/ui-vue/components"; +import { FormVariable, FormVariableCategory, UseFormSchema } from "../../../../../components/types"; import { inject } from "vue"; -import renderVariableCell from "../components/variable-cell.component"; import { useVariableDefaultValue } from "./use-variable-default-value"; +import codeAndNameColumnFormatter from "../formatters/code-and-name-column-formatter"; +import defaultValueColumnFormatter from "../formatters/default-value-column-formatter"; +import typeColumnFormatter from "../formatters/type-column-formatter"; /** * 获取表格配置 */ export function useVariableDataGridOptions() { const useFormSchema = inject('useFormSchema') as UseFormSchema; - /** 检查默认值格式 */ const { showDefaultValueEditor } = useVariableDefaultValue(); const notifyService: FNotifyService = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; - /** 列配置 */ - const columnOption = { - fitColumns: true, - fitMode: 'percentage' - }; - - /** 选择行配置 */ - const selectionOption = { - enableSelectRow: true, - multiSelect: true, - showCheckbox: true, - showSelectAll: true - }; - /** * 表格列配置 */ @@ -38,7 +25,7 @@ export function useVariableDataGridOptions() { dataType: 'string', width: 120, resizable: true, - formatter: renderVariableCell + formatter: codeAndNameColumnFormatter }, { field: 'name', @@ -46,15 +33,16 @@ export function useVariableDataGridOptions() { dataType: 'string', width: 120, resizable: true, - formatter: renderVariableCell + formatter: codeAndNameColumnFormatter }, { field: 'type', title: '变量类型', dataType: 'enum', - valign: 'middle', - formatter: renderVariableCell, + width: 120, + resizable: true, + formatter: typeColumnFormatter, editor: { type: 'combo-list', data: [ @@ -75,11 +63,15 @@ export function useVariableDataGridOptions() { dataType: 'string', width: 120, resizable: true, - formatter: renderVariableCell, + formatter: defaultValueColumnFormatter, }, { field: 'category', - title: "变量类型", + title: "变量分类", + dataType: 'string', + width: 120, + resizable: true, + readonly: true, formatter: { type: 'enum', data: [ @@ -95,12 +87,7 @@ export function useVariableDataGridOptions() { { id: 'locale', name: '组件变量' }, { id: 'remote', name: '表单变量' }, ] - }, - dataType: 'string', - width: 120, - resizable: true, - readonly: true - + } }, { field: 'sourceName', @@ -112,8 +99,14 @@ export function useVariableDataGridOptions() { } ] + function getColumns() { + return columns; + } + /** * 获取数字类变量的编辑器配置 + * @param variable + * @returns */ function getNumberVariableEditor(variable: FormVariable): EditorConfig { const editorConfig: EditorConfig = { @@ -122,32 +115,45 @@ export function useVariableDataGridOptions() { max: 100000000 }; - // 组件变量没有精度 - if (variable.category === FormVariableCategory.locale) { - return editorConfig; - } - - // 获取表单Schema中记录的表单变量 const schemas = useFormSchema.getSchemas(); - if (!schemas) { + // 1、组件变量需要设置精度 + const needSetPrecision = schemas && variable.category === FormVariableCategory.remote; + if (!needSetPrecision) { return editorConfig; } - const remoteVariables = schemas.variables || []; - const remoteVariable = remoteVariables.find(remoteVariable => remoteVariable.id === variable.id); - if (remoteVariable && remoteVariable.type) { - editorConfig.precision = remoteVariable.type.precision; + // 2、从表单Schema中查找变量 + const variablesInSchemas = schemas.variables || []; + const variablesInSchema = variablesInSchemas.find(variablesInSchema => variablesInSchema.id === variable.id); + + // 3、设置编辑器的精度 + if (variablesInSchema && variablesInSchema.type) { + editorConfig.precision = variablesInSchema.type.precision; } return editorConfig; } - function updateDefaultValueColumnEditor(variable: FormVariable, cell: any) { - const variableType = variable.type; + /** + * 更新默认值列的编辑器 + * @param cell + * @returns + */ + function updateDefaultValueColumnEditor(cell: any) { + // 修改默认值列前,需要更新编辑器 + const { field } = cell.column; + const needUpdateEditor = field === 'value'; + if (!needUpdateEditor) { + return; + } + + const variable: FormVariable = cell.row.raw; const defaultValueColumn = columns.find(column => column.field === 'value'); if (!defaultValueColumn) { return; } + + const variableType = variable.type; switch (variableType) { case 'Number': { defaultValueColumn.editor = getNumberVariableEditor(variable); @@ -209,10 +215,32 @@ export function useVariableDataGridOptions() { } } + /** + * 获取单元格状态,是否可以修改 + * @param cell + * @returns + */ + function getCellState(cell: any) { + const variable: FormVariable = cell.row.raw; + const { field } = cell.column; + + switch (field) { + case 'code': + case 'name': + case 'type': { + // 只有组件变量的编号、名称、类型可以修改 + const canEditCell = variable.category === FormVariableCategory.locale; + return canEditCell; + } + default: { + return true; + } + } + } + return { - columns, - columnOption, - selectionOption, - updateDefaultValueColumnEditor + getColumns, + updateDefaultValueColumnEditor, + getCellState }; } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts index 23113f5b206..8ec31333cd5 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-default-value.ts @@ -1,23 +1,23 @@ import { FNotifyService } from "@farris/ui-vue/components"; import { FormVariable } from "../../../../types"; -import getArrayObjectEditor from '../components/array-object-editor.component'; +import { useArrayAndObjectEditor } from "./use-array-and-object-editor"; export function useVariableDefaultValue() { const notifyService: FNotifyService = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; - const { showArrayObjectEditor } = getArrayObjectEditor(); + const { showArrayAndObjectEditor } = useArrayAndObjectEditor(); /** * 将字符串类型的默认值转换为对象类型,用于DOM存储。 * @param variable * @returns */ - function resolveDefaultValueInViewModel(variable: FormVariable) { + function resolveDefaultValueInViewModel(variable: FormVariable): any { if (variable.value === undefined || variable.value === null || variable.value === '') { - return undefined; + return; } - - if (variable.type === 'Object' || variable.type === 'Array') { + const isObjectOrArray = variable.type === 'Object' || variable.type === 'Array'; + if (isObjectOrArray) { try { return JSON.parse(variable.value); @@ -27,9 +27,12 @@ export function useVariableDefaultValue() { return; } } + + // 若默认值中有单引号,会引起编译错误。这里强制替换掉默认值中的单引号 if (typeof (variable.value) === 'string') { return variable.value.trim().replace(/'/g, ''); } + return variable.value; } @@ -39,94 +42,106 @@ export function useVariableDefaultValue() { * @param variable * @returns */ - function resolveDefaultValueInEditor(variable: FormVariable) { + function resolveDefaultValueInEditor(variable: FormVariable): any { if (!variable || !variable.value) { - return; + return variable.value; } - if (variable.type === 'Object' || variable.type === 'Array') { + const isObjectOrArray = variable.type === 'Object' || variable.type === 'Array'; + if (isObjectOrArray) { try { - variable.value = JSON.stringify(variable.value, null, 4); + return JSON.stringify(variable.value, null, 4); } catch (error) { console.error(error); notifyService.error('解析默认值失败'); return; } } + + return variable.value; } /** * 清空变量的默认值 * @param cell */ - function clearDefaultValue(cell: any) { - if (cell.column.field !== 'type') { + function clearDefaultValueWhenModifyType(cell: any) { + // 1、修改类型列后,需要清空默认值 + const { field } = cell.column; + const needClearDefaultValue = field === 'type' && cell.newValue && cell.newValue !== cell.oldValue; + if (!needClearDefaultValue) { return; } - // 修改变量类型后,清除变量的默认值 - if (cell.newValue && cell.newValue !== cell.oldValue) { - cell.row.data.value.updateData({ - value: undefined - }); - notifyService.warning('修改变量类型后,自动清除默认值'); + + // 2、清空默认值 + cell.row.data.value.updateData({ + value: undefined + }); + notifyService.warning('修改变量类型后,自动清除默认值'); + + } + + function checkObjectValid(defaultValue: any): boolean { + try { + const object = JSON.parse(defaultValue); + const isNotObject = !object || typeof (object) !== 'object' || Array.isArray(object); + if (isNotObject) { + notifyService.error('默认值不是对象格式,请检查。'); + return false; + } + } catch (error) { + console.error(error); + notifyService.error('默认值不是对象格式,请检查。'); + return false; } + return true; + } + function checkArrayValid(defaultValue: any): boolean { + try { + const array = JSON.parse(defaultValue); + const isNotArray = !array || typeof (array) !== 'object' || !Array.isArray(array); + if (isNotArray) { + notifyService.error('默认值不是数组格式,请检查。'); + return false; + } + } catch (error) { + console.error(error); + notifyService.error('默认值不是数组格式,请检查。'); + return false; + } + return true; } /** * 校验默认值格式是否正确 */ - function checkDefaultValueValid(variableType: string, defaultValue: string): string | undefined { + function checkDefaultValueValid(variableType: string, defaultValue: any): boolean { if (!defaultValue) { - return; + return true; } switch (variableType) { case 'Object': { - try { - const object = JSON.parse(defaultValue); - if (!object || typeof (object) !== 'object' || Array.isArray(object)) { - return '默认值不是对象格式,请检查。'; - } - } catch (error) { - console.error(error); - return '默认值不是对象格式,请检查。'; - } - break; + return checkObjectValid(defaultValue); } case 'Array': { - try { - const array = JSON.parse(defaultValue); - if (!array || typeof (array) !== 'object' || !Array.isArray(array)) { - return '默认值不是数组格式,请检查。'; - } - } catch (error) { - console.error(error); - return '默认值不是数组格式,请检查。'; - } - break; + return checkArrayValid(defaultValue); } - case 'String': case 'Text': { - // 若默认值中有单引号,会引起编译错误。这里强制替换掉默认值中的单引号 - if (typeof (defaultValue) === 'string' && defaultValue.indexOf('\'') > -1) { - defaultValue = defaultValue.trim().replace(/'/g, ''); - return; - } + default: { + return true; } } - } - /** * 打开默认值编辑器 */ - function showDefaultValueEditor(variable: FormVariable,cell: any) { + function showDefaultValueEditor(variable: FormVariable, cell: any) { const currentValue = variable.value; - // 确认框的回调函数 - const confirmHandler = (value: any):boolean => { - const result = checkDefaultValueValid(variable.type,value); - if(result){ - notifyService.error(result); + // 1、确认框的回调函数 + const confirmHandler = (value: any): boolean => { + const checkPassed = checkDefaultValueValid(variable.type, value); + if (!checkPassed) { return false; } @@ -135,15 +150,14 @@ export function useVariableDefaultValue() { }); return true; }; - // 显示数组和对象的编辑器 - showArrayObjectEditor(currentValue,confirmHandler); + // 2、显示数组和对象的编辑器 + showArrayAndObjectEditor(currentValue, confirmHandler); } return { resolveDefaultValueInViewModel, resolveDefaultValueInEditor, - checkDefaultValueValid, - clearDefaultValue, + clearDefaultValueWhenModifyType, showDefaultValueEditor } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/code-and-name-column-formatter.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/code-and-name-column-formatter.tsx new file mode 100644 index 00000000000..d3f43d72490 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/code-and-name-column-formatter.tsx @@ -0,0 +1,22 @@ +import { VisualData, VisualDataCell } from "@farris/ui-vue/components"; +import { FormVariableCategory } from "../../../../types"; +import { JSX } from "vue/jsx-runtime"; + +/** + * 变量编号和名称列格式化器 + * 1、显示编辑图标 + */ +export default function codeAndNameColumnFormatter(visualDataCell: VisualDataCell, visualDataRow: VisualData): () => JSX.Element { + const { data: displayText } = visualDataCell; + const { category: variableCategory } = visualDataRow.raw; + // 组件变量的单元格显示编辑图标 + const showEditIcon = variableCategory === FormVariableCategory.locale; + + return ( +
+ {displayText} + {showEditIcon && } +
+ ); + +} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx new file mode 100644 index 00000000000..0215e637d80 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx @@ -0,0 +1,19 @@ +import { VisualData, VisualDataCell } from "@farris/ui-vue/components"; +import { JSX } from "vue/jsx-runtime"; + +/** + * 变量默认值列格式化器 + * 1、显示下拉图标 + */ +export default function defaultValueColumnFormatter(visualDataCell: VisualDataCell, visualDataRow: VisualData): () => JSX.Element { + const { data } = visualDataCell; + const displayText = data; + + return ( +
+ {displayText} + +
+ ); + +} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/type-column-formatter.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/type-column-formatter.tsx new file mode 100644 index 00000000000..a633f791be0 --- /dev/null +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/type-column-formatter.tsx @@ -0,0 +1,41 @@ +import { VisualData, VisualDataCell } from "@farris/ui-vue/components"; +import { FormVariableTypes, FormVariableCategory } from "../../../../types"; +import { JSX } from "vue/jsx-runtime"; + +/** + * 变量类型列格式化器 + * 1、显示变量类型名称 + * 2、显示下拉图标 + */ +export default function typeColumnFormatter(visualDataCell: VisualDataCell, visualDataRow: VisualData): () => JSX.Element { + const { data: cellValue } = visualDataCell; + const { category: variableCategory } = visualDataRow.raw; + // 组件变量的单元格显示下拉图标 + const showDropDownIcon = variableCategory === FormVariableCategory.locale; + + /** + * 格式化单元格数据 + * @returns + */ + function formatCellData(): string { + let displayText = cellValue; + + // 1、获取变量类型信息 + const formVariableType = FormVariableTypes.find(vriableType => vriableType.value === cellValue); + + // 2、展示变量类型的名称 + if (formVariableType) { + displayText = formVariableType.text; + } + + return displayText; + } + + return ( +
+ {formatCellData()} + {showDropDownIcon && } +
+ ); + +} diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index 59695849522..70ae1805cbb 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -3,8 +3,8 @@ import { FDataGrid } from "@farris/ui-vue/components"; import { variableManagerProps, VariableManagerProps } from "./variable-manager.props"; import './variable-manager.scss'; import { useVariableData } from "./composition/use-variable-data"; -import { FormVariable, FormVariableCategory } from "../../../../components/types"; -import {useVariableDataGridOptions} from "./composition/use-variable-datagrid-options"; +import { FormVariable } from "../../../../components/types"; +import { useVariableDataGridOptions } from "./composition/use-variable-datagrid-options"; import { useVariableDefaultValue } from "./composition/use-variable-default-value"; export default defineComponent({ @@ -15,10 +15,22 @@ export default defineComponent({ /** 表格实例 */ const gridComponentInstance = ref(); - /** 表格配置 */ - const { columns, columnOption, selectionOption, updateDefaultValueColumnEditor } = useVariableDataGridOptions(); + /** 列配置 */ + const columnOption = { + fitColumns: true, + fitMode: 'percentage' + }; + /** 选择行配置 */ + const selectionOption = { + enableSelectRow: true, + multiSelect: true, + showCheckbox: true, + showSelectAll: true + }; + /** 表格配置相关方法 */ + const { getColumns, updateDefaultValueColumnEditor, getCellState } = useVariableDataGridOptions(); /** 变量默认值相关方法 */ - const { clearDefaultValue } = useVariableDefaultValue(); + const { clearDefaultValueWhenModifyType } = useVariableDefaultValue(); /** 变量数据相关方法 */ const { variableList, loadVariables, deleteVariables, addVariableToDataGrid, updateVariableToViewModel, refreshRemoteVariables } = useVariableData(gridComponentInstance); loadVariables(); @@ -57,20 +69,12 @@ export default defineComponent({ * @param cell */ function onBeforeEditCell(cell: any) { - const variable: FormVariable = cell.row.raw; - const { field } = cell.column; - // 编辑默认值单元格前,需要更新默认值单元格的编辑器 - if (field === 'value') { - updateDefaultValueColumnEditor(variable, cell); - return true; - } + // 1、更新默认值单元格的编辑器 + updateDefaultValueColumnEditor(cell); - // 表单变量的编号、名称、类型不支持修改 - if (variable.category === FormVariableCategory.remote && ['code', 'name', 'type'].includes(field)) { - return false; - } - - return true; + // 2、判断当前单元格是否可编辑 + const cellCanEdit = getCellState(cell); + return cellCanEdit; }; /** @@ -88,10 +92,10 @@ export default defineComponent({ */ function onEndEditCell(cell: any) { const variable: FormVariable = cell.row.raw; - // 修改类型列后,清空默认值 - clearDefaultValue(cell); + // 1、修改类型列后,清空默认值 + clearDefaultValueWhenModifyType(cell); - // 修改变量后,更新变量到视图模型 + // 2、修改变量后,更新变量到视图模型 const changedOject = { field: cell.column.field, value: cell.newValue, @@ -101,7 +105,6 @@ export default defineComponent({ context.expose({ refreshVariableManager }) - return () => { return (
@@ -126,7 +129,7 @@ export default defineComponent({
Date: Mon, 10 Mar 2025 16:33:51 +0800 Subject: [PATCH 15/34] =?UTF-8?q?chore:=20=E8=B0=83=E6=95=B4=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composition/use-variable-data.ts | 1 + .../use-variable-datagrid-options.ts | 25 +++++++++++-------- .../variable-manager.component.tsx | 4 +-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts index 20d3c4ae340..093f1b0f39d 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -207,6 +207,7 @@ export function useVariableData(gridComponentInstance: Ref) { } const variableCode = variable.code && variable.code.trim(); const variableName = variable.name && variable.name.trim(); + // 2、变量编号、名称、类型不能为空 if (!variableCode || !variableName || !variable.type) { return false; diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts index 42dc3a69095..46e44a09390 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-datagrid-options.ts @@ -134,25 +134,28 @@ export function useVariableDataGridOptions() { return editorConfig; } + function checkBeforeUpdateColumnEditor(cell: any): boolean { + // 修改默认值列前,需要更新编辑器 + const { field } = cell.column; + const needUpdateEditor = field === 'value'; + return needUpdateEditor; + } + /** * 更新默认值列的编辑器 * @param cell * @returns */ function updateDefaultValueColumnEditor(cell: any) { - // 修改默认值列前,需要更新编辑器 - const { field } = cell.column; - const needUpdateEditor = field === 'value'; - if (!needUpdateEditor) { + // 1、检查是否需要更新编辑器 + const checkPassed = checkBeforeUpdateColumnEditor(cell); + if (!checkPassed) { return; } - + + // 2、更新编辑器 const variable: FormVariable = cell.row.raw; - const defaultValueColumn = columns.find(column => column.field === 'value'); - if (!defaultValueColumn) { - return; - } - + const defaultValueColumn = columns.find(column => column.field === 'value') as DataColumn; const variableType = variable.type; switch (variableType) { case 'Number': { @@ -228,7 +231,7 @@ export function useVariableDataGridOptions() { case 'code': case 'name': case 'type': { - // 只有组件变量的编号、名称、类型可以修改 + // 组件变量的编号、名称、类型可以修改 const canEditCell = variable.category === FormVariableCategory.locale; return canEditCell; } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index 70ae1805cbb..923982799a3 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -73,8 +73,8 @@ export default defineComponent({ updateDefaultValueColumnEditor(cell); // 2、判断当前单元格是否可编辑 - const cellCanEdit = getCellState(cell); - return cellCanEdit; + const canEditCell = getCellState(cell); + return canEditCell; }; /** -- Gitee From a80d5a4eee3b9b78249f43b09a190f3f482a3edd Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 11 Mar 2025 09:38:17 +0800 Subject: [PATCH 16/34] =?UTF-8?q?feature:=20=E6=94=AF=E6=8C=81=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../custom-class-editor.component.tsx | 153 ++++++++++++++++++ .../custom-class-editor.props.ts | 6 + .../custom-class-editor.scss | 20 +++ .../form-designer/form-designer.component.tsx | 36 ++++- .../src/components/designer.component.tsx | 2 + 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx create mode 100644 packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.props.ts create mode 100644 packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.scss diff --git a/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx new file mode 100644 index 00000000000..ebfbac7f3d1 --- /dev/null +++ b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx @@ -0,0 +1,153 @@ +import { SetupContext, defineComponent, ref, computed, inject, onBeforeMount } from "vue"; +import { FNotifyService, FSplitter, FSplitterPane } from "@farris/ui-vue/components"; +import { FormViewModel, UseFormSchema } from "../../../../types"; +import { useViewModelNavigation } from "../../../view-model-designer/method-manager/composition/use-view-model-list"; +import MonacoEditor from '../../../monaco-editor/monaco-editor.component'; +import './custom-class-editor.scss'; +import { CustomClassEditorProps, customClassEditorProps } from "./custom-class-editor.props"; + +export default defineComponent({ + name: 'FCustomClassEditor', + props: customClassEditorProps, + emits: [] as (string[] & ThisType) | undefined, + setup(props: CustomClassEditorProps, context: SetupContext) { + const useFormSchema = inject('useFormSchema') as UseFormSchema; + const notifyService = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + const formSchema = useFormSchema.getFormSchema(); + + /** 生成视图模型导航数据 */ + const { resolveViewModelList } = useViewModelNavigation(); + const viewModelNavigation = resolveViewModelList(); + /** 当前视图模型 */ + const activeViewModel = ref(viewModelNavigation?.activeViewModel); + /** 视图模型导航数据 */ + const viewModelNavgationData = ref(viewModelNavigation?.viewModelTabs); + + const monacoEditorRef = ref(); + /** 自定义样式Dom */ + formSchema.module.customClass ??= {}; + const { customClass } = formSchema.module; + /** 当前编辑器内的样式代码 */ + const currentClassCode = ref(); + + /** 视图模型页签的样式 */ + const viewModelTabClass = computed(() => (viewModelTabId: string) => { + const showActiceClass = activeViewModel.value?.id === viewModelTabId; + return { 'f-listview-active': showActiceClass }; + }); + + /** + * 获取当前视图模型关联的组件内码 + * @returns + */ + function getCurrentComponentId(): string | undefined { + const activeViewModelId = activeViewModel.value?.id; + if (!activeViewModelId) { + return; + } + const currentComponent = useFormSchema.getComponentByViewModelId(activeViewModelId); + return currentComponent?.id; + } + + /** + * 保存自定义样式 + */ + function saveCustomClass() { + const currentComponentId = getCurrentComponentId(); + if (!currentComponentId) { + return; + } + + const oldClassCode = customClass[currentComponentId]; + const newClassCode = monacoEditorRef.value?.getContent(); + // 样式变化后,进行更新 + if (oldClassCode !== newClassCode) { + customClass[currentComponentId] = newClassCode; + } + } + + /** + * 更新编辑器中的样式代码 + */ + function updateClassCodeInEditor() { + const currentComponentId = getCurrentComponentId(); + if (!currentComponentId) { + return; + } + currentClassCode.value = customClass[currentComponentId]; + } + + /** + * 切换视图模型导航 + */ + function onChangeViewModelTab(nextViewModel: FormViewModel) { + const lastViewModelId = activeViewModel.value?.id; + const nextViewModelId = nextViewModel.id; + + // 1、点击当前页签,无需处理 + if (lastViewModelId === nextViewModelId) { + return; + } + + // 2、保存自定义样式 + saveCustomClass(); + + // 3、更新当前选中的页签 + activeViewModel.value = nextViewModel; + + // 4、更新编辑器内的样式代码 + updateClassCodeInEditor(); + } + + onBeforeMount(() => { + updateClassCodeInEditor(); + }); + + context.expose({ + saveCustomClass + }); + + /** + * 渲染左侧导航 + */ + function renderViewModelNavgation() { + return
    + { + viewModelNavgationData.value?.map((viewModel: any) => { + return
    onChangeViewModelTab(viewModel)}> +
    +
    + +
    +
    +
    ; + }) + } +
; + } + + return () => { + return ( +
+ + +
+ {renderViewModelNavgation()} +
+
+ + + +
+
+ ); + }; + } +}); + diff --git a/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.props.ts b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.props.ts new file mode 100644 index 00000000000..f819c3e1c70 --- /dev/null +++ b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.props.ts @@ -0,0 +1,6 @@ +import { ExtractPropTypes } from "vue"; + +export const customClassEditorProps = { +} as Record; + +export type CustomClassEditorProps = ExtractPropTypes; diff --git a/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.scss b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.scss new file mode 100644 index 00000000000..89ff4d81426 --- /dev/null +++ b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.scss @@ -0,0 +1,20 @@ +.f-custom-class-editor { + height: 100%; + display: flex; + flex-direction: column; + padding-left: 10px; + + .view-model-list { + overflow: auto; + height: 100%; + background: #fcfdff !important; + + ul { + padding: 0; + } + + .f-template-listnav-row .list-nav-link .nav-item-name { + opacity: 1; + } + } +} \ No newline at end of file diff --git a/packages/designer/src/components/components/form-designer/form-designer.component.tsx b/packages/designer/src/components/components/form-designer/form-designer.component.tsx index f87b2395187..6aa16c684bc 100644 --- a/packages/designer/src/components/components/form-designer/form-designer.component.tsx +++ b/packages/designer/src/components/components/form-designer/form-designer.component.tsx @@ -7,6 +7,7 @@ import modulePropertyConfig from '../../types/form-property-config.json'; import FEntityTreeView from '../entity-tree-view/components/entity-tree-view.component'; import { afterPropeControlPropertyChangedService } from "../../composition/control-property-changed.service"; import { UseDesignViewModel, UseFormSchema, UseSchemaService } from "../../types"; +import FCustomClassEditor from './components/custom-class-editor/custom-class-editor.component'; export default defineComponent({ name: 'FFormDesigner', @@ -22,6 +23,7 @@ export default defineComponent({ const controlTreeRef = ref(); const entityTreeRef = ref(); const monacoEditorRef = ref(); + const customClassEditorRef = ref(); function onCanvasInitialized(dragula: any) { dragulaCompostion.value = dragula; @@ -78,6 +80,12 @@ export default defineComponent({ /** 代码编辑器的显示文本 */ const formSchemaCodes = ref(''); function onChangeDesignerView(viewName: string) { + // 从自定义样式页面切换到其它页面时,保存自定义样式 + const needSaveCustomClass = activeDesignerView.value === 'customClassEditor'; + if (needSaveCustomClass) { + customClassEditorRef.value?.saveCustomClass(); + } + activeDesignerView.value = viewName; if (viewName === 'formDesignerCode') { formSchemaCodes.value = JSON.stringify(schema.value, null, 4); @@ -104,6 +112,14 @@ export default defineComponent({ }; }); + const customClassEditorClass = computed(() => { + return { + 'pl-2 pr-2 d-flex': true, + 'f-designer-view-tabs-item': true, + 'active': activeDesignerView.value === 'customClassEditor' + }; + }); + propertyConfigSchemaMap['Module'] = modulePropertyConfig; function onOutlineChanged(selectionSchema: any) { if (selectionSchema?.type === 'Module') { @@ -129,7 +145,19 @@ export default defineComponent({ propertyPanelInstance?.value.refreshPanel(); propertyPanelInstance?.value.reloadPropertyPanel(); } - context.expose({ reloadPropertyPanel, onChangeDesignerView }); + + /** + * 保存前准备 + */ + function prepareBeforeSaveForm() { + // 在自定义样式页面保存表单时,需要同步保存自定义样式 + const needSaveCustomClass = activeDesignerView.value === 'customClassEditor'; + if(needSaveCustomClass){ + customClassEditorRef.value?.saveCustomClass(); + } + } + + context.expose({ reloadPropertyPanel, onChangeDesignerView, prepareBeforeSaveForm }); function onEntityUpdated() { onCanvasChanged(); @@ -187,12 +215,18 @@ export default defineComponent({ + +
onChangeDesignerView('formDesigner')} class={formDesignerViewClass.value}>可视化设计器
onChangeDesignerView('formDesignerCode')} class={formDesignerCodeViewClass.value}>设计时代码
+
onChangeDesignerView('customClassEditor')} + class={customClassEditorClass.value}>自定义样式
diff --git a/packages/designer/src/components/designer.component.tsx b/packages/designer/src/components/designer.component.tsx index 8e99d528bb2..0b015c12e6e 100644 --- a/packages/designer/src/components/designer.component.tsx +++ b/packages/designer/src/components/designer.component.tsx @@ -136,6 +136,8 @@ export default defineComponent({ * 保存表单 */ function saveFormMetadata(needRunForm: boolean = false) { + formDesignerRef.value?.prepareBeforeSaveForm(); + const loadingInstance = loadingService?.show({ message: '保存中,请稍候...' }); useFormMetadataComposition.saveFormMetadata().then(() => { !needRunForm && notifyService.success({ message: '表单保存成功' }); -- Gitee From 769d8a7d21689cb8c79cdf873336ba4e06319a2f Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 11 Mar 2025 15:36:31 +0800 Subject: [PATCH 17/34] =?UTF-8?q?feature:=20=E5=AE=8C=E5=96=84=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../custom-class-editor.component.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx index ebfbac7f3d1..880b9473695 100644 --- a/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx +++ b/packages/designer/src/components/components/form-designer/components/custom-class-editor/custom-class-editor.component.tsx @@ -68,9 +68,9 @@ export default defineComponent({ } /** - * 更新编辑器中的样式代码 + * 设置当前的样式代码,以供编辑器显示 */ - function updateClassCodeInEditor() { + function updateCurrentClassCode() { const currentComponentId = getCurrentComponentId(); if (!currentComponentId) { return; @@ -96,12 +96,12 @@ export default defineComponent({ // 3、更新当前选中的页签 activeViewModel.value = nextViewModel; - // 4、更新编辑器内的样式代码 - updateClassCodeInEditor(); + // 4、重新设置当前的样式代码 + updateCurrentClassCode(); } onBeforeMount(() => { - updateClassCodeInEditor(); + updateCurrentClassCode(); }); context.expose({ -- Gitee From fa26ba51aa318016fbedd374ca13da214c84cf12 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 17 Mar 2025 20:51:14 +0800 Subject: [PATCH 18/34] =?UTF-8?q?feature:=20=E6=8F=90=E4=BE=9B=E5=A4=9A?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=B1=9E=E6=80=A7=E5=80=BC=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/composition/use-type-resolver.ts | 3 +- .../components/dynamic-form/src/types.ts | 3 +- .../dynamic-view/src/components/maps.ts | 2 + .../components/property-editor/index.ts | 10 +- .../const/const-property.component.tsx | 120 ++++ .../src/components/const/const-property.css | 6 + .../components/const/const-property.props.ts | 29 + .../custom/custom-property.component.tsx | 55 ++ .../src/components/custom/custom-property.css | 6 + .../custom/custom-property.props.ts | 24 + .../state-machine-property.component.tsx | 113 +++ .../state-machine/state-machine-property.css | 53 ++ .../state-machine-property.props.ts | 27 + .../variable/variable-property.component.tsx | 162 +++++ .../components/variable/variable-property.css | 42 ++ .../variable/variable-property.props.ts | 33 + .../property-editor/src/composition/data.ts | 367 +--------- .../property-editor/src/composition/type.ts | 153 ++-- .../src/composition/use-initialized-value.ts | 140 ---- .../src/composition/use-property-type.ts | 144 ++++ .../src/composition/use-property-value.ts | 44 ++ .../src/composition/use-state-machine.ts | 65 ++ .../src/composition/use-update-data.ts | 186 ----- .../src/composition/use-variable.ts | 105 +++ .../src/property-editor.component.tsx | 651 ++---------------- .../property-editor/src/property-editor.css | 178 +---- .../src/property-editor.props.ts | 19 +- .../src/schema/property-editor.schema.json | 33 + .../composition/entity/input-base-property.ts | 14 +- 29 files changed, 1245 insertions(+), 1542 deletions(-) create mode 100644 packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx create mode 100644 packages/ui-vue/components/property-editor/src/components/const/const-property.css create mode 100644 packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts create mode 100644 packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx create mode 100644 packages/ui-vue/components/property-editor/src/components/custom/custom-property.css create mode 100644 packages/ui-vue/components/property-editor/src/components/custom/custom-property.props.ts create mode 100644 packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx create mode 100644 packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.css create mode 100644 packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts create mode 100644 packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx create mode 100644 packages/ui-vue/components/property-editor/src/components/variable/variable-property.css create mode 100644 packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts delete mode 100644 packages/ui-vue/components/property-editor/src/composition/use-initialized-value.ts create mode 100644 packages/ui-vue/components/property-editor/src/composition/use-property-type.ts create mode 100644 packages/ui-vue/components/property-editor/src/composition/use-property-value.ts create mode 100644 packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts delete mode 100644 packages/ui-vue/components/property-editor/src/composition/use-update-data.ts create mode 100644 packages/ui-vue/components/property-editor/src/composition/use-variable.ts diff --git a/packages/ui-vue/components/dynamic-form/src/composition/use-type-resolver.ts b/packages/ui-vue/components/dynamic-form/src/composition/use-type-resolver.ts index b50902acfc5..0a98c5ce927 100644 --- a/packages/ui-vue/components/dynamic-form/src/composition/use-type-resolver.ts +++ b/packages/ui-vue/components/dynamic-form/src/composition/use-type-resolver.ts @@ -95,7 +95,8 @@ export function useTypeResolver(): UseTypeResolver { case 'query-solution-config': case 'solution-preset': return 'onFieldsChanged'; - + case 'property-editor': + return 'onValueChange'; } } diff --git a/packages/ui-vue/components/dynamic-form/src/types.ts b/packages/ui-vue/components/dynamic-form/src/types.ts index e5029eeff4c..555bfffb03a 100644 --- a/packages/ui-vue/components/dynamic-form/src/types.ts +++ b/packages/ui-vue/components/dynamic-form/src/types.ts @@ -2,7 +2,8 @@ export type EditorType = 'button-edit' | 'check-box' | 'check-group' | 'combo-li 'date-picker' | 'date-range' | 'datetime-picker' | 'datetime-range' | 'events-editor' | 'month-picker' | 'month-range' | 'year-picker' | 'year-range' | 'input-group' | 'lookup' | 'number-range' | 'number-spinner' | 'radio-group' | 'text' | 'response-layout-editor-setting' | 'switch' | 'grid-field-editor' | 'field-selector' | 'schema-selector' | 'mapping-editor' | - 'textarea' | 'response-form-layout-setting'|'binding-selector' | 'query-solution-config' | 'solution-preset' | 'item-collection-editor'; + 'textarea' | 'response-form-layout-setting'|'binding-selector' | 'query-solution-config' | 'solution-preset' | 'item-collection-editor' | + 'property-editor'; export interface EditorConfig { /** 编辑器类型 */ diff --git a/packages/ui-vue/components/dynamic-view/src/components/maps.ts b/packages/ui-vue/components/dynamic-view/src/components/maps.ts index 96bb31c94a5..a859da777e2 100644 --- a/packages/ui-vue/components/dynamic-view/src/components/maps.ts +++ b/packages/ui-vue/components/dynamic-view/src/components/maps.ts @@ -60,6 +60,7 @@ import FTreeGrid from '@farris/ui-vue/components/tree-grid'; import FEventParameter from '@farris/ui-vue/components/event-parameter'; // import FExternalContainer from '@farris/ui-vue/components/external-container'; import FFieldset from '@farris/ui-vue/components/fieldset'; +import FPropertyEditor from '@farris/ui-vue/components/property-editor'; const componentMap: Record = {}; const componentPropsConverter: Record = {}; @@ -134,6 +135,7 @@ function loadRegister() { FBindingSelector.register(componentMap, componentPropsConverter, componentPropertyConfigConverter, resolverMap); FEventParameter.register(componentMap, componentPropsConverter, componentPropertyConfigConverter, resolverMap); FFieldset.register(componentMap, componentPropsConverter, componentPropertyConfigConverter, resolverMap); + FPropertyEditor.register(componentMap, componentPropsConverter, componentPropertyConfigConverter, resolverMap); } } diff --git a/packages/ui-vue/components/property-editor/index.ts b/packages/ui-vue/components/property-editor/index.ts index 02947dd5878..4b58d5c871c 100644 --- a/packages/ui-vue/components/property-editor/index.ts +++ b/packages/ui-vue/components/property-editor/index.ts @@ -1,4 +1,4 @@ - + /** * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. * @@ -15,19 +15,19 @@ * limitations under the License. */ import type { App } from 'vue'; -import propertyEditor from './src/property-editor.component'; +import PropertyEditor from './src/property-editor.component'; import { propsResolver } from './src/property-editor.props'; export * from './src/property-editor.props'; -export { propertyEditor }; +export { PropertyEditor }; export default { install(app: App): void { - app.component(propertyEditor.name as string, propertyEditor); + app.component(PropertyEditor.name as string, PropertyEditor); }, register(componentMap: Record, propsResolverMap: Record, configResolverMap: Record, resolverMap: Record): void { - componentMap['property-editor'] = propertyEditor; + componentMap['property-editor'] = PropertyEditor; propsResolverMap['property-editor'] = propsResolver; } }; diff --git a/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx new file mode 100644 index 00000000000..f224c83079f --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx @@ -0,0 +1,120 @@ +/** + * 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 { computed, Ref, ref, SetupContext } from 'vue'; +import { ConstPropertyProps, ConstType } from './const-property.props'; +import { FComboList } from '@farris/ui-vue/components/combo-list'; +import { FNumberSpinner } from '@farris/ui-vue/components/number-spinner'; +import './const-property.css'; +import { ConstEnumItem, UsePropertyValue } from '../../composition/type'; + +export default function ( + props: ConstPropertyProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +) { + const readOnly = ref(false); + + /** 静态值类型:number, enum */ + const constType: Ref = ref(props.constType); + /** 静态值的枚举项(静态值类型为enum时使用) */ + const constEnums: Ref = ref(props.constEnums); + + /** 属性值相关方法 */ + const { getPropertyValue, triggerValueChange } = usePropertyValueComposition; + const propertyValue = getPropertyValue('const'); + + /** 控制右侧区域显示的内容 */ + const shouldShowContent = computed(() => (type: string) => { + return type === constType.value; + }); + + /** + * 设置常量的属性值 + */ + function setConstValue(newValue:any) { + triggerValueChange(newValue); + } + + /** + * 数值控件值变化 + * @param value + */ + function onNumberValueChange(value: number) { + setConstValue(value); + } + + /** + * 下拉列表控件值变化 + * @param constEnumItems + * @returns + */ + function onComboListValueChange(constEnumItems: ConstEnumItem[]) { + if (!constEnumItems || constEnumItems.length < 1) { + return; + } + const selectedValue = constEnumItems[0].id; + setConstValue(selectedValue); + } + + /** + * 静态值为number类型,渲染数值控件 + * @returns + */ + function renderNumber() { + return ( + + + ); + } + + /** + * 静态值为enum类型,渲染下拉列表控件 + * @returns + */ + function renderEnum() { + return ( + + + ); + } + + return () => { + return ( +
+ {shouldShowContent.value('number') && renderNumber()} + {shouldShowContent.value('enum') && renderEnum()} +
+ ); + }; + +} + diff --git a/packages/ui-vue/components/property-editor/src/components/const/const-property.css b/packages/ui-vue/components/property-editor/src/components/const/const-property.css new file mode 100644 index 00000000000..4796a723fb2 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/const/const-property.css @@ -0,0 +1,6 @@ +.f-property-editor-const-container { + float: left; + width: 65%; + margin-left: 3%; + background: #FFFFFF; +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts b/packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts new file mode 100644 index 00000000000..8b3dfd1c951 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts @@ -0,0 +1,29 @@ + +/** + * 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 { ExtractPropTypes, PropType } from 'vue'; +import { ConstEnumItem } from '../../composition/type'; +export type ConstType = 'number' | 'enum'; + +export const constPropertyProps = { + /** 静态值的类型 */ + constType: { type: String as PropType, default: '' }, + /** 静态值的枚举项(静态值类型为enum时使用) */ + constEnums: { type: Array, default: [] }, +} as Record; + +export type ConstPropertyProps = ExtractPropTypes; + diff --git a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx new file mode 100644 index 00000000000..a9f1f38873e --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx @@ -0,0 +1,55 @@ + +/** + * 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 { Ref, ref, SetupContext } from 'vue'; +import { CustomPropertyProps } from './custom-property.props'; +import './custom-property.css'; +import { UsePropertyValue } from '../../composition/type'; +import { JSX } from 'vue/jsx-runtime'; + +export default function ( + props: CustomPropertyProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +): () => JSX.Element { + const readOnly: Ref = ref(false); + /** 属性值相关方法 */ + const { getPropertyValue, triggerValueChange } = usePropertyValueComposition; + const propertyValue: Ref = getPropertyValue('custom'); + + /** + * 文本控件值变化事件 + * @param $event + */ + function onInputValueChange($event: Event) { + const newValue = ($event.target as HTMLInputElement).value; + triggerValueChange(newValue); + } + + return () => { + return ( +
+ + +
+ ); + }; +} diff --git a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.css b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.css new file mode 100644 index 00000000000..ffa645de94e --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.css @@ -0,0 +1,6 @@ +.f-property-editor-customize-container { + width: 65%; + float: left; + margin-left: 3%; + background: #FFFFFF; +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.props.ts b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.props.ts new file mode 100644 index 00000000000..3628f1937b1 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.props.ts @@ -0,0 +1,24 @@ + +/** + * 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 { ExtractPropTypes } from 'vue'; + +export const customPropertyProps = { + +} as Record; + +export type CustomPropertyProps = ExtractPropTypes; + diff --git a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx new file mode 100644 index 00000000000..9c80ab4dd7c --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx @@ -0,0 +1,113 @@ +/** + * 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 { Ref, ref, SetupContext } from 'vue'; +import { StateMachinePropertyProps } from './state-machine-property.props'; +import { FComboList } from '@farris/ui-vue/components/combo-list'; +import './state-machine-property.css'; +import { useStateMachine } from '../../composition/use-state-machine'; +import { StateMachineItem, UsePropertyValue } from '../../composition/type'; + +export default function ( + props: StateMachinePropertyProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +) { + const readOnly = ref(false); + /** 状态机列表 */ + const stateMachines: Ref = ref(props.stateMachines); + /** 状态机相关方法 */ + const { getStateMachineValue } = useStateMachine(props, context, usePropertyValueComposition); + + /** 属性值相关方法 */ + const { triggerValueChange } = usePropertyValueComposition; + const propertyValue = getStateMachineValue(); + /** 当前状态机内码 */ + const currentStateMachineId = ref(propertyValue.value.field); + /** 状态机前缀,是或否 */ + const status = ref(propertyValue.value.status); + + /** + * 点击状态机前缀(是或否)按钮 + */ + function onButtonClick() { + status.value = !status.value; + propertyValue.value.status = status.value; + triggerValueChange(propertyValue.value); + } + + /** + * 状态机下拉框值变化 + * @param stateMachineItems + * @returns + */ + function onComboListValueChange(stateMachineItems: StateMachineItem[]) { + if (!stateMachineItems || stateMachineItems.length < 1) { + return; + } + const selectedStateMachine = stateMachineItems[0]; + propertyValue.value.field = selectedStateMachine.id; + triggerValueChange(propertyValue.value); + } + + /** + * 渲染是或否按钮 + * @returns + */ + function renderYesNoButton() { + return ( +
+ {status.value ? '是' : '否'} +
+ ); + } + + /** + * 渲染状态机下拉列表 + * @returns + */ + function renderComboList() { + return ( +
+ + +
+ + ); + } + + return () => { + return ( +
+ {renderYesNoButton()} + {renderComboList()} +
+ ); + }; + +} diff --git a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.css b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.css new file mode 100644 index 00000000000..70d83cd6adc --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.css @@ -0,0 +1,53 @@ +.f-property-editor-stateMachine-container { + width: 65%; + float: left; + margin-left: 3%; + background: #FFFFFF; + border: 1px solid #D8DCE6; + height: 26px; + border-radius: 3px; + + .f-stateMachine-status { + float: left; + width: 28px; + text-align: center; + background: #FFFFFF; + height: 20px; + margin-top: 2px; + margin-left: 5px; + padding-top: 1px; + background-color: #f4f6ff; + font-size: 13px; + font-family: PingFangSC-Regular; + color: #34495E; + } + + .f-stateMachine-combo-list { + float: right; + width: 75%; + background: #FFFFFF; + border: unset; + + .input-group { + border: unset; + box-shadow: none; + } + + .farris-combo-list .input-group { + border: 0; + box-shadow: none !important; + } + + .farris-combo-list input-group.actived .input-group { + box-shadow: none !important; + } + + .farris-combo-list .f-cmp-inputgroup.actived { + box-shadow: none !important; + } + } +} + +.f-property-editor-stateMachine-container:focus { + box-shadow: blue; +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts new file mode 100644 index 00000000000..296e5131331 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts @@ -0,0 +1,27 @@ + +/** + * 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 { ExtractPropTypes } from 'vue'; +import { StateMachineItem } from '../../composition/type'; + +export const stateMachinePropertyProps = { + /** 状态机列表 */ + stateMachines: { type: Array, default: [] }, + +} as Record; + +export type StateMachinePropertyProps = ExtractPropTypes; + diff --git a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx new file mode 100644 index 00000000000..ef114433813 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx @@ -0,0 +1,162 @@ +/** + * 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 { computed, Ref, ref, SetupContext } from 'vue'; +import { VariablePropertyProps } from './variable-property.props'; +import { FComboList } from '@farris/ui-vue/components/combo-list'; +import './variable-property.css' +import { UsePropertyValue, VariableItem, VariableValue } from '../../composition/type'; +import { useVariable } from '../../composition/use-variable'; + +export default function ( + props: VariablePropertyProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +) { + const readOnly = ref(false); + /** 变量列表 */ + const variables: Ref = ref(props.variables); + /** 控件名称,生成新变量时使用 */ + const controlName = ref(props.controlName); + /** 是否显示新增变量按钮 */ + const showAddButton = ref(!!controlName.value); + + /** 变量相关方法 */ + const { generateVariable, getVariableByPath, getVariableValue } = useVariable(props, context, usePropertyValueComposition); + /** 属性值相关方法 */ + const { triggerValueChange } = usePropertyValueComposition; + const propertyValue: Ref = getVariableValue(); + + /** 当前变量内码 */ + const currentVariableId = ref(propertyValue.value.field); + /** 变量下拉列表样式 */ + const comboListClass = computed(() => { + return [{ 'form-control-select-show': showAddButton.value }, + { 'form-control-select-hide': !showAddButton.value }]; + }); + + /** + * 设置变量属性值 + */ + function setVariableValue(variable: VariableValue, isTriggerChange: boolean) { + Object.assign(propertyValue.value, variable); + currentVariableId.value = propertyValue.value.field; + isTriggerChange && triggerValueChange(propertyValue.value); + } + + /** + * 点击新增变量按钮 + */ + function onAddButtonClick() { + // 1、生成一个新变量 + const newVariable = generateVariable(); + + // 2、检查新变量是否已经存在 + const existedVariable = getVariableByPath(newVariable.path); + + // 3、如果变量已经存在,则使用已有变量,否则使用新增变量 + if (existedVariable) { + setVariableValue(existedVariable, true); + } else { + variables.value.push(newVariable); + setVariableValue(newVariable, true); + } + } + + /** + * 显示下拉框前的回调 + */ + const beforeShowVariable = (instance: any) => { + return Promise.resolve(true); + }; + + /** + * 下拉框值变更 + * @param variableItems + */ + function onComboListValueChange(variableItems: VariableItem[]) { + if (!variableItems || variableItems.length < 1) { + return; + } + const variableItem = variableItems[0]; + const newVariable: VariableValue = { + path: variableItem.path, + fullPath: variableItem.fullPath, + field: variableItem.field, + type: "variable" + } + setVariableValue(newVariable, true); + } + + /** + * 清空变量值 + */ + function clearVariable() { + const emptyVariable: VariableValue = { type: 'variable', path: '', field: '', fullPath: '' }; + // 清空变量后,属性值不完整,不需要触发变更 + setVariableValue(emptyVariable, false); + } + + /** + * 渲染变量下拉列表 + * @returns + */ + function renderComboList() { + return ( + + + ); + } + + /** + * 渲染新增变量按钮 + * @returns + */ + function renderAddButton() { + return ( +
+ +
+ ); + } + + return () => { + return ( +
+ {renderComboList()} + {showAddButton.value && renderAddButton()} +
+ ); + }; + +} diff --git a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.css b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.css new file mode 100644 index 00000000000..5e30182cddf --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.css @@ -0,0 +1,42 @@ +.f-property-editor-variable-container { + float: left; + width: 65%; + margin-left: 3%; + .f-property-editor-variable-add-button { + margin-left: 2%; + float: left; + } + + .f-variable-button{ + width: calc(2px + .375rem + 1.4286em); + height: calc(2px + .375rem + 1.4286em); + padding: .1875rem; + border-color: transparent !important; + box-shadow: none !important; + background-color:#f0f0f0; + box-shadow: none !important; + transition: color .2s ease-in-out; + border-width: 1px; + border-radius: 3px; + } + + .f-variable-button:focus { + text-decoration: none; + outline: 0; + } + + .form-control-select-hide { + height: 28px; + margin: 0px !important; + width: 100%; + float: left; + } + + .form-control-select-show { + height: 28px; + margin: 0px !important; + width: 80%; + float: left; + } +} + diff --git a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts new file mode 100644 index 00000000000..aad22c5712f --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts @@ -0,0 +1,33 @@ + +/** + * 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 { ExtractPropTypes } from 'vue'; +import { VariableItem } from '../../composition/type'; + +export const variablePropertyProps = { + variables: { type: Array, default: [] }, + + controlName: { type: String, default: '' }, + + /** 新增变量名称的前缀 */ + newVariablePrefix: { type: String, default: '' }, + /** 新增变量的类型 */ + newVariableType: { type: String, default: '' }, + +} as Record; + +export type VariablePropertyProps = ExtractPropTypes; + diff --git a/packages/ui-vue/components/property-editor/src/composition/data.ts b/packages/ui-vue/components/property-editor/src/composition/data.ts index 1be17edcf96..04f8fcfaef7 100644 --- a/packages/ui-vue/components/property-editor/src/composition/data.ts +++ b/packages/ui-vue/components/property-editor/src/composition/data.ts @@ -1,374 +1,25 @@ -import { PropertyEditorOptions, ArchiveOfPropertyValue, PropertyEditorValueChanged } from './type'; -import {ref} from 'vue'; +import { PropertyTypeItem } from './type'; -/** 所有值-内部存档&修改ArchiveOfPropertyValue */ -export const archiveOfPropertyValue: any = ref({ - /** 常量值 */ - constValue: { - /** 值类型:常量(const), 变量(variable), 状态机(state), 自定义(custom) */ - type: 'const', - /** 属性值 */ - value: '', - }, - /** 变量值 */ - variableValue: { - type: 'variable', - value: { - category: '', - path: '', - field: '', - fullPath: '' - } - }, - /** 状态值 */ - stateValue: null, - /** 自定义属性值 */ - customValue: { - type: 'custom', - value: '' - }, - expressionValue: { - type: 'expression', - /** 用户点击弹窗内确认按钮后置为true */ - value: '', - }, - stateMachineValue: { - type: 'stateMachine', - value: '', - }, - dataStatesValue: { - type: 'dataStates', - value: '', - } -}); - -/** 左侧状态数组:常量、变量、自定义 */ -export const dropdownStatesInTotal = ref([ +/** 左侧属性类型的枚举数据 */ +export const PROPERTY_TYPE_ENUMS: PropertyTypeItem[] = [ { 'id': 'const', - 'label': '常量' + 'name': '常量' }, { 'id': 'variable', - 'label': '变量' + 'name': '变量' }, { 'id': 'custom', - 'label': '自定义' + 'name': '自定义' }, { 'id': 'stateMachine', - 'label': '状态机' + 'name': '状态机' }, { 'id': 'expression', - 'label': '表达式' - }, - { - 'id': 'dataStates', - 'label': '数据状态' - } -]); - -/** 枚举类型-默认显示const状态 */ -export const option1: PropertyEditorOptions = { - controlName: 'userName', - propertyName: 'readonly', - propertyType: 'enum', - isNewVariable: false, - propertyValue: { - // type: 'dataStates', - // value: undefined - type:'const', - value:'true' - }, - editorOptions: { - types: ['const', 'variable', 'custom', 'expression', 'stateMachine', 'dataStates'], - enums: [{ key: 'true', value: '是' }, { key: 'false', value: '否' }], - variables: [ - { - category: 'remote', - path: 'root-component.isUserNameReadonly', - field: '49311371-fd9f-4019-8611-dce4dcae97fe', - fullPath: 'isUserNameReadonly' - }, - { - category: 'remote', - path: 'isSystem', - field: '49311371-fd9f-4019-8611-dce4dcae99fe', - fullPath: 'isSystem' - } - ], - expressionConfig: { - editor: 'ExpressionEditorComponent', - beforeOpenModal: () => { - return { - editorParams: { - modalTitle: '只读编辑器', - fieldId: 'ca30ad64-c9f6-4660-ad66-38073f6bd0b5', - viewModelId: 'basic-form-viewmodel', - expType: 'readonly' - }, - value: '{\'expr\':\'DefaultFunction.Length(\\\'aaa\\\')>2\',\'sexpr\':\'\'}' - }; - }, - exprValue: { - type: 'expression', - value: { - type: 'expression', - parameters: 'ca30ad64-c9f6', - value: '{\'expr\':\'DefaultFunction.Length(\\\'aaa\\\')>2\',\'sexpr\':\'\'}' - } - }, - }, - stateMachine: [ - { - id: 'canRemove', - name: '删除', - exist: '非' - }, - { - id: 'canCancelApprove', - name: '取消提交审批', - exist: '是' - }, - { - id: 'canApprove', - name: '提交审批', - exist: '是' - }, - { - id: 'editable', - name: '可编辑', - exist: '是' - }, - { - id: 'canEdit', - name: '编辑', - exist: '是' - }, - { - id: 'canRemoveDetail', - name: '删除明细', - exist: '是' - }, - { - id: 'canAdd', - name: '新增', - exist: '是' - }, - { - id: 'canSave', - name: '保存', - exist: '是' - }, - { - id: 'canCancel', - name: '取消', - exist: '是' - }, - { - id: 'canAddDetail', - name: '新增明细', - exist: '是' - } - ], - dataStates: [ - { - textField: '制单', - titleField: '制单', - valueField: 'Billing' - }, - { - textField: '提交审批', - titleField: '提交审批', - valueField: 'SubmitApproval' - }, - { - textField: '审批通过', - titleField: '审批通过', - valueField: 'Approved' - }, - { - textField: '审批不通过', - titleField: '审批不通过', - valueField: 'ApprovalNotPassed' - } - ] - }, - /** 状态机是否有前缀viewModel.stateMachine && */ - hasPrefix: 2 -}; - -/** 枚举类型-默认显示variable状态 */ -const option2: PropertyEditorOptions = { - controlName: 'UserAge', - propertyName: 'readonly', - propertyType: 'enum', - isNewVariable: false, - propertyValue: { - type: 'variable', - value: - { - category: 'remote', - path: 'root-component.isUserAgeReadonly', - field: '49311371-fd9f-4019-8611-dce4dcae97fe', - fullPath: 'isUserAgeReadonly' - }, - }, - editorOptions: { - types: ['variable'], - enums: [{ key: 'true', value: '是' }, { key: 'false', value: '否' }], - variables: [ - { - category: 'remote', - path: 'root-component.isUserAgeReadonly', - field: '49311371-fd9f-4019-8611-dce4dcae97fe', - fullPath: 'isUserAgeReadonly' - }, - ] - } -}; - -/** 枚举类型-默认显示custom状态 */ -const option3: PropertyEditorOptions = { - controlName: 'UserAddress', - propertyName: 'readonly', - propertyType: 'enum', - isNewVariable: false, - propertyValue: { - type: 'custom', - value: '!viewModel.stateMachine["editable"]' - }, - editorOptions: { - types: ['const', 'variable', 'custom'], - enums: [{ key: 'true', value: '是' }, { key: 'false', value: '否' }], - variables: [ - { - category: 'local', - path: 'isSystem', - field: '49311371-fd9f-4019-8611-dce4dcae97fe', - fullPath: 'isSystem' - } - ] + 'name': '表达式' } -}; - -/** string类型- 默认显示const状态 */ -const option4: PropertyEditorOptions = { - controlName: 'UserAddress', - propertyName: 'readonly', - propertyType: 'string', - isNewVariable: false, - propertyValue: { - type: 'const', - value: '!viewmodel.statemachine["editable"]' - }, - editorOptions: { - types: ['const', 'variable', 'custom'], - enums: [{ key: 'true', value: '是' }, { key: 'false', value: '否' }], - variables: - [{ - // 标记来自表单变量或组件变量 - category: 'local', - path: 'isSystem', - field: '49311371-fd9f-4019-8611-dce4dcae97fe', - fullPath: 'isSystem' - } - ] - } -}; - -/** number类型- 默认显示custom状态 */ -const option5: PropertyEditorOptions = { - controlName: 'UserAddress', - propertyName: 'readonly', - propertyType: 'number', - isNewVariable: false, - propertyValue: { - type: 'custom', - value: '!viewModel.stateMachine["editable"]' - }, - editorOptions: { - types: ['const', 'variable', 'custom'], - enums: [{ key: 'true', value: '是' }, { key: 'false', value: '否' }], - variables: - [{ - category: 'local', - path: 'isSystem', - field: '49311371-fd9f-4019-8611-dce4dcae97fe', - fullPath: 'isSystem' - } - ], - - } -}; - -const archiveOfThisPropertyValue: ArchiveOfPropertyValue = { - /** 常量值 */ - constValue: { - /** 值类型:常量(const), 变量(variable), 状态机(state), 自定义(custom) */ - type: 'const', - /** 属性值 */ - value: 'true', - }, - /** 变量值 */ - variableValue: { - type: 'variable', - value: { - category: 'local', - path: 'isUserNameReadonly', - field: '49311371-fd9f-4019-8611-dce4dcae97fe', - fullPath: 'isUserNameReadonly' - } - }, - /** 状态值 */ - stateValue: null, - /** 自定义属性值 */ - customValue: { - type: 'custom', - value: '!viewModel.stateMachine["editable"]' - }, - /** 表达式属性值 */ - expressionValue: { - type: 'expression', - value: false, - }, - /** 状态机属性值 */ - stateMachineValue: { - type: 'stateMachine', - value: '' - }, - /** 数据状态属性值 */ - dataStatesValue: { - type: 'dataStates', - value: '' - } -}; - -const propertyValueChangedEventArgs1: PropertyEditorValueChanged = { - /** 待编辑的属性名 */ - propertyName: 'readonly', - /** 属性类型:enum, string, number, enum */ - propertyType: 'enum', - isNewVariable: false, - propertyValue: archiveOfThisPropertyValue.constValue -}; - -const propertyValueChangedEventArgs2: PropertyEditorValueChanged = { - /** 待编辑的属性名 */ - propertyName: 'readonly', - /** 属性类型:enum, string, number, enum */ - propertyType: 'enum', - isNewVariable: false, - propertyValue: archiveOfThisPropertyValue.variableValue -}; - -const propertyValueChangedEventArgs3: PropertyEditorValueChanged = { - /** 待编辑的属性名 */ - propertyName: 'readonly', - /** 属性类型:enum, string, number, enum */ - propertyType: 'enum', - isNewVariable: false, - propertyValue: archiveOfThisPropertyValue.customValue -}; +]; diff --git a/packages/ui-vue/components/property-editor/src/composition/type.ts b/packages/ui-vue/components/property-editor/src/composition/type.ts index eee7f4b8a2f..fcaaf87689a 100644 --- a/packages/ui-vue/components/property-editor/src/composition/type.ts +++ b/packages/ui-vue/components/property-editor/src/composition/type.ts @@ -1,110 +1,95 @@ +import { Ref } from "vue"; +import { PropertyType } from "../property-editor.props"; + /** - * 枚举选项 + * 属性类型的枚举选项 */ -export interface EnumItem { - /** 枚举项的值 */ - key: any; - /** 枚举项的显示名称 */ - value: string; +export interface PropertyTypeItem { + /** 属性类型:const、variable、custom、stateMachine、expression */ + id: PropertyType; + /** 属性类型的显示名称 */ + name: string; } /** - * 变量选项 + * 常量值的枚举选项 */ -export interface VariableItem { - /** 变量类型,支持状态变量(variable),实体变量(entity) */ - category: string; +export interface ConstEnumItem { + /** 枚举项的键值 */ + id: any; + /** 枚举项的名称 */ + name: string; +} + +/** + * 变量属性值 + */ +export interface VariableValue { + type: 'variable'; + /** 变量唯一标识 */ + field: string; /** 变量绑定路径 */ path: string; - /** 变量唯一标识 */ + /** 包含层级结构的变量路径 */ + fullPath: string; + /** 是否为新增的变量 */ + isNewVariable?: boolean; + /** 新变量的类型 */ + newVariableType?: 'String' | 'Number' | 'Boolean' | 'Date' | 'DateTime' | 'Text' | 'Object' | 'Array'; +} + +/** + * 变量数据的类型 + */ +export interface VariableItem { + /** 变量内码 */ field: string; + /** 变量绑定路径 */ + path: string; /** 包含层级结构的变量路径 */ fullPath: string; } /** - * 属性编辑器的值。 - * 包括:常量、变量、状态机、自定义等类型 + * 状态机属性值 */ -export interface PropertyEditorValue { - /** 值类型:常量(const), 变量(variable), 状态机(stateMachine), 自定义(custom) */ - type: string; - /** 属性值 */ - value: any; +export interface StateMachineValue { + type: 'stateMachine'; + /** 状态机标识 */ + field: string; + /** 状态机前缀状态 */ + status: boolean; } /** - * 属性编辑器可选值配置 + * 状态机数据的类型 */ -export interface EditorOption { - /** 支持的编辑器类型 */ - types: string[]; - /** 枚举类型常量编辑器的枚举列表 */ - enums?: EnumItem[]; - /** 变量编辑器的变量列表 */ - variables?: VariableItem[]; - /** 新增变量的类型 */ - newVariableType?: string; - /** 新增变量名称的前缀 */ - newVariablePrefix?: string; - /** 获取最新变量列表函数 */ - getVariables?: any; - /** 获取最新状态机列表函数 */ - getStates?: any; - /** 状态机编辑器的状态列表 */ - stateMachine?: any; - /** 数据状态列表 */ - dataStates?: any; - expressionConfig?: any; +export interface StateMachineItem { + /** 状态机内码 */ + id: string; + /** 状态机的显示名称 */ + name: string; } -export interface ArchiveOfPropertyValue { - /** 常量值 */ - constValue: PropertyEditorValue; - /** 变量值 */ - variableValue: PropertyEditorValue; - /** 状态值 */ - stateValue: PropertyEditorValue | null; - /** 自定义属性值 */ - customValue: PropertyEditorValue; - /** 表达式值 */ - expressionValue: PropertyEditorValue; - /** 状态机值 */ - stateMachineValue: PropertyEditorValue; - /** 数据状态值 */ - dataStatesValue: PropertyEditorValue; +export interface UsePropertyValue { + triggerValueChange: (newValue: any) => void; + getPropertyValue: (propertyType: PropertyType) => Ref; + } -export interface PropertyEditorValueChanged { - /** 待编辑的属性名 */ - propertyName: string; - /** 属性类型:boolean, string, number, enum */ - propertyType: string; - /** 检测是否产生新变量 */ - isNewVariable: boolean; - /** 属性编辑器的初始值 */ - propertyValue: PropertyEditorValue; - /** 状态机是否有viewModel.stateMachine前缀 */ - hasPrefix?: boolean; +export interface UsePropertyType { + getAllowedPropertyTypeItems: () => Ref; + getCurrentPropertyType: () => Ref; + } -/** - * 属性编辑器配置 - * 用来初始化属性编辑器 - */ -export interface PropertyEditorOptions { - /** 当前选中的控件对应的英文名称,例userName */ - controlName: string; - /** 待编辑的属性名 */ - propertyName: string; - /** 属性类型:boolean, string, number, enum */ - propertyType: string; - /** 检测是否产生新变量 */ - isNewVariable: boolean; - /** 属性编辑器的初始值 */ - propertyValue: PropertyEditorValue; - /** 属性编辑器可选值配置 */ - editorOptions: EditorOption; - /** 状态机是否有前缀viewModel.stateMachine && */ - hasPrefix?: number; +export interface UseStateMachine { + getStateMachineValue: () => Ref; + +} + +export interface UseVariable { + generateVariable: () => VariableValue; + getVariableByPath: (variablePath: string) => VariableValue; + getVariableValue: () => Ref; } diff --git a/packages/ui-vue/components/property-editor/src/composition/use-initialized-value.ts b/packages/ui-vue/components/property-editor/src/composition/use-initialized-value.ts deleted file mode 100644 index c7cd352e2d8..00000000000 --- a/packages/ui-vue/components/property-editor/src/composition/use-initialized-value.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * 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 { Ref, ref } from 'vue'; -import { cloneDeep } from 'lodash-es'; - -export function useInitializedValue( - importedOriginalData, constEnumValueArray, - currentState, bindStateMachineValue, exists, - searchText, showExpressionComponent -) { - /** 常量-number类型-number-数字输入框 */ - const numberConstValue = ref(0); - /** 数据状态-用户设定绑定值 */ - const dataStatesBindValue = ref(''); - - /** 数据状态-存储所有值的数组 */ - const dataStatesValueArray = ref([]); - - /** 常量-enum类型-用户设定绑定值 */ - const constEnumBindValue = ref(''); - - /** 变量-用户设定的绑定值 */ - const bindVariableValue = ref(''); - - /** - * 常量-枚举:初始设置枚举对应的绑定值和展示数组 - */ - function setEnumConstValue() { - // 存储 常量-enum 的变量值数组 - if (importedOriginalData.value.propertyType === 'enum' && importedOriginalData.value.propertyValue.type === 'const') { - // 当默认显示常量-enum类型时,使用constEnumBindValue来存储comboList中对应的数据,此处value是数组中的key - constEnumBindValue.value = cloneDeep(importedOriginalData.value.propertyValue.value); - constEnumValueArray.value = cloneDeep(importedOriginalData.value.editorOptions.enums); - } - }; - - /** - * 常量-数字 - */ - function setNumberConstValue() { - if (importedOriginalData.value.propertyType === 'number') { - numberConstValue.value = importedOriginalData.value.propertyValue.value; - } - } - - /** 状态机-设置初始绑定值 */ - function setBindStateMachineValue() { - if (currentState.value.id === 'stateMachine') { - bindStateMachineValue = cloneDeep(importedOriginalData.value.propertyValue.value.id); - if (bindStateMachineValue) { - exists.value = cloneDeep(importedOriginalData.value.propertyValue.value.exist); - } else { - exists.value = '否'; - } - } - } - - /** 数据状态-设置初始绑定值 */ - function setBindDataStatesValue() { - if (currentState.value.id === 'dataStates') { - // 数据状态数组 - dataStatesValueArray.value = cloneDeep(importedOriginalData.value.editorOptions.dataStates); - // 数据状态根据propertyValue设置初始值 - if (importedOriginalData.value.propertyValue.value) { - const string = importedOriginalData.value.propertyValue.value; - const result = dataStatesValueArray.value - .filter((element: any) => string.includes(element.value)) - .map((element: any) => element.value) - .join(','); - dataStatesBindValue.value = cloneDeep(result); - } - } - } - /** - * 变量-点击按钮-设置当前绑定的变量值 - */ - function setBindVariableValue() { - if (currentState.value.id === 'variable') { - bindVariableValue.value = importedOriginalData.value.propertyValue.value.path; - } - } - function setBindExpressionValue() { - // 表达式-弹窗组件 - if (currentState.value.id === 'expression') { - showExpressionComponent.value = true; - // 弹窗默认显示值 - const { handleExpressionValue } = importedOriginalData.value.editorOptions.expressionConfig; - if (handleExpressionValue) { - searchText.value = handleExpressionValue().value.value; - } else { - searchText.value = importedOriginalData.value.editorOptions.expressionConfig.expressionValue.value.value; - } - } - } - function setBindCustomValue() { - // 如果为自定义类型,进行subscribe - if (currentState.value.id === 'custom') { - // customValueChange(); - } - } - /** 配置各显示框中的值 */ - function setValue() { - // 常量-enum类型-初始显示值 - setEnumConstValue(); - // 常量-number类型-初始显示值 - setNumberConstValue(); - // 变量-下拉框-初始显示值 - setBindVariableValue(); - // 状态机-下拉框-初始显示值 - setBindStateMachineValue(); - // 数据状态-下拉框-初始显示值 - setBindDataStatesValue(); - // 表达式-帮助-初始显示值 - setBindExpressionValue(); - // 自定义-输入框-初始显示值 - setBindCustomValue(); - } - - return { - numberConstValue, - bindVariableValue, - dataStatesBindValue, - dataStatesValueArray, - constEnumBindValue, - setValue - }; -} diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts new file mode 100644 index 00000000000..b58aae05116 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts @@ -0,0 +1,144 @@ + + +import { Ref, SetupContext, ref } from "vue"; +import { PropertyEditorProps, PropertyType } from "../property-editor.props"; +import { PROPERTY_TYPE_ENUMS } from "./data"; +import { ConstEnumItem, PropertyTypeItem, UsePropertyType } from "./type"; +import { ConstType } from "../components/const/const-property.props"; + +export function usePropertyType( + props: PropertyEditorProps, + context: SetupContext, +): UsePropertyType { + + const constType: Ref = ref(props.constType); + const constEnums: Ref = ref(props.constEnums); + /** 允许选择的属性类型内码 */ + const propertyTypes: Ref = ref(props.propertyTypes); + /** 允许选择的属性类型数据 */ + const allowedPropertyTypeItems: Ref = ref([]); + /** 当前选择的属性类型 */ + const currentPropertyType: Ref = ref(); + + + /** + * 获取允许选择的属性类型数据 + */ + function getAllowedPropertyTypeItems(): Ref { + const allowedPropertyTypeIds = propertyTypes.value; + allowedPropertyTypeItems.value = PROPERTY_TYPE_ENUMS.filter(propertyTypeItem => allowedPropertyTypeIds.includes(propertyTypeItem.id)); + return allowedPropertyTypeItems; + } + + /** + * 判断是否是状态机(旧的状态机格式) + * @param propertyValue + * @returns + */ + function isStateMachine(propertyValue: any): boolean { + if (typeof (propertyValue) !== 'string') { + return false; + } + const stateMachineRegex = /^(?:(!)?)viewModel\.stateMachine\['([^']+)'\]$/; + const isStateMachine = stateMachineRegex.test(propertyValue); + return isStateMachine; + } + + /** + * 判断是否是常量 + * @param propertyValue + * @returns + */ + function isConst(propertyValue: any): boolean { + const allowedPropertyTypes = propertyTypes.value; + + // 1、常量枚举类型 + const isConstEnum = allowedPropertyTypes.includes('const') && constType.value === 'enum' + && constEnums.value.findIndex(constEnum => constEnum.id === propertyValue) > -1; + + // 2、常量数值类型 + const isConstNumber = allowedPropertyTypes.includes('const') && constType.value === 'number' + && typeof propertyValue === "number"; + + return isConstEnum || isConstNumber; + } + + + /** + * 判断是否是自定义类型 + * @param propertyValue + * @returns + */ + function isCustom(propertyValue: any): boolean { + const allowedPropertyTypes = propertyTypes.value; + + const isCustom = allowedPropertyTypes.includes("custom") && typeof (propertyValue) === 'string'; + return isCustom; + } + + /** + * 从对象结构中提取属性类型 + * @param propertyValue + * @returns + */ + function extractFromObjectType(propertyValue: any): PropertyType | undefined { + const isObject = propertyValue && typeof (propertyValue) === 'object'; + if (!isObject) { + return; + } + return propertyValue.type; + } + + /** + * 从非对象结构中提取属性类型 + * @param propertyValue + * @returns + */ + function extractFromNonObjectType(propertyValue: any): PropertyType | undefined { + // 1、定义属性类型检查器 + const typeCheckers = new Map boolean>([ + ['const', isConst], + ['stateMachine', isStateMachine], + ['custom', isCustom], + ]); + + // 2、遍历检查器,找到匹配的类型 + for (const [propertyType, checker] of typeCheckers.entries()) { + if (checker(propertyValue)) { + return propertyType; + } + } + } + + /** + * 提取属性类型 + * @returns + */ + function extractPropertyType(): PropertyType { + const propertyValue: any = props.modelValue; + // 1、默认为第一个可选的属性类型 + const dfaultPropertyType: PropertyType = propertyTypes.value[0]; + + // 2、属性值为对象结构,属性值的type为属性类型 + const propertyTypefromObject = extractFromObjectType(propertyValue); + + // 2、属性值为非对象结构,属性值的type为属性类型 + const propertyTypefromNonObject = extractFromNonObjectType(propertyValue); + + return propertyTypefromObject || propertyTypefromNonObject || dfaultPropertyType; + } + + /** + * 获取当前选择的属性类型 + * @returns + */ + function getCurrentPropertyType(): Ref { + if (!currentPropertyType.value) { + // 从属性值中提取属性类型 + currentPropertyType.value = extractPropertyType(); + } + return currentPropertyType; + } + + return { getAllowedPropertyTypeItems, getCurrentPropertyType }; +} diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts new file mode 100644 index 00000000000..e52530c6160 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts @@ -0,0 +1,44 @@ +import { Ref, SetupContext, ref } from "vue"; +import { PropertyEditorProps, PropertyType } from "../property-editor.props"; +import { UsePropertyValue } from "./type"; +import { cloneDeep } from "lodash"; + +export function usePropertyValue( + props: PropertyEditorProps, + context: SetupContext, + currentPropertyType: PropertyType +): UsePropertyValue { + const modelValue = ref(props.modelValue); + + /** 存储所有类型的属性值 */ + const propertyValueMap = new Map>(); + propertyValueMap.set(currentPropertyType, ref(cloneDeep(modelValue.value))); + + /** + * 触发属性值改变 + * @param newValue + */ + function triggerValueChange(newValue: any) { + context.emit('valueChange', cloneDeep(newValue)); + } + + /** + * 获取属性值 + * @param propertyType + * @returns + */ + function getPropertyValue(propertyType: PropertyType): Ref { + // 1、从propertyValueMap中获取属性值 + const propertyValue = propertyValueMap.get(propertyType); + if (propertyValue) { + return propertyValue; + } + // 2、propertyValueMap中不存在属性值,则新建 + const newPropertyValue = ref(); + propertyValueMap.set(propertyType, newPropertyValue); + return newPropertyValue; + + } + + return { triggerValueChange, getPropertyValue }; +} diff --git a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts new file mode 100644 index 00000000000..8dc2fe63822 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts @@ -0,0 +1,65 @@ +import { Ref, SetupContext, ref } from "vue"; +import { PropertyEditorProps } from "../property-editor.props"; +import { StateMachineValue, UsePropertyValue, UseStateMachine } from "./type"; + +export function useStateMachine( + props: PropertyEditorProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +): UseStateMachine { + + const stateMachineRegex = /^(?:(!)?)viewModel\.stateMachine\['([^']+)'\]$/; + const { getPropertyValue } = usePropertyValueComposition; + + /** + * 把状态机转为新的格式 + * viewModel.stateMachine['xxx'] -> {type: 'stateMachine',status: false,field: 'xxx'} + */ + function convertStateMachineFormat(oldStateMachineFormat: Ref) { + // 1、字符串类型为旧结构 + const isOldStructure = typeof oldStateMachineFormat.value === 'string'; + if (!isOldStructure) { + return; + } + + // 2、判断是否为状态机 + const matchResult = oldStateMachineFormat.value.match(stateMachineRegex); + if (!matchResult || matchResult.length < 3) { + return; + } + + // 3、转化为新的格式 + const newStateMachineFormat: StateMachineValue = { + type: 'stateMachine', + status: matchResult[1], + field: matchResult[2] + } + + oldStateMachineFormat.value = newStateMachineFormat; + usePropertyValueComposition.triggerValueChange(newStateMachineFormat); + } + + /** + * 获取状态机属性值 + * @returns + */ + function getStateMachineValue() { + // 1、如果存在属性值,则直接返回 + const propertyValue: Ref = getPropertyValue('stateMachine'); + if (propertyValue.value) { + convertStateMachineFormat(propertyValue); + return propertyValue; + } + // 2、如果属性值为空,则新建一个 + propertyValue.value = { + type: 'stateMachine', + field: '', + status: false + } + return propertyValue; + + } + + + return { getStateMachineValue }; +} diff --git a/packages/ui-vue/components/property-editor/src/composition/use-update-data.ts b/packages/ui-vue/components/property-editor/src/composition/use-update-data.ts deleted file mode 100644 index 15ec7d9bc95..00000000000 --- a/packages/ui-vue/components/property-editor/src/composition/use-update-data.ts +++ /dev/null @@ -1,186 +0,0 @@ - -/* eslint-disable no-use-before-define */ -/** - * 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 { PropertyEditorProps, propertyEditorProps } from '../property-editor.props'; -import { SetupContext, ref, Ref } from 'vue'; -import { cloneDeep } from 'lodash-es'; - -export function useUpdate(context: SetupContext, importedOriginalData, constEnumBindValue, constEnumValueArray, - archiveOfPropertyValue, displayArrayState, bindStateMachineValue, exists, dataStatesValueArray, - searchText, readOnly, currentState) { - /** 状态机是否有前缀viewModel.stateMachine && */ - const prefix: Ref = ref(false); - - /** 出参属性PropertyEditorValueChanged */ - const propertyEditorValueChange: any = ref({ - propertyName: '', - /** 属性类型:boolean, string, number, enum */ - propertyType: '', - /** 是否生成新变量*/ - isNewVariable: false, - /** 属性编辑器的初始值 */ - propertyValue: null, - /** 状态机是否有前缀viewModel.stateMachine && */ - hasPrefix: false, - }); - - /** - * 常量-枚举:设置枚举对应的绑定值和展示数组 - */ - function setStateOfEnum() { - if (importedOriginalData.value.propertyValue.type === 'const') { - importedOriginalData.value.propertyValue.value = cloneDeep(archiveOfPropertyValue.value.constValue.value); - constEnumBindValue.value = cloneDeep(archiveOfPropertyValue.value.constValue.value); - constEnumValueArray.value = cloneDeep(importedOriginalData.value.editorOptions.enums); - } - } - - /** 状态机-设置对应的绑定值和生成数组 */ - function setStateOfStateMachine() { - if (importedOriginalData.value.propertyValue.type === 'stateMachine') { - importedOriginalData.value.propertyValue.value = cloneDeep(archiveOfPropertyValue.value.stateMachineValue.value); - displayArrayState.value = cloneDeep(importedOriginalData.value.editorOptions.stateMachine); - if (importedOriginalData.value.propertyValue.value.name) { - bindStateMachineValue = cloneDeep(importedOriginalData.value.propertyValue.value.id); - } - else { - importedOriginalData.value.propertyValue.value = { - id: '', - name: '', - exist: '' - }; - bindStateMachineValue = ''; - exists.value = '否'; - } - } - }; - /** 数据状态-设置对应的绑定值和生成数组 */ - function setValueOfDataStates() { - if (importedOriginalData.value.propertyValue.type === 'dataStates') { - importedOriginalData.value.propertyValue.value = cloneDeep(archiveOfPropertyValue.value.dataStatesValue.value); - dataStatesValueArray.value = cloneDeep(importedOriginalData.value.editorOptions.dataStates); - } - }; - /** 表达式-将表达式绑定值置为空 */ - function setExpressionBindValue() { - searchText.value = ''; - if (archiveOfPropertyValue.value.expressionValue) { - archiveOfPropertyValue.value.expressionValue.value = ''; - } - } - /** 状态机-切换状态-是/否 */ - function changeState() { - if (!readOnly.value) { - exists.value = exists.value === '否' ? '是' : '否'; - importedOriginalData.value.propertyValue.value.exist = exists; - archiveOfPropertyValue.value.stateMachineValue.value.exist = exists; - emitOutPutInterfaceData(); - } - } - - /** 自定义-清空符合状态机的值 */ - function clearCustomBindValue() { - if (propertyEditorValueChange.value.propertyValue.value) { - if (propertyEditorValueChange.value.propertyValue.value.includes('viewModel.stateMachine')) { - archiveOfPropertyValue.value.customValue.value = ''; - } - } - } - - /** 将最终状态和值,赋给propertyEditorValueChange */ - function setOutputData() { - propertyEditorValueChange.value.propertyName = cloneDeep(importedOriginalData.value.propertyName); - propertyEditorValueChange.value.propertyType = cloneDeep(importedOriginalData.value.propertyType); - propertyEditorValueChange.value.propertyValue = cloneDeep(importedOriginalData.value.propertyValue); - propertyEditorValueChange.value.hasPrefix = cloneDeep(prefix); - } - /** - * 出参-传出接口 - */ - function emitOutPutInterfaceData() { - if (!readOnly.value) { - setOutputData(); - // 判定需要出参的情况 - switch (propertyEditorValueChange.value.propertyValue.type) { - case 'const': - // const时的出参判断条件 - if ((propertyEditorValueChange.value.propertyType === 'enum' && propertyEditorValueChange.value.propertyValue.value !== '') - || (propertyEditorValueChange.value.propertyType === 'number' && propertyEditorValueChange.value.propertyValue.value != null) - || (propertyEditorValueChange.value.propertyType === 'string')) { - // 将表达式绑定值置为空 - setExpressionBindValue(); - context.emit('propertyEditorValueChanged', propertyEditorValueChange); - } - break; - case 'variable': - // variable时的出参判断条件 - if (propertyEditorValueChange.value.propertyValue.value.path !== '') { - // 将表达式绑定值置为空 - setExpressionBindValue(); - context.emit('propertyEditorValueChanged', propertyEditorValueChange); - } - break; - case 'custom': - // 将表达式绑定值置为空 - setExpressionBindValue(); - clearCustomBindValue(); - context.emit('propertyEditorValueChanged', propertyEditorValueChange); - break; - case 'expression': - if (searchText.value) { - context.emit('propertyEditorValueChanged', propertyEditorValueChange); - } - break; - case 'stateMachine': - // variable时的出参判断条件 - if (propertyEditorValueChange.value.propertyValue.value.id) { - setExpressionBindValue(); - context.emit('propertyEditorValueChanged', propertyEditorValueChange); - } - break; - case 'dataStates': - // 将表达式绑定值置为空 - if (propertyEditorValueChange.value.propertyValue.value !== '') { - setExpressionBindValue(); - context.emit('propertyEditorValueChanged', propertyEditorValueChange); - break; - } - } - } - } - /** - * 更新数据-左侧区域切换不同模式or各区域值变更后,更新当前数据 - */ - function updateData() { - // 将archiveOfPropertyValue中对应constValue/variableValue/customValue存储的值放入当前值 - importedOriginalData.value.propertyValue = archiveOfPropertyValue.value[`${currentState.value.id}Value`]; - // 出现枚举时,需要绑定 - setStateOfEnum(); - setStateOfStateMachine(); - setValueOfDataStates(); - emitOutPutInterfaceData(); - // 检测当前是否生成了新的变量 - propertyEditorValueChange.value.isNewVariable = false; - } - - return { - updateData, - changeState, - prefix, - propertyEditorValueChange - }; -} diff --git a/packages/ui-vue/components/property-editor/src/composition/use-variable.ts b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts new file mode 100644 index 00000000000..6903c7d8753 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts @@ -0,0 +1,105 @@ + + +import { Ref, SetupContext, ref } from "vue"; +import { PropertyEditorProps } from "../property-editor.props"; +import { useGuid } from '@farris/ui-vue/components/common'; +import { UsePropertyValue, UseVariable, VariableValue } from "./type"; + +export function useVariable( + props: PropertyEditorProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +): UseVariable { + + const newVariablePrefix = ref(props.newVariablePrefix); + const newVariableType = ref(props.newVariableType); + + const propertyName = ref(props.id); + const controlName = ref(props.controlName); + const variables = ref(props.variables); + const { getPropertyValue } = usePropertyValueComposition; + + /** + * 把字符串的首字母大写 + * @param originalString + * @returns + */ + function setFirstLetterUpperCase(originalString: string) { + return originalString[0].toUpperCase() + originalString.slice(1); + } + + /** + * 把字符串的首字母小写 + * @param originalString + * @returns + */ + function setFirstLetterLowerCase(originalString: string) { + return originalString[0].toLowerCase() + originalString.slice(1); + } + + /** + * 生成新的变量 + * @returns + */ + function generateVariable(): VariableValue { + // 1、变量名的中间部分 + const splicingNameMiddle = newVariablePrefix.value ? setFirstLetterUpperCase(controlName.value) : + setFirstLetterLowerCase(controlName.value); + + // 2、变量名的右侧内容 + const splicingNameRight = setFirstLetterUpperCase(propertyName.value); + + // 3、拼接成新的变量名 + const newVariablePath = `${newVariablePrefix.value}${splicingNameMiddle}${splicingNameRight}`; + + const { guid } = useGuid(); + const newVariable: VariableValue = { + type: 'variable', + path: newVariablePath, + field: guid(), + fullPath: newVariablePath, + isNewVariable: true, + newVariableType: newVariableType.value + } + return newVariable; + } + + /** + * 根据变量路径获取变量 + * @param variablePath + * @returns + */ + function getVariableByPath(variablePath: string): VariableValue { + const existedVariable = variables.value.find(variable => variable.path === variablePath); + return existedVariable; + } + + /** 判断当前显示的变量是否已被删除,若被删除,则标红处理 */ + function ifHighlightBorder() { + } + + /** + * 获取状态机属性值 + * @returns + */ + function getVariableValue(): Ref { + // 1、如果存在属性值,则直接返回 + const propertyValue: Ref = getPropertyValue('variable'); + if (propertyValue.value) { + return propertyValue; + } + + // 2、如果属性值为空,则新建一个 + propertyValue.value = { + type: 'variable', + field: '', + path: '', + fullPath: '' + } + return propertyValue; + + } + + + return { generateVariable, getVariableByPath, getVariableValue }; +} diff --git a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx index 1c974dd0159..efc8c7fe5b0 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx +++ b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx @@ -1,4 +1,3 @@ - /* eslint-disable no-use-before-define */ /** * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. @@ -15,628 +14,104 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { defineComponent, SetupContext, Ref, ref, onMounted, watch } from 'vue'; -import { PropertyEditorProps, propertyEditorProps } from './property-editor.props'; -import { cloneDeep } from 'lodash-es'; -import { option1, archiveOfPropertyValue, dropdownStatesInTotal } from './composition/data'; -import { FComboList } from '../../../components/combo-list'; -import { FInputGroup } from '../../../components/input-group'; -import { FNumberSpinner } from '../../../components/number-spinner'; -import { useInitializedValue } from './composition/use-initialized-value'; -import { useUpdate } from './composition/use-update-data'; +import { defineComponent, SetupContext, ref, computed } from 'vue'; +import { PropertyEditorProps, propertyEditorProps, PropertyType } from './property-editor.props'; +import { FComboList } from '@farris/ui-vue/components/combo-list'; +import getConstRender from './components/const/const-property.component'; +import getVariableRender from './components/variable/variable-property.component'; +import getStateMachineRender from './components/state-machine/state-machine-property.component'; +import getCustomRender from './components/custom/custom-property.component'; +import { usePropertyValue } from './composition/use-property-value'; +import { usePropertyType } from './composition/use-property-type'; import './property-editor.css'; export default defineComponent({ name: 'FPropertyEditor', props: propertyEditorProps, - emits: ['propertyEditorValueChanged'] as (string[] & ThisType) | undefined, + emits: ['valueChange'] as (string[] & ThisType) | undefined, setup(props: PropertyEditorProps, context: SetupContext) { - /** 初始传入值PropertyEditorOptions*/ - // props.importedOriginalData - const importedOriginalData: any = ref(option1); - - /** 表达式绑定值 */ - const searchText = ref(''); - - /** 左侧状态切换-当前状态 (const-常量;variable-变量;custom-自定义) */ - const currentState: any = ref('const'); - - /** 常量-enum类型-存储所有枚举值的数组 */ - const constEnumValueArray: any = ref([]); - - /** 变量-根据是否显示control名称,确认是否显示button */ - const showAddButton: Ref = ref(false); - - /** 变量-点击button-存储根据命名规则生成的变量名*/ - let newVariable: any; - - /** 变量-点击button-生成代码编辑器中的field部分 */ - const fieldContent: Ref = ref(''); - - /** 变量-点击button-记录上一次点击值 */ - const frontValue: Ref = ref(''); - - /** 变量-下拉框-用户点击增加按钮后的变量数组 */ - const displayArray: any = ref([]); - - // /** 变量-下拉框-绑定值 */ - // let bindVariableValue: any; - - /** 状态机-下拉框 */ - let bindStateMachineValue: any; - - /** 状态机-用户点击下拉框后的变量数组 */ - const displayArrayState = ref([]); - - /** 状态机-文字-是/否 */ - const exists: Ref = ref('是'); - - /** 自定义-string类型-input-用户输入内容绑定 */ - const currentValue: any = ref(''); - - /** 表达式-弹窗 */ - const showExpressionComponent: Ref = ref(false); - - /** 表达式-group */ - const groupIcon = ref(""); - - /** 只读属性 */ - const readOnly: Ref = ref(false); - - const dropdownStates: any = ref([]); - /** 初始化数据 */ - const { numberConstValue, bindVariableValue, dataStatesBindValue, dataStatesValueArray, constEnumBindValue, setValue } = useInitializedValue( - importedOriginalData, constEnumValueArray, - currentState, bindStateMachineValue, exists, - searchText, showExpressionComponent); - /** 更新数据 */ - const { updateData, changeState, prefix, propertyEditorValueChange } = useUpdate( - context, importedOriginalData, constEnumBindValue, constEnumValueArray, - archiveOfPropertyValue, displayArrayState, bindStateMachineValue, exists, - dataStatesValueArray, searchText, readOnly, currentState); - - /** 判断当前显示的变量是否已被删除,若被删除,则标红处理 */ - function ifHighlightBorder() { - // if (currentState.value.id === 'variable' && importedOriginalData.value.propertyValue.type === 'variable') { - // // 更新变量下拉列表 - // const getVariablesFunction = importedOriginalData.value.editorOptions.getVariables; - // if (getVariablesFunction) { - // displayArray.value = getVariablesFunction(); - // } - // if (document.getElementsByClassName('f-page-single-property-editor-component-right-variable')) { - // if (document.getElementsByClassName('f-page-single-property-editor-component-right-variable')[0]) { - // const html = document.getElementsByClassName('f-page-single-property-editor-component-right-variable')[0]; - // if (html.getElementsByClassName('input-group')) { - // if (html.getElementsByClassName('input-group')[0]) { - // const element = html.getElementsByClassName('input-group')[0]; - // // 查看是否该变量已被删除 - // const variableExist = displayArray.value.find(item => item.path === bindVariableValue); - // // if (!variableExist && (bindVariableValue !== '' && bindVariableValue !== undefined)) { - // // element.style?.setProperty('borderColor', 'red'); - // // } - // // else { - // // element.style?.setProperty('borderColor', '#D8DCE6'); - // // } - // } - // } - // } - // } - // } - } - - /** 判断初始支持的状态 */ - function generateDefaultState() { - dropdownStates.value = dropdownStatesInTotal.value.filter(item => - importedOriginalData.value.editorOptions.types.includes(item.id) - ); - } - - /** 属性编辑器左侧初始状态 */ - function setCurrentState() { - // 初始状态: find查询入参中存储的默认状态,与当前存储的3种状态:常量、变量、自定义进行比对; - currentState.value = cloneDeep(dropdownStates.value.find( - item => (item.id === importedOriginalData.value.propertyValue.type))); - } - /** - * 根据入参,判断属性编辑器初始状态,并存储入参到archiveOfPropertyValue的对应状态中 - */ - function defaultStateValue() { - setCurrentState(); - // 判断特例:variable传值为undefined,需设定好path等相关参数 - if (currentState.value.id === 'variable' && importedOriginalData.value.propertyValue.value === undefined) { - importedOriginalData.value.propertyValue = cloneDeep(archiveOfPropertyValue.value.variableValue); - } - // 存储初始值:将默认值存储到archive对应的constValue、variableValue、customValue - archiveOfPropertyValue.value[`${currentState.value.id}Value`] = cloneDeep(importedOriginalData.value.propertyValue); - // 配置各显示框中的值 - setValue(); - } - - /** - * 左侧区域类型转换后,同时切换右侧区域 - */ - function getSelectedState(selectedValue) { - // 确认左侧类型 - currentState.value = cloneDeep(dropdownStates.value.find((item: any) => item.label === selectedValue[0].label)); - // 切换为表达式状态后,显示对应的弹窗组件 - if (currentState.value.id === 'expression') { - if (archiveOfPropertyValue.value.expressionValue.value) { - searchText.value = archiveOfPropertyValue.value.expressionValue.value.value; - } - showExpressionComponent.value = true; - } - // 如果为自定义类型,进行subscribe - if (currentState.value.id === 'custom') { - // TODO 此处的频繁watch是有问题的 - customValueChange(); - } - updateData(); - ifHighlightBorder(); - } - - /** - * 常量-枚举-下拉框:用户切换绑定变量 - */ - function getSelectedFormState(value) { - // 此处value是数组中的key - constEnumBindValue.value = cloneDeep(value.value); - importedOriginalData.value.propertyValue.value = cloneDeep(value.value); - archiveOfPropertyValue.value.constValue.value = cloneDeep(value.value); - updateData(); - } - - /** - * 常量-数字变化 - */ - function numberConstValueChanged($event) { - archiveOfPropertyValue.value.constValue.value = $event; - updateData(); - } - - /** - * 常量-字符串-记录input值 - */ - function getConstInputValue(currentValue) { - archiveOfPropertyValue.value.constValue.value = currentValue; - updateData(); - } - - /** - * 变量-点击button-点击产生新的变量值; - */ - function generateVariables() { - // 根据新变量的命名规则,进行字符串拼接 - const setUpperCaseNameRight = importedOriginalData.value.propertyName; - // 首字母大写 - const splicingNameRight = setUpperCaseNameRight[0].toUpperCase() + setUpperCaseNameRight.substr(1); - const setUpperCaseNameMiddle = importedOriginalData.value.controlName; - // 根据前缀是否存在决定首字母是否小写 - const newVariablePrefix = importedOriginalData.value.editorOptions.newVariablePrefix || ''; - const splicingNameMiddle = newVariablePrefix ? setUpperCaseNameMiddle[0].toUpperCase() + setUpperCaseNameMiddle.substr(1) : - setUpperCaseNameMiddle[0].toLowerCase() + setUpperCaseNameMiddle.substr(1); - newVariable = `${newVariablePrefix}${splicingNameMiddle}${splicingNameRight}`; - saveVariablesChanges(); - ifHighlightBorder(); - } - - /** - * 变量-点击button-是否生成变量、绑定、生成展示数组、更新数据 - */ - function saveVariablesChanges() { - iterateVariableArray(); - if (currentState.value.id === 'variable') { - bindVariableValue.value = importedOriginalData.value.propertyValue.value.path; - } - generateCurrentVariableArray(); - // 当重复前一个绑定值时,不需要更新数据 - if (frontValue.value !== importedOriginalData.value.propertyValue.value.path) { - updateData(); - } - } - - /** - * 变量-点击按钮-遍历数组,确定是否生成新的变量 - */ - function iterateVariableArray() { - let count = 0; - importedOriginalData.value.editorOptions.variables?.forEach(item => { - // 如果遍历一遍后,没有与newVariable相同的值,则表明可以生成新的值; - if (item.path !== newVariable) { - count += 1; - } - else { - // 若遍历到相同的值,则记录这个值,并将这个值设定为当前绑定值 - frontValue.value = importedOriginalData.value.propertyValue.value.path; - importedOriginalData.value.propertyValue.value = cloneDeep(item); - archiveOfPropertyValue.value.variableValue.value = cloneDeep(item); - } - }); - // 如果编辑后所有的path都不与newVariable重复,则生成新变量; - generateNewVariable(count); - } - - /** - * 变量-点击按钮-遍历数组-生成新变量 - */ - function generateNewVariable(count: number) { - // 通过count与原值length的对比,判断是否编辑后所有的path都不与newVariable重复 - if (count === importedOriginalData.value.editorOptions.variables?.length) { - // 生成新变量值 - importedOriginalData.value.propertyValue.value.category = 'local'; - importedOriginalData.value.propertyValue.value.path = newVariable; - importedOriginalData.value.propertyValue.value.field = fieldContent; - importedOriginalData.value.propertyValue.value.fullPath = newVariable; - importedOriginalData.value.propertyValue.value.newVariableType = importedOriginalData.value.editorOptions.newVariableType; - propertyEditorValueChange.value.isNewVariable = true; - // 将新的变量放入变量数组 - importedOriginalData.value.editorOptions.variables.push(cloneDeep(importedOriginalData.value.propertyValue.value)); - archiveOfPropertyValue.value.variableValue.value = cloneDeep(importedOriginalData.value.propertyValue.value); - } - } + const readOnly = ref(false); + + /** 左侧-属性类型相关方法 */ + const { getAllowedPropertyTypeItems, getCurrentPropertyType } = usePropertyType(props, context); + /** 允许选择的属性类型 */ + const allowedPropertyTypeItems = getAllowedPropertyTypeItems(); + /** 当前选择的属性类型 */ + const currentPropertyType = getCurrentPropertyType(); + + /** 右侧-属性值相关方法 */ + const usePropertyValueComposition = usePropertyValue(props, context, currentPropertyType.value); + const { getPropertyValue, triggerValueChange } = usePropertyValueComposition; + /** 渲染右侧内容 */ + const renderConst = getConstRender(props, context, usePropertyValueComposition); + const renderVariable = getVariableRender(props, context, usePropertyValueComposition); + const renderCustom = getCustomRender(props, context, usePropertyValueComposition); + const renderStateMachine = getStateMachineRender(props, context, usePropertyValueComposition); + /** 控制右侧区域显示 */ + const shouldShowRight = computed(() => (selectedPropertyType: PropertyType) => { + return selectedPropertyType === currentPropertyType.value; + }); /** - * 变量-下拉框-点击下拉框中的值-改变当前绑定的变量值 + * 左侧属性类型变化 */ - function changeSelectVariable(value) { - if (!value || !value.selections || value.selections.length < 1) { - return; - } - archiveOfPropertyValue.value.variableValue.value.category = cloneDeep(value.selections[0].category); - archiveOfPropertyValue.value.variableValue.value.path = cloneDeep(value.selections[0].path); - archiveOfPropertyValue.value.variableValue.value.fullPath = cloneDeep(value.selections[0].fullPath); - archiveOfPropertyValue.value.variableValue.value.field = cloneDeep(value.selections[0].field); - bindVariableValue.value = cloneDeep(value.value); - updateData(); - ifHighlightBorder(); - } + function onPropertyTypeChange() { + // 1、获取当前属性值 + const propertyValue = getPropertyValue(currentPropertyType.value); - /** 变量-清空当前值 */ - function clearVariable() { - importedOriginalData.value.propertyValue.value.category = ''; - importedOriginalData.value.propertyValue.value.path = ''; - importedOriginalData.value.propertyValue.value.field = ''; - importedOriginalData.value.propertyValue.value.fullPath = ''; - if (currentState.value.id === 'variable') { - bindVariableValue.value = importedOriginalData.value.propertyValue.value.path; + // 2、如果属性值不为空,触发属性值变更 + if (propertyValue.value) { + triggerValueChange(propertyValue.value); } - updateData(); - ifHighlightBorder(); - } - - /** - * 变量-生成当前的变量数组 - */ - function generateCurrentVariableArray() { - displayArray.value = cloneDeep(importedOriginalData.value.editorOptions.variables); } /** - * 变量-显示变量下拉框前回调 + * 渲染左侧属性类型下拉列表 */ - const beforeShowVariable = (instance: any) => { - const getVariablesFunction = importedOriginalData.value.editorOptions.getVariables; - const result: any = { - showDialog: true - }; - if (getVariablesFunction) { - displayArray.value = getVariablesFunction(); - if (instance) { - instance.data = displayArray; - } - ifHighlightBorder(); - } - return Promise.resolve(true); - }; - - /** 状态机-点击下拉框中的值-改变当前绑定的状态机的值 */ - function changeSelectStateMachine(value) { - const middleArray = { - id: value[0].id, - name: value[0].exist, - exist: value[0].name - }; - archiveOfPropertyValue.value.stateMachineValue.value = cloneDeep(middleArray); - exists.value = importedOriginalData.value.propertyValue.value.exist === '是' ? '是' : '否'; - bindStateMachineValue = cloneDeep(middleArray.id); - updateData(); - } - - /** 状态机-生成当前的状态机数组 */ - function generateCurrentStatesArray() { - displayArrayState.value = cloneDeep(importedOriginalData.value.editorOptions.stateMachine); - exists.value = archiveOfPropertyValue.value.stateMachineValue.value.exist === '是' ? '是' : '否'; - } - - /** - * 自定义-检测自定义值变换并将结果传出 - */ - const textChangeSubject = ref(); - function customValueChange() { - watch(textChangeSubject, (newValue) => { - archiveOfPropertyValue.value.customValue.value = newValue; - updateData(); - }); - } - function getCustomizeValue(changeValue) { - textChangeSubject.value = changeValue; - } - - /** 表达式-弹窗 */ - function showExpression() { - // 修改中 - } - - /** 数据状态-用户切换绑定变量 */ - function getSelectedDataStates(value) { - importedOriginalData.value.propertyValue.value = cloneDeep(value); - archiveOfPropertyValue.value.dataStatesValue.value = cloneDeep(value); - const result = value.map(element => element.valueField).join(','); - dataStatesBindValue.value = cloneDeep(result); - updateData(); - } - - /** 变量 */ - function returnVariableStructure() { + function renderLeftContent() { return ( -
- {/* 如果此组件没有对应的变量名,则展示按钮,双击可添加新变量 */} +
changeSelectVariable(e)} - onClear={clearVariable} - > - - {/* comboList新增模板 */} - {/* < itemTemp let-item let-idx='index'> - - {displayArray.value[idx].fullPath} - */} - {/* 如果此组件有对应的变量名,则展示dropdown组件,可以绑定全局变量及本模块对应变量 */} - {showAddButton.value ? (
- -
) : ''} -
- ); - } - /** 自定义 */ - function returnCustomStructure() { - return ( -
- getCustomizeValue((e.target as HTMLInputElement).value)} - disabled={readOnly.value} > -
- ); - } - /** 表达式 */ - function returnExpressionStructure() { - return ( -
- -
- ); - } - /** 状态机 */ - function returnStateMachineStructure() { - return ( -
- {/* 显示文字 */} -
- {exists.value} -
-
- { changeSelectStateMachine(e); }} - > - - {/* - {{ displayArrayState[idx].name }} - */} -
-
- ); - } - /** 数据状态 */ - function returnDataStatesStructure() { - return ( -
- getSelectedDataStates(e)} - > - -
- ); - } - /** 常量-自定义类型 */ - function returnStringConstStructure() { - return ( - { getConstInputValue(e); }} - disabled={readOnly.value} - placeholder={'输入自定义内容'} - > - ); - } - /** 常量-枚举类型 */ - function returnEnumConstStructure() { - return ( - getSelectedFormState(e)} - > - - ); - } - /** 常量-数字类型 */ - function returnNumberConstStructure() { - return ( - { numberConstValueChanged(value); }} - class='f-page-single-property-editor-component-const-number' > - - ); - } - /** 左侧选择区域:常量、变量、自定义、表达式 */ - function returnLeftController() { - return ( -
- getSelectedState(e)} + onChange={onPropertyTypeChange} >
); } - /** 右侧区域组件 */ - function returnRightController() { + + + /** + * 渲染右侧属性值区域 + */ + function renderRightContent() { + /** 右侧区域渲染方法 */ return ( -
- {/* 对应常量部分 */} - {currentState.value.id === 'const' ? ( -
- {/* 常量-string类型 */} - {importedOriginalData.value.propertyType === 'string' ? returnStringConstStructure() : ''} - {/* 常量-枚举类型 */} - {importedOriginalData.value.propertyType === 'enum' ? returnEnumConstStructure() : ''} - {/* 常量-number类型 */} - {importedOriginalData.value.propertyType === 'number' ? returnNumberConstStructure() : ''} -
- ) : ''} - {/* 对应变量部分 */} - {currentState.value.id === 'variable' ? returnVariableStructure() : ''} - {/* 对应自定义部分 */} - {currentState.value.id === 'custom' ? returnCustomStructure() : ''} - {/* 对应表达式部分 */} - {(currentState.value.id === 'expression' && showExpressionComponent.value) ? returnExpressionStructure() : ''} - {/* 对应状态机部分 */} - {currentState.value.id === 'stateMachine' ? returnStateMachineStructure() : ''} - {/* 对应数据状态部分 */} - {currentState.value.id === 'dataStates' ? returnDataStatesStructure() : ''} +
+ {shouldShowRight.value('const') && renderConst()} + {shouldShowRight.value('variable') && renderVariable()} + {shouldShowRight.value('custom') && renderCustom()} + {shouldShowRight.value('stateMachine') && renderStateMachine()} +
); } - onMounted(() => { - // 如果为只读属性 - // if (isReadonly.value[0] === true) { - // readOnly.value = true; - // showAddButton.value = false; - // } else { - // readOnly.value = false; - // showAddButton.value = true; - // } - // 判断初始支持的状态 - generateDefaultState(); - defaultStateValue(); - generateCurrentVariableArray(); - generateCurrentStatesArray(); - - if (importedOriginalData.value.hasPrefix && importedOriginalData.value.hasPrefix === 2) { - prefix.value = true; - } - if (importedOriginalData.value.controlName !== undefined) { - showAddButton.value = true; - } - }); - - // watch(currentState.value, () => { - // 如果为只读属性 - // if (changes['isReadonly']) { - // if (changes['isReadonly']['currentValue'][0] === true) { - // readOnly = true; - // showAddButton = false; - // } - // else { - // readOnly = false; - // showAddButton = true; - // } - // } - // if (importedOriginalData.value.currentValue.propertyValue && (searchText.value === null || searchText.value.length === 0)) { - // generateDefaultState(); - // defaultStateValue(); - // } - // }); - return () => { return ( - <> -
- {returnLeftController()} - {returnRightController()} -
- +
+ {renderLeftContent()} + {/* 确认好的属性类型后,再显示右侧属性值区域 */} + {renderRightContent()} +
); }; } diff --git a/packages/ui-vue/components/property-editor/src/property-editor.css b/packages/ui-vue/components/property-editor/src/property-editor.css index 4ad46fa988c..cd5079843e5 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.css +++ b/packages/ui-vue/components/property-editor/src/property-editor.css @@ -1,181 +1,13 @@ -.f-page-single-property-editor-component { +.f-property-editor-container { min-width: 230px; } -.f-page-single-property-editor-component-tag { - display: 1; - font-family: PingFangSC-Regular; - font-size: 13px; - color: rgba(0, 0, 0, 0.50); - letter-spacing: 0; - line-height: 16px; - margin-left: 5%; - margin-top: 2.5%; - margin-bottom: 2.5%; -} - -.f-page-single-property-editor-component-left-controller { - float: left; - /* background: #FFFFFF; */ - height: 28px; - width: 32%; -} - -.f-page-single-property-editor-component-right-const { - float: left; - width: 65%; - margin-left: 3%; - background: #FFFFFF; -} - -.f-page-single-property-editor-component-right-variable { - float: left; - width: 65%; - margin-left: 3%; - /* background: #FFFFFF; */ -} - -.f-page-single-property-editor-template { - width: 100%; - height: 25px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - line-height: 25px; -} - -.form-control-select-1 { - height: 26px; - margin: 0px !important; - width: 100%; - border: 1px solid #D8DCE6; - border-radius: 3px; - border-color: #D8DCE6; -} - -.form-control-select-show { - height: 28px; - margin: 0px !important; - width: 80%; - float: left; - /* border: 1px solid #EEEFF2; - border-radius: 2px; */ -} - -.form-control-select-hide { - height: 28px; - margin: 0px !important; - width: 100%; - float: left; - /* border: 1px solid #EEEFF2; - border-radius: 2px; */ -} - -.selectForm-dropdown { - height: 26px; - width: 100%; - border: 1px solid #D8DCE6; - border-radius: 3px; - border-color: #D8DCE6; -} - -.f-page-single-property-editor-component-variable-button { - margin-left: 2%; - float: left; -} - -.dropdown-all-variables { - display: inline-block; - margin-left: 10px; +.f-property-editor-right { height: 28px; } -.f-page-single-property-editor-component-right-customize { - width: 65%; +.f-property-editor-left { float: left; - margin-left: 3%; - background: #FFFFFF; -} - -.f-page-single-property-editor-component-right-expression { - width: 65%; - float: left; - margin-left: 3%; - /* background: #FFFFFF; */ -} - -.f-page-single-property-editor-component-right-stateMachine { - width: 65%; - float: left; - margin-left: 3%; - background: #FFFFFF; - border: 1px solid #D8DCE6; - height: 26px; - border-radius: 3px; -} - -.f-page-single-property-editor-component-right-dataStates { - float: left; - width: 65%; - margin-left: 3%; - background: #FFFFFF; -} - -.f-page-single-property-editor-component-right-stateMachine:focus { - box-shadow: blue; -} - -:host ::ng-deep div.f-stateMachine-combo>farris-combo-list .input-group { - border: 0; - box-shadow: none !important; -} - -:host ::ng-deep div.f-stateMachine-combo>farris-combo-list input-group.actived .input-group { - box-shadow: none !important; -} - -:host ::ng-deep div.f-stateMachine-combo>farris-combo-list .f-cmp-inputgroup.actived { - box-shadow: none !important; -} - -.f-stateMachine-exist { - float: left; - width: 28px; - text-align: center; - background: #FFFFFF; - height: 20px; - margin-top: 2px; - margin-left: 5px; - padding-top: 1px; - background-color: #f4f6ff; - font-size: 13px; - font-family: PingFangSC-Regular; - color: #34495E; -} - -.f-stateMachine-combo { - float: right; - width: 75%; - background: #FFFFFF; -} - -.f-stateMachine-combo .input-group{ - border: unset; - box-shadow: none; -} - -.f-customize-input-controller { height: 28px; - width: 100%; - border: 1px solid #EEEFF2; - border-radius: 2px; -} - -.f-variable-button{ - width: calc(2px + .375rem + 1.4286em); - height: calc(2px + .375rem + 1.4286em); - padding: .1875rem; - border-color: transparent !important; - box-shadow: none !important; - background-color:#f0f0f0; -} + width: 32%; +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/property-editor.props.ts b/packages/ui-vue/components/property-editor/src/property-editor.props.ts index 10b62a8d0fb..1ea95c137a3 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.props.ts +++ b/packages/ui-vue/components/property-editor/src/property-editor.props.ts @@ -1,4 +1,4 @@ - + /** * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. * @@ -14,14 +14,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ExtractPropTypes, PropType } from 'vue'; +import { ExtractPropTypes } from 'vue'; import { createPropsResolver } from '../../dynamic-resolver/src/props-resolver'; import { schemaMapper } from './schema/schema-mapper'; import { schemaResolver } from './schema/schema-resolver'; import propertyEditorSchema from './schema/property-editor.schema.json'; import propertyConfig from './property-config/property-editor.property-config.json'; +import { constPropertyProps } from './components/const/const-property.props'; +import { variablePropertyProps } from './components/variable/variable-property.props'; +import { stateMachinePropertyProps } from './components/state-machine/state-machine-property.props'; +import { customPropertyProps } from './components/custom/custom-property.props'; + +export type PropertyType = 'const' | 'variable' | 'custom' | 'stateMachine' | 'expression'; export const propertyEditorProps = { + ...constPropertyProps, + ...variablePropertyProps, + ...customPropertyProps, + ...stateMachinePropertyProps, + id: { Type: String, default: '' }, + + modelValue: { type: [Number, String, Boolean, Object] }, + /** 属性类型列表 */ + propertyTypes: { type: Array, default: [] }, } as Record; diff --git a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json index 31c62155510..0c2cfb59360 100644 --- a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json +++ b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json @@ -65,7 +65,40 @@ "description": "", "type": "boolean", "default": true + }, + "propertyTypes": { + "description": "", + "type": "Array", + "default": [] + }, + "constEnums": { + "description": "", + "type": "Array", + "default": [] + }, + "constType": { + "description": "", + "type": "String", + "default": "string" + }, + "variables": { + "description": "", + "type": "Array", + "default": [] + }, + "controlName": { + "description": "", + "type": "string", + "default": "" + }, + "stateMachines": { + "description": "", + "type": "Array", + "default": [] } + + + }, "required": [ "id", diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts index 0b41f267c85..d419e51a4a4 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts @@ -313,11 +313,17 @@ export class InputBaseProperty extends BaseControlProperty { readonly: { description: "", title: "只读", - type: "boolean", editor: { - enableClear: true, - editable: true - } + type: "property-editor", + propertyTypes: ['const', 'variable', 'custom', 'stateMachine'], + constType: 'enum', + constEnums: [{ id: true, name: '是' }, { id: false, name: '否' }], + controlName:'', + variables: [ + ], + stateMachines: [ + ] + } }, disabled: { description: "", -- Gitee From 67ce62ab9958e57cf9dbfccaa075b8ed3d39202b Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 17 Mar 2025 21:20:39 +0800 Subject: [PATCH 19/34] =?UTF-8?q?chore:=20property-editor=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../variable/variable-property.component.tsx | 24 ++++++------------- .../property-editor/src/composition/type.ts | 4 ++-- .../src/composition/use-state-machine.ts | 4 ++-- .../src/composition/use-variable.ts | 4 ++-- .../src/schema/property-editor.schema.json | 13 +++++++--- .../composition/entity/input-base-property.ts | 5 +++- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx index ef114433813..6935e43b049 100644 --- a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx @@ -50,10 +50,10 @@ export default function ( /** * 设置变量属性值 */ - function setVariableValue(variable: VariableValue, isTriggerChange: boolean) { + function setVariableValue(variable: VariableValue) { Object.assign(propertyValue.value, variable); currentVariableId.value = propertyValue.value.field; - isTriggerChange && triggerValueChange(propertyValue.value); + triggerValueChange(propertyValue.value); } /** @@ -68,10 +68,10 @@ export default function ( // 3、如果变量已经存在,则使用已有变量,否则使用新增变量 if (existedVariable) { - setVariableValue(existedVariable, true); + setVariableValue(existedVariable); } else { variables.value.push(newVariable); - setVariableValue(newVariable, true); + setVariableValue(newVariable); } } @@ -95,18 +95,9 @@ export default function ( path: variableItem.path, fullPath: variableItem.fullPath, field: variableItem.field, - type: "variable" + type: "Variable" } - setVariableValue(newVariable, true); - } - - /** - * 清空变量值 - */ - function clearVariable() { - const emptyVariable: VariableValue = { type: 'variable', path: '', field: '', fullPath: '' }; - // 清空变量后,属性值不完整,不需要触发变更 - setVariableValue(emptyVariable, false); + setVariableValue(newVariable); } /** @@ -121,7 +112,7 @@ export default function ( v-model={currentVariableId.value} placeholder={''} viewType={'text'} - enableClear={true} + enableClear={false} valueField='field' textField='fullPath' data={variables.value} @@ -129,7 +120,6 @@ export default function ( readonly={readOnly.value} editable={false} onChange={onComboListValueChange} - onClear={clearVariable} > ); diff --git a/packages/ui-vue/components/property-editor/src/composition/type.ts b/packages/ui-vue/components/property-editor/src/composition/type.ts index fcaaf87689a..4446c344c4f 100644 --- a/packages/ui-vue/components/property-editor/src/composition/type.ts +++ b/packages/ui-vue/components/property-editor/src/composition/type.ts @@ -25,7 +25,7 @@ export interface ConstEnumItem { * 变量属性值 */ export interface VariableValue { - type: 'variable'; + type: 'Variable'; /** 变量唯一标识 */ field: string; /** 变量绑定路径 */ @@ -54,7 +54,7 @@ export interface VariableItem { * 状态机属性值 */ export interface StateMachineValue { - type: 'stateMachine'; + type: 'StateMachine'; /** 状态机标识 */ field: string; /** 状态机前缀状态 */ diff --git a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts index 8dc2fe63822..0ca78fe0e75 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts @@ -30,7 +30,7 @@ export function useStateMachine( // 3、转化为新的格式 const newStateMachineFormat: StateMachineValue = { - type: 'stateMachine', + type: 'StateMachine', status: matchResult[1], field: matchResult[2] } @@ -52,7 +52,7 @@ export function useStateMachine( } // 2、如果属性值为空,则新建一个 propertyValue.value = { - type: 'stateMachine', + type: 'StateMachine', field: '', status: false } diff --git a/packages/ui-vue/components/property-editor/src/composition/use-variable.ts b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts index 6903c7d8753..abc63ef301f 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-variable.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts @@ -54,7 +54,7 @@ export function useVariable( const { guid } = useGuid(); const newVariable: VariableValue = { - type: 'variable', + type: 'Variable', path: newVariablePath, field: guid(), fullPath: newVariablePath, @@ -91,7 +91,7 @@ export function useVariable( // 2、如果属性值为空,则新建一个 propertyValue.value = { - type: 'variable', + type: 'Variable', field: '', path: '', fullPath: '' diff --git a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json index 0c2cfb59360..050567b93d9 100644 --- a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json +++ b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json @@ -91,14 +91,21 @@ "type": "string", "default": "" }, + "newVariablePrefix": { + "description": "", + "type": "string", + "default": "" + }, + "newVariableType": { + "description": "", + "type": "string", + "default": "" + }, "stateMachines": { "description": "", "type": "Array", "default": [] } - - - }, "required": [ "id", diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts index a4c0f47ef3f..435e68207ff 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts @@ -308,6 +308,7 @@ export class InputBaseProperty extends BaseControlProperty { type: "input-group", $converter: "/converter/property-editor.converter" }, info); + const controlName = propertyData.type && propertyData.type.toLowerCase().replace(/-/g, '_'); const editorProperties = { readonly: { @@ -318,7 +319,9 @@ export class InputBaseProperty extends BaseControlProperty { propertyTypes: ['const', 'variable', 'custom', 'stateMachine'], constType: 'enum', constEnums: [{ id: true, name: '是' }, { id: false, name: '否' }], - controlName:'', + controlName:controlName, + newVariablePrefix:'is', + newVariableType:'Boolean', variables: [ ], stateMachines: [ -- Gitee From 24d1a9091b4a6db5153fde43400c35b6898e8665 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 17 Mar 2025 21:26:16 +0800 Subject: [PATCH 20/34] =?UTF-8?q?chore:=20property-editor=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../property-editor/src/schema/property-editor.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json index 050567b93d9..0afe10b9003 100644 --- a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json +++ b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json @@ -79,7 +79,7 @@ "constType": { "description": "", "type": "String", - "default": "string" + "default": "" }, "variables": { "description": "", -- Gitee From 9421ce8571242d6b3aa4e9844d6517f160a6bfcf Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 17 Mar 2025 22:19:43 +0800 Subject: [PATCH 21/34] =?UTF-8?q?chore:=20property-editor=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/const/const-property.component.tsx | 2 +- .../components/custom/custom-property.component.tsx | 2 +- .../property-editor/src/composition/data.ts | 10 +++++----- .../src/composition/use-property-type.ts | 12 ++++++------ .../src/composition/use-state-machine.ts | 2 +- .../property-editor/src/composition/use-variable.ts | 2 +- .../src/property-editor.component.tsx | 8 ++++---- .../property-editor/src/property-editor.props.ts | 2 +- .../src/composition/entity/input-base-property.ts | 2 +- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx index f224c83079f..d2c3f2d2d59 100644 --- a/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx @@ -34,7 +34,7 @@ export default function ( /** 属性值相关方法 */ const { getPropertyValue, triggerValueChange } = usePropertyValueComposition; - const propertyValue = getPropertyValue('const'); + const propertyValue = getPropertyValue('Const'); /** 控制右侧区域显示的内容 */ const shouldShowContent = computed(() => (type: string) => { diff --git a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx index a9f1f38873e..bbf98dfa192 100644 --- a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx @@ -28,7 +28,7 @@ export default function ( const readOnly: Ref = ref(false); /** 属性值相关方法 */ const { getPropertyValue, triggerValueChange } = usePropertyValueComposition; - const propertyValue: Ref = getPropertyValue('custom'); + const propertyValue: Ref = getPropertyValue('Custom'); /** * 文本控件值变化事件 diff --git a/packages/ui-vue/components/property-editor/src/composition/data.ts b/packages/ui-vue/components/property-editor/src/composition/data.ts index 04f8fcfaef7..75bc3ad7c19 100644 --- a/packages/ui-vue/components/property-editor/src/composition/data.ts +++ b/packages/ui-vue/components/property-editor/src/composition/data.ts @@ -3,23 +3,23 @@ import { PropertyTypeItem } from './type'; /** 左侧属性类型的枚举数据 */ export const PROPERTY_TYPE_ENUMS: PropertyTypeItem[] = [ { - 'id': 'const', + 'id': 'Const', 'name': '常量' }, { - 'id': 'variable', + 'id': 'Variable', 'name': '变量' }, { - 'id': 'custom', + 'id': 'Custom', 'name': '自定义' }, { - 'id': 'stateMachine', + 'id': 'StateMachine', 'name': '状态机' }, { - 'id': 'expression', + 'id': 'Expression', 'name': '表达式' } ]; diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts index b58aae05116..b7d942d0dc2 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts @@ -53,11 +53,11 @@ export function usePropertyType( const allowedPropertyTypes = propertyTypes.value; // 1、常量枚举类型 - const isConstEnum = allowedPropertyTypes.includes('const') && constType.value === 'enum' + const isConstEnum = allowedPropertyTypes.includes('Const') && constType.value === 'enum' && constEnums.value.findIndex(constEnum => constEnum.id === propertyValue) > -1; // 2、常量数值类型 - const isConstNumber = allowedPropertyTypes.includes('const') && constType.value === 'number' + const isConstNumber = allowedPropertyTypes.includes('Const') && constType.value === 'number' && typeof propertyValue === "number"; return isConstEnum || isConstNumber; @@ -72,7 +72,7 @@ export function usePropertyType( function isCustom(propertyValue: any): boolean { const allowedPropertyTypes = propertyTypes.value; - const isCustom = allowedPropertyTypes.includes("custom") && typeof (propertyValue) === 'string'; + const isCustom = allowedPropertyTypes.includes("Custom") && typeof (propertyValue) === 'string'; return isCustom; } @@ -97,9 +97,9 @@ export function usePropertyType( function extractFromNonObjectType(propertyValue: any): PropertyType | undefined { // 1、定义属性类型检查器 const typeCheckers = new Map boolean>([ - ['const', isConst], - ['stateMachine', isStateMachine], - ['custom', isCustom], + ['Const', isConst], + ['StateMachine', isStateMachine], + ['Custom', isCustom], ]); // 2、遍历检查器,找到匹配的类型 diff --git a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts index 0ca78fe0e75..9e5e8bafb7e 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts @@ -45,7 +45,7 @@ export function useStateMachine( */ function getStateMachineValue() { // 1、如果存在属性值,则直接返回 - const propertyValue: Ref = getPropertyValue('stateMachine'); + const propertyValue: Ref = getPropertyValue('StateMachine'); if (propertyValue.value) { convertStateMachineFormat(propertyValue); return propertyValue; diff --git a/packages/ui-vue/components/property-editor/src/composition/use-variable.ts b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts index abc63ef301f..84cab70df8d 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-variable.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts @@ -84,7 +84,7 @@ export function useVariable( */ function getVariableValue(): Ref { // 1、如果存在属性值,则直接返回 - const propertyValue: Ref = getPropertyValue('variable'); + const propertyValue: Ref = getPropertyValue('Variable'); if (propertyValue.value) { return propertyValue; } diff --git a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx index efc8c7fe5b0..2c7cf82820d 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx +++ b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx @@ -96,10 +96,10 @@ export default defineComponent({ /** 右侧区域渲染方法 */ return (
- {shouldShowRight.value('const') && renderConst()} - {shouldShowRight.value('variable') && renderVariable()} - {shouldShowRight.value('custom') && renderCustom()} - {shouldShowRight.value('stateMachine') && renderStateMachine()} + {shouldShowRight.value('Const') && renderConst()} + {shouldShowRight.value('Variable') && renderVariable()} + {shouldShowRight.value('Custom') && renderCustom()} + {shouldShowRight.value('StateMachine') && renderStateMachine()}
); diff --git a/packages/ui-vue/components/property-editor/src/property-editor.props.ts b/packages/ui-vue/components/property-editor/src/property-editor.props.ts index 1ea95c137a3..31647b12c95 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.props.ts +++ b/packages/ui-vue/components/property-editor/src/property-editor.props.ts @@ -25,7 +25,7 @@ import { variablePropertyProps } from './components/variable/variable-property.p import { stateMachinePropertyProps } from './components/state-machine/state-machine-property.props'; import { customPropertyProps } from './components/custom/custom-property.props'; -export type PropertyType = 'const' | 'variable' | 'custom' | 'stateMachine' | 'expression'; +export type PropertyType = 'Const' | 'Variable' | 'Custom' | 'StateMachine' | 'Expression'; export const propertyEditorProps = { ...constPropertyProps, diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts index 435e68207ff..cabb2e63e6e 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts @@ -316,7 +316,7 @@ export class InputBaseProperty extends BaseControlProperty { title: "只读", editor: { type: "property-editor", - propertyTypes: ['const', 'variable', 'custom', 'stateMachine'], + propertyTypes: ['Const', 'Variable', 'Custom', 'StateMachine'], constType: 'enum', constEnums: [{ id: true, name: '是' }, { id: false, name: '否' }], controlName:controlName, -- Gitee From ae0e96d45c86edd2e801aa9e154292b6e838a685 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Wed, 19 Mar 2025 09:23:49 +0800 Subject: [PATCH 22/34] =?UTF-8?q?chore:=20=E6=8F=90=E4=BE=9B=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E8=A1=A8=E5=8D=95=E5=86=85=E5=8F=98=E9=87=8F=E7=9A=84?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/composition/use-form-schema.ts | 21 ++++- .../designer/src/components/types/metadata.ts | 2 + .../const/const-property.component.tsx | 2 +- .../components/const/const-property.props.ts | 2 +- .../custom/custom-property.component.tsx | 2 +- .../expression-property.component.tsx | 77 +++++++++++++++++++ .../expression/expression-property.css | 5 ++ .../expression/expression-property.props.ts | 23 ++++++ .../state-machine-property.component.tsx | 2 +- .../state-machine-property.props.ts | 2 +- .../variable/variable-property.component.tsx | 11 ++- .../variable/variable-property.props.ts | 2 +- .../src/composition/{data.ts => datas.ts} | 2 +- .../src/composition/{type.ts => types.ts} | 5 ++ .../src/composition/use-property-editor.ts | 66 ++++++++++++++++ .../src/composition/use-property-type.ts | 4 +- .../src/composition/use-property-value.ts | 2 +- .../src/composition/use-state-machine.ts | 2 +- .../src/composition/use-variable.ts | 14 +++- .../src/property-editor.component.tsx | 4 +- .../src/schema/property-editor.schema.json | 4 +- .../src/composition/entity/base-property.ts | 50 ++++++++++-- .../composition/entity/input-base-property.ts | 20 +++-- 23 files changed, 294 insertions(+), 30 deletions(-) create mode 100644 packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx create mode 100644 packages/ui-vue/components/property-editor/src/components/expression/expression-property.css create mode 100644 packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts rename packages/ui-vue/components/property-editor/src/composition/{data.ts => datas.ts} (90%) rename packages/ui-vue/components/property-editor/src/composition/{type.ts => types.ts} (93%) create mode 100644 packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts diff --git a/packages/designer/src/components/composition/use-form-schema.ts b/packages/designer/src/components/composition/use-form-schema.ts index 0986e1b165e..a5f46eba53c 100644 --- a/packages/designer/src/components/composition/use-form-schema.ts +++ b/packages/designer/src/components/composition/use-form-schema.ts @@ -739,6 +739,23 @@ export function useFormSchema(): UseFormSchema { } } } + + /** + * 根据编号获取变量 + */ + function getVariableByCode(variableCode: string): FormVariable | undefined { + const viewModels = formSchema.module.viewmodels; + if (!viewModels || viewModels.length === 0) { + return; + } + for (const viewModel of viewModels) { + const variable = viewModel.states.find(stateItem => stateItem.code === variableCode); + if (variable) { + return variable; + } + } + } + /** * 获取所有VM下的变量,组装成树结构 * 树表中额外增加statePath属性(命令所在viewModelId.variableCode),用于窗口展开时数据行的回显。 @@ -1302,6 +1319,8 @@ export function useFormSchema(): UseFormSchema { deleteComponent, getControlsInCmpWidthBinding, getVariableById, - updateRemoteVariables + getVariableByCode, + updateRemoteVariables, + getRootViewModelId }; } diff --git a/packages/designer/src/components/types/metadata.ts b/packages/designer/src/components/types/metadata.ts index 6715f37ae3d..32703509242 100644 --- a/packages/designer/src/components/types/metadata.ts +++ b/packages/designer/src/components/types/metadata.ts @@ -218,6 +218,7 @@ export interface UseFormSchema { setFormTemplateRule: (rules: any) => void; getFormTemplateRule: () => any; getLocaleVariablesByViewModelId: (viewModelId: string) => any; + getRootViewModelId: () => string; getRemoteVariables: () => any; getFieldsByViewModelId: (viewModelId: string) => FormSchemaEntityField[] | undefined; getExpressions: () => FormExpression[]; @@ -225,6 +226,7 @@ export interface UseFormSchema { deleteComponent: (componentId: string) => void; getControlsInCmpWidthBinding: (viewModelId: string, fieldId: string) => any; getVariableById: (variableId: string) => FormVariable | undefined; + getVariableByCode: (variableCode: string) => FormVariable | undefined; updateRemoteVariables: (variables: FormSchemaEntityField[]) => void; } diff --git a/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx index d2c3f2d2d59..bbf5eebae02 100644 --- a/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/const/const-property.component.tsx @@ -18,7 +18,7 @@ import { ConstPropertyProps, ConstType } from './const-property.props'; import { FComboList } from '@farris/ui-vue/components/combo-list'; import { FNumberSpinner } from '@farris/ui-vue/components/number-spinner'; import './const-property.css'; -import { ConstEnumItem, UsePropertyValue } from '../../composition/type'; +import { ConstEnumItem, UsePropertyValue } from '../../composition/types'; export default function ( props: ConstPropertyProps, diff --git a/packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts b/packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts index 8b3dfd1c951..b83b6bdce93 100644 --- a/packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts +++ b/packages/ui-vue/components/property-editor/src/components/const/const-property.props.ts @@ -15,7 +15,7 @@ * limitations under the License. */ import { ExtractPropTypes, PropType } from 'vue'; -import { ConstEnumItem } from '../../composition/type'; +import { ConstEnumItem } from '../../composition/types'; export type ConstType = 'number' | 'enum'; export const constPropertyProps = { diff --git a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx index bbf98dfa192..3d433b9b207 100644 --- a/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/custom/custom-property.component.tsx @@ -17,7 +17,7 @@ import { Ref, ref, SetupContext } from 'vue'; import { CustomPropertyProps } from './custom-property.props'; import './custom-property.css'; -import { UsePropertyValue } from '../../composition/type'; +import { UsePropertyValue } from '../../composition/types'; import { JSX } from 'vue/jsx-runtime'; export default function ( diff --git a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx new file mode 100644 index 00000000000..61cd40e5829 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx @@ -0,0 +1,77 @@ +/** + * 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 { Ref, ref, SetupContext } from 'vue'; +import { ExpressionPropertyProps } from './expression-property.props'; +import { FInputGroup } from '@farris/ui-vue/components/input-group'; +import './expression-property.css'; +import { UsePropertyValue } from '../../composition/types'; +import { ExpressionEditor } from '@farris/ui-vue/components/expression-editor'; +import { FModalService } from '@farris/ui-vue/components/modal'; + +export default function ( + props: ExpressionPropertyProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +) { + const readOnly = ref(false); + /** 表达式绑定值 */ + const expressionValue = ref(''); + const groupIcon = ref(""); + + /** + * 将表达式绑定值置为空 + */ + function clearExpressionValue() { + + } + + /** + * 弹出表达式编辑器 + */ + function showExpressionEditor() { + const config = { + render: () => { + return + ; + }, + width: 1060, + height: 600, + fitContent: false, + showButtons: false, + showHeader: false, + showFloatingClose: true + } + FModalService.show(config); + } + return () => { + return ( +
+ +
+ ); + }; + +} diff --git a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.css b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.css new file mode 100644 index 00000000000..fa335d0e915 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.css @@ -0,0 +1,5 @@ +.f-property-editor-expression-container { + width: 65%; + float: left; + margin-left: 3%; +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts new file mode 100644 index 00000000000..9e54d3102ed --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts @@ -0,0 +1,23 @@ + +/** + * 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 { ExtractPropTypes } from 'vue'; + +export const expressionPropertyProps = { + +} as Record; + +export type ExpressionPropertyProps = ExtractPropTypes; diff --git a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx index 9c80ab4dd7c..9db1949e968 100644 --- a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx @@ -18,7 +18,7 @@ import { StateMachinePropertyProps } from './state-machine-property.props'; import { FComboList } from '@farris/ui-vue/components/combo-list'; import './state-machine-property.css'; import { useStateMachine } from '../../composition/use-state-machine'; -import { StateMachineItem, UsePropertyValue } from '../../composition/type'; +import { StateMachineItem, UsePropertyValue } from '../../composition/types'; export default function ( props: StateMachinePropertyProps, diff --git a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts index 296e5131331..da85d3eaeed 100644 --- a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts +++ b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.props.ts @@ -15,7 +15,7 @@ * limitations under the License. */ import { ExtractPropTypes } from 'vue'; -import { StateMachineItem } from '../../composition/type'; +import { StateMachineItem } from '../../composition/types'; export const stateMachinePropertyProps = { /** 状态机列表 */ diff --git a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx index 6935e43b049..68973d45e76 100644 --- a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.component.tsx @@ -17,7 +17,7 @@ import { computed, Ref, ref, SetupContext } from 'vue'; import { VariablePropertyProps } from './variable-property.props'; import { FComboList } from '@farris/ui-vue/components/combo-list'; import './variable-property.css' -import { UsePropertyValue, VariableItem, VariableValue } from '../../composition/type'; +import { UsePropertyValue, VariableItem, VariableValue } from '../../composition/types'; import { useVariable } from '../../composition/use-variable'; export default function ( @@ -51,7 +51,13 @@ export default function ( * 设置变量属性值 */ function setVariableValue(variable: VariableValue) { - Object.assign(propertyValue.value, variable); + Object.assign(propertyValue.value, { + field: variable.field, + path: variable.path, + fullPath: variable.fullPath, + isNewVariable: variable.isNewVariable, + newVariableType: variable.isNewVariable && variable.newVariableType + }); currentVariableId.value = propertyValue.value.field; triggerValueChange(propertyValue.value); } @@ -114,6 +120,7 @@ export default function ( viewType={'text'} enableClear={false} valueField='field' + idField='field' textField='fullPath' data={variables.value} beforeOpen={beforeShowVariable} diff --git a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts index aad22c5712f..c87614d54ad 100644 --- a/packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts +++ b/packages/ui-vue/components/property-editor/src/components/variable/variable-property.props.ts @@ -15,7 +15,7 @@ * limitations under the License. */ import { ExtractPropTypes } from 'vue'; -import { VariableItem } from '../../composition/type'; +import { VariableItem } from '../../composition/types'; export const variablePropertyProps = { variables: { type: Array, default: [] }, diff --git a/packages/ui-vue/components/property-editor/src/composition/data.ts b/packages/ui-vue/components/property-editor/src/composition/datas.ts similarity index 90% rename from packages/ui-vue/components/property-editor/src/composition/data.ts rename to packages/ui-vue/components/property-editor/src/composition/datas.ts index 75bc3ad7c19..d4e69075a60 100644 --- a/packages/ui-vue/components/property-editor/src/composition/data.ts +++ b/packages/ui-vue/components/property-editor/src/composition/datas.ts @@ -1,4 +1,4 @@ -import { PropertyTypeItem } from './type'; +import { PropertyTypeItem } from './types'; /** 左侧属性类型的枚举数据 */ export const PROPERTY_TYPE_ENUMS: PropertyTypeItem[] = [ diff --git a/packages/ui-vue/components/property-editor/src/composition/type.ts b/packages/ui-vue/components/property-editor/src/composition/types.ts similarity index 93% rename from packages/ui-vue/components/property-editor/src/composition/type.ts rename to packages/ui-vue/components/property-editor/src/composition/types.ts index 4446c344c4f..45f401b05f9 100644 --- a/packages/ui-vue/components/property-editor/src/composition/type.ts +++ b/packages/ui-vue/components/property-editor/src/composition/types.ts @@ -93,3 +93,8 @@ export interface UseVariable { getVariableByPath: (variablePath: string) => VariableValue; getVariableValue: () => Ref; } + +export interface UsePropertyEditor { + getVariables: (viewModelId: string) => any[]; + getControlName: (propertyData: any) => string; +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts new file mode 100644 index 00000000000..035bd7640c9 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts @@ -0,0 +1,66 @@ +import { FormVariable } from "@farris/ui-vue/components/common"; +import { DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import { UsePropertyEditor } from "./types"; + +/** + * PropertyEditor对外提供的接口 + * @param designerHostService + * @returns + */ +export function usePropertyEditor(designerHostService: DesignerHostService): UsePropertyEditor { + const { formSchemaUtils } = designerHostService; + + /** + * 把变量视图模型的变量转化为PropertyEditor的变量格式 + * @param variable + * @returns + */ + function convertToEditorVariable(variable: FormVariable, pathPrefix: string = '') { + return { + category: variable.category, + path: pathPrefix + variable.code, + name: variable.name, + field: variable.id, + fullPath: variable.code + }; + } + + /** + * 获取视图模型上的变量 + * @param viewModelId + * @returns + */ + function getVariablesByViewModelId(viewModelId: string, pathPrefix: string = '') { + const viewModel = formSchemaUtils.getViewModelById(viewModelId); + return viewModel.states.map(state => convertToEditorVariable(state, pathPrefix)); + } + + /** + * 获取PropertyEditor需要的变量数据 + */ + function getVariables(viewModelId: string): any[] { + const rootViewModelId = formSchemaUtils.getRootViewModelId(); + // 1、当前组件的组件变量 + const currentViewModelVariables = getVariablesByViewModelId(viewModelId); + if (viewModelId === rootViewModelId) { + return currentViewModelVariables; + } + + // 2、根组件的组件变量 + const rootViewModelVariables = getVariablesByViewModelId(rootViewModelId, 'root-component.'); + return [...currentViewModelVariables, ...rootViewModelVariables]; + } + + /** + * 获取控件名称 + * @param propertyData + * @returns + */ + function getControlName(propertyData: any): string { + const bindingPath = propertyData && propertyData.binding && propertyData.binding.path; + return bindingPath || ''; + + } + + return { getVariables, getControlName }; +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts index b7d942d0dc2..fdf7b5b3c7b 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts @@ -2,8 +2,8 @@ import { Ref, SetupContext, ref } from "vue"; import { PropertyEditorProps, PropertyType } from "../property-editor.props"; -import { PROPERTY_TYPE_ENUMS } from "./data"; -import { ConstEnumItem, PropertyTypeItem, UsePropertyType } from "./type"; +import { PROPERTY_TYPE_ENUMS } from "./datas"; +import { ConstEnumItem, PropertyTypeItem, UsePropertyType } from "./types"; import { ConstType } from "../components/const/const-property.props"; export function usePropertyType( diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts index e52530c6160..3ad722aabce 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts @@ -1,6 +1,6 @@ import { Ref, SetupContext, ref } from "vue"; import { PropertyEditorProps, PropertyType } from "../property-editor.props"; -import { UsePropertyValue } from "./type"; +import { UsePropertyValue } from "./types"; import { cloneDeep } from "lodash"; export function usePropertyValue( diff --git a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts index 9e5e8bafb7e..d96ccaa36db 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts @@ -1,6 +1,6 @@ import { Ref, SetupContext, ref } from "vue"; import { PropertyEditorProps } from "../property-editor.props"; -import { StateMachineValue, UsePropertyValue, UseStateMachine } from "./type"; +import { StateMachineValue, UsePropertyValue, UseStateMachine } from "./types"; export function useStateMachine( props: PropertyEditorProps, diff --git a/packages/ui-vue/components/property-editor/src/composition/use-variable.ts b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts index 84cab70df8d..bbdefab21a0 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-variable.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-variable.ts @@ -3,7 +3,7 @@ import { Ref, SetupContext, ref } from "vue"; import { PropertyEditorProps } from "../property-editor.props"; import { useGuid } from '@farris/ui-vue/components/common'; -import { UsePropertyValue, UseVariable, VariableValue } from "./type"; +import { UsePropertyValue, UseVariable, VariableValue } from "./types"; export function useVariable( props: PropertyEditorProps, @@ -37,6 +37,15 @@ export function useVariable( return originalString[0].toLowerCase() + originalString.slice(1); } + /** + * 把_和-删除,并且把后面第一个字符转为大写 + * @param originalString + * @returns + */ + function removeAndCapitalize(originalString: string): string { + return originalString.replace(/[-_](.)/g, (match, char) => char.toUpperCase()); + } + /** * 生成新的变量 * @returns @@ -50,7 +59,8 @@ export function useVariable( const splicingNameRight = setFirstLetterUpperCase(propertyName.value); // 3、拼接成新的变量名 - const newVariablePath = `${newVariablePrefix.value}${splicingNameMiddle}${splicingNameRight}`; + let newVariablePath = `${newVariablePrefix.value}${splicingNameMiddle}${splicingNameRight}`; + newVariablePath = removeAndCapitalize(newVariablePath); const { guid } = useGuid(); const newVariable: VariableValue = { diff --git a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx index 2c7cf82820d..de64ebd412d 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx +++ b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx @@ -21,6 +21,7 @@ import getConstRender from './components/const/const-property.component'; import getVariableRender from './components/variable/variable-property.component'; import getStateMachineRender from './components/state-machine/state-machine-property.component'; import getCustomRender from './components/custom/custom-property.component'; +import getExpressionRender from './components/expression/expression-property.component'; import { usePropertyValue } from './composition/use-property-value'; import { usePropertyType } from './composition/use-property-type'; @@ -48,6 +49,7 @@ export default defineComponent({ const renderVariable = getVariableRender(props, context, usePropertyValueComposition); const renderCustom = getCustomRender(props, context, usePropertyValueComposition); const renderStateMachine = getStateMachineRender(props, context, usePropertyValueComposition); + const renderExpression = getExpressionRender(props, context, usePropertyValueComposition); /** 控制右侧区域显示 */ const shouldShowRight = computed(() => (selectedPropertyType: PropertyType) => { return selectedPropertyType === currentPropertyType.value; @@ -100,7 +102,7 @@ export default defineComponent({ {shouldShowRight.value('Variable') && renderVariable()} {shouldShowRight.value('Custom') && renderCustom()} {shouldShowRight.value('StateMachine') && renderStateMachine()} - + {shouldShowRight.value('Expression') && renderExpression()}
); } diff --git a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json index 0afe10b9003..65a19971f75 100644 --- a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json +++ b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json @@ -108,7 +108,9 @@ } }, "required": [ - "id", "type" + ], + "ignore": [ + "id" ] } \ No newline at end of file diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts index dc43fc281c2..2f22e82553f 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts @@ -3,6 +3,7 @@ import { DgControl } from "../../../../designer-canvas/src/composition/dg-contro import { cloneDeep } from "lodash-es"; import { refreshCanvas } from "../../../../designer-canvas/src/composition/update-cancas"; import { canvasChanged } from "../../../../designer-canvas/src/composition/designer-canvas-changed"; +import { PropertyChangeObject } from "./property-entity"; /** * 控件属性基类 @@ -153,11 +154,11 @@ export class BaseControlProperty { } /** - * - * @param propertyId - * @param componentInstance - * @returns - */ + * + * @param propertyId + * @param componentInstance + * @returns + */ public updateElementByParentContainer(propertyId: string, componentInstance: DesignerComponentInstance) { // 1、定位控件父容器 const parentContainer = componentInstance && componentInstance.parent && componentInstance.parent['schema']; @@ -173,4 +174,43 @@ export class BaseControlProperty { refreshCanvas(); } + /** + * 属性编辑器,在编辑过程中会新增变量,此处需要将新增的变量追加到ViewModel中 + * @param changeObject + * @param viewModelId + * @returns + */ + public addNewVariableToViewModel(changeObject: PropertyChangeObject, viewModelId: string) { + const newPropertyValue = changeObject.propertyValue; + // 1、判断当前属性值是否为对象 + const isObject = newPropertyValue && typeof newPropertyValue === 'object'; + if (!isObject) { + return; + } + + // 2、判断是否为新变量 + const isNewVariable = newPropertyValue.type === 'Variable' && newPropertyValue.isNewVariable; + if (!isNewVariable) { + return; + } + + // 3、构造变量结构 + const newVariable = { + id: newPropertyValue.field, + category: 'locale', + code: newPropertyValue.fullPath, + name: newPropertyValue.fullPath, + type: newPropertyValue.newVariableType || 'String' + }; + delete newPropertyValue.newVariableType; + delete newPropertyValue.isNewVariable; + + // 4、把新变量添加到ViewModel中 + const existedVariable = this.formSchemaUtils.getVariableByCode(newVariable.code); + if (!existedVariable) { + const viewModel = this.formSchemaUtils.getViewModelById(viewModelId); + viewModel.states.push(newVariable); + } + } + } diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts index cabb2e63e6e..f13562019c9 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts @@ -11,6 +11,7 @@ import { import { useResponseLayoutEditorSetting } from "../../../../response-layout-editor/src/composition/converter/use-response-layout-editor-setting"; import { FormSchemaEntityField$Type, FormSchemaEntityFieldType$Type, FormVariable } from "@farris/ui-vue/components/common"; import { DgControl } from "../../../../designer-canvas"; +import { usePropertyEditor } from "../../../../property-editor/src/composition/use-property-editor"; export class InputBaseProperty extends BaseControlProperty { public responseLayoutEditorFunction: UseResponseLayoutEditorSetting; @@ -308,7 +309,8 @@ export class InputBaseProperty extends BaseControlProperty { type: "input-group", $converter: "/converter/property-editor.converter" }, info); - const controlName = propertyData.type && propertyData.type.toLowerCase().replace(/-/g, '_'); + + const { getVariables, getControlName } = usePropertyEditor(this.designerHostService) const editorProperties = { readonly: { @@ -319,14 +321,13 @@ export class InputBaseProperty extends BaseControlProperty { propertyTypes: ['Const', 'Variable', 'Custom', 'StateMachine'], constType: 'enum', constEnums: [{ id: true, name: '是' }, { id: false, name: '否' }], - controlName:controlName, - newVariablePrefix:'is', - newVariableType:'Boolean', - variables: [ - ], + controlName: getControlName(propertyData), + newVariablePrefix: 'is', + newVariableType: 'Boolean', + variables: getVariables(this.viewModelId), stateMachines: [ ] - } + } }, disabled: { description: "", @@ -349,6 +350,11 @@ export class InputBaseProperty extends BaseControlProperty { // 合并属性,保留原属性值 editorProperties[key] = Object.assign(editorProperties[key] || {}, properties[key]); } + if (!setPropertyRelates) { + setPropertyRelates = (changeObject) => { + this.addNewVariableToViewModel(changeObject, this.viewModelId); + } + } return { ...editorBasic, properties: { ...editorProperties }, setPropertyRelates }; -- Gitee From 915e2e2aeea217faa2c6a761b36bb5a36757e4a2 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 24 Mar 2025 09:01:21 +0800 Subject: [PATCH 23/34] =?UTF-8?q?feature:=20property-edotor=E9=9B=86?= =?UTF-8?q?=E6=88=90=E8=A1=A8=E8=BE=BE=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expression-property.component.tsx | 69 ++++++++----------- .../expression/expression-property.props.ts | 2 +- .../property-editor/src/composition/types.ts | 38 +++++++++- .../src/composition/use-expression.ts | 53 ++++++++++++++ .../src/composition/use-property-editor.ts | 22 +++--- .../src/composition/use-property-type.ts | 2 +- .../src/composition/use-property-value.ts | 24 ++++++- .../src/property-editor.component.tsx | 4 +- .../src/property-editor.props.ts | 2 + .../src/schema/property-editor.schema.json | 7 +- .../src/composition/entity/base-property.ts | 66 ++++++++++++++++++ .../composition/entity/expression-property.ts | 27 +++++++- .../composition/entity/input-base-property.ts | 20 ++++-- 13 files changed, 271 insertions(+), 65 deletions(-) create mode 100644 packages/ui-vue/components/property-editor/src/composition/use-expression.ts diff --git a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx index 61cd40e5829..b799d0fcc44 100644 --- a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Ref, ref, SetupContext } from 'vue'; +import { ref, SetupContext } from 'vue'; import { ExpressionPropertyProps } from './expression-property.props'; -import { FInputGroup } from '@farris/ui-vue/components/input-group'; import './expression-property.css'; import { UsePropertyValue } from '../../composition/types'; -import { ExpressionEditor } from '@farris/ui-vue/components/expression-editor'; -import { FModalService } from '@farris/ui-vue/components/modal'; +import { FExpressionTextbox } from '@farris/ui-vue/components/expression-editor'; +import { useExpression } from '../../composition/use-expression'; export default function ( props: ExpressionPropertyProps, @@ -27,49 +26,41 @@ export default function ( usePropertyValueComposition: UsePropertyValue ) { const readOnly = ref(false); - /** 表达式绑定值 */ - const expressionValue = ref(''); - const groupIcon = ref(""); + /** 属性值相关方法 */ + const { triggerValueChange } = usePropertyValueComposition; - /** - * 将表达式绑定值置为空 - */ - function clearExpressionValue() { + /** 表达式相关方法 */ + const { getExpressionValue } = useExpression(props, context, usePropertyValueComposition); + /** 表达式属性值 */ + const expressionValue = getExpressionValue(); + const { expressionInfo } = expressionValue.value; + /** 表达式的规则值 */ + const expressionRule = ref(expressionInfo.value); + /** 表达式的提示信息 */ + const expressionMessage = ref(expressionInfo.message); + /** 表达式编辑器所需的配置 */ + const expressionConfig = ref(props.expressionConfig) - } - - /** - * 弹出表达式编辑器 - */ - function showExpressionEditor() { - const config = { - render: () => { - return - ; - }, - width: 1060, - height: 600, - fitContent: false, - showButtons: false, - showHeader: false, - showFloatingClose: true + function onSubmitModal({ expression, message }) { + if (!expression) { + return; } - FModalService.show(config); + expressionValue.value.expressionInfo.value = expression; + expressionValue.value.expressionInfo.message = message; + triggerValueChange(expressionValue.value); } + return () => { return ( -
- + + onSubmitModal={onSubmitModal} + >
); }; diff --git a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts index 9e54d3102ed..0671b5b5790 100644 --- a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts +++ b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.props.ts @@ -17,7 +17,7 @@ import { ExtractPropTypes } from 'vue'; export const expressionPropertyProps = { - + expressionConfig: { type: Object , default: {} }, } as Record; export type ExpressionPropertyProps = ExtractPropTypes; diff --git a/packages/ui-vue/components/property-editor/src/composition/types.ts b/packages/ui-vue/components/property-editor/src/composition/types.ts index 45f401b05f9..f8b7acb1057 100644 --- a/packages/ui-vue/components/property-editor/src/composition/types.ts +++ b/packages/ui-vue/components/property-editor/src/composition/types.ts @@ -71,10 +71,37 @@ export interface StateMachineItem { name: string; } +/** + * 表达式的信息 + */ +export interface ExpressionInfo { + /** 表达式的规则值 */ + value: string; + /** 表达式的提示信息 */ + message: string; + /** 表达式目标控件的标识 */ + targetId: string; + /** 表达式目标控件的类型 */ + targetType: string; + /** 表达式的类型 */ + expressionType: string; +} + +/** + * 表达式属性值 + */ +export interface ExpressionValue { + type: 'Expression'; + /** 表达式标识 */ + expressionId: string; + /** 表达式信息,用于往expressions节点存储 */ + expressionInfo: ExpressionInfo; +} + export interface UsePropertyValue { triggerValueChange: (newValue: any) => void; getPropertyValue: (propertyType: PropertyType) => Ref; - + isPropertyValueValid: (propertyType: PropertyType, propertyValue: any) => boolean; } export interface UsePropertyType { @@ -95,6 +122,11 @@ export interface UseVariable { } export interface UsePropertyEditor { - getVariables: (viewModelId: string) => any[]; + getVariables: (viewModelId: string) => VariableItem[]; getControlName: (propertyData: any) => string; -} \ No newline at end of file + getStateMachines: () => StateMachineItem[]; +} + +export interface UseExpression { + getExpressionValue: () => Ref; +} diff --git a/packages/ui-vue/components/property-editor/src/composition/use-expression.ts b/packages/ui-vue/components/property-editor/src/composition/use-expression.ts new file mode 100644 index 00000000000..c4dee062f96 --- /dev/null +++ b/packages/ui-vue/components/property-editor/src/composition/use-expression.ts @@ -0,0 +1,53 @@ +import { Ref, SetupContext, ref } from "vue"; +import { PropertyEditorProps } from "../property-editor.props"; +import { ExpressionValue, UseExpression, UsePropertyValue } from "./types"; + +export function useExpression( + props: PropertyEditorProps, + context: SetupContext, + usePropertyValueComposition: UsePropertyValue +): UseExpression { + + const { getPropertyValue } = usePropertyValueComposition; + const expressionType = props.id; + const { expressionConfig } = props; + const { targetId } = expressionConfig && expressionConfig.expressionInfo; + + /** + * 生成表达式内码 + * @returns + */ + function generateExpressionId(): string { + return targetId + '_' + expressionType; + } + + /** + * 生成有个空的表达式值 + * @returns + */ + function generateExpressionValue(): ExpressionValue { + return { + type: 'Expression', + expressionId: generateExpressionId(), + expressionInfo: expressionConfig.expressionInfo + } + } + + /** + * 获取表达式的值 + */ + function getExpressionValue(): Ref { + const propertyValue = getPropertyValue('Expression'); + // 1、表达式为空,生成一个空的表达式值 + if (!propertyValue.value) { + propertyValue.value = generateExpressionValue(); + return propertyValue; + } + + // 2、记录expressionInfo的值 + propertyValue.value.expressionInfo = expressionConfig.expressionInfo; + return propertyValue; + } + + return { getExpressionValue }; +} diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts index 035bd7640c9..66043c05fbb 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts @@ -1,6 +1,6 @@ import { FormVariable } from "@farris/ui-vue/components/common"; import { DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; -import { UsePropertyEditor } from "./types"; +import { StateMachineItem, UsePropertyEditor, VariableItem } from "./types"; /** * PropertyEditor对外提供的接口 @@ -8,18 +8,16 @@ import { UsePropertyEditor } from "./types"; * @returns */ export function usePropertyEditor(designerHostService: DesignerHostService): UsePropertyEditor { - const { formSchemaUtils } = designerHostService; + const { formSchemaUtils, formStateMachineUtils } = designerHostService; /** * 把变量视图模型的变量转化为PropertyEditor的变量格式 * @param variable * @returns */ - function convertToEditorVariable(variable: FormVariable, pathPrefix: string = '') { + function convertToEditorVariable(variable: FormVariable, pathPrefix: string = ''):VariableItem { return { - category: variable.category, path: pathPrefix + variable.code, - name: variable.name, field: variable.id, fullPath: variable.code }; @@ -30,7 +28,7 @@ export function usePropertyEditor(designerHostService: DesignerHostService): Use * @param viewModelId * @returns */ - function getVariablesByViewModelId(viewModelId: string, pathPrefix: string = '') { + function getVariablesByViewModelId(viewModelId: string, pathPrefix: string = ''):VariableItem[] { const viewModel = formSchemaUtils.getViewModelById(viewModelId); return viewModel.states.map(state => convertToEditorVariable(state, pathPrefix)); } @@ -38,7 +36,7 @@ export function usePropertyEditor(designerHostService: DesignerHostService): Use /** * 获取PropertyEditor需要的变量数据 */ - function getVariables(viewModelId: string): any[] { + function getVariables(viewModelId: string): VariableItem[] { const rootViewModelId = formSchemaUtils.getRootViewModelId(); // 1、当前组件的组件变量 const currentViewModelVariables = getVariablesByViewModelId(viewModelId); @@ -62,5 +60,13 @@ export function usePropertyEditor(designerHostService: DesignerHostService): Use } - return { getVariables, getControlName }; + /** + * 获取PropertyEditor需要的状态机数据 + */ + function getStateMachines(): StateMachineItem[] { + const renderStates = formStateMachineUtils && formStateMachineUtils.getRenderStates(); + return renderStates || []; + } + + return { getVariables, getControlName, getStateMachines }; } \ No newline at end of file diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts index fdf7b5b3c7b..402132cce73 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-type.ts @@ -122,7 +122,7 @@ export function usePropertyType( // 2、属性值为对象结构,属性值的type为属性类型 const propertyTypefromObject = extractFromObjectType(propertyValue); - // 2、属性值为非对象结构,属性值的type为属性类型 + // 3、属性值为非对象结构,属性值的type为属性类型 const propertyTypefromNonObject = extractFromNonObjectType(propertyValue); return propertyTypefromObject || propertyTypefromNonObject || dfaultPropertyType; diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts index 3ad722aabce..904a95e9637 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-value.ts @@ -1,7 +1,7 @@ import { Ref, SetupContext, ref } from "vue"; import { PropertyEditorProps, PropertyType } from "../property-editor.props"; import { UsePropertyValue } from "./types"; -import { cloneDeep } from "lodash"; +import { cloneDeep } from "lodash-es"; export function usePropertyValue( props: PropertyEditorProps, @@ -40,5 +40,25 @@ export function usePropertyValue( } - return { triggerValueChange, getPropertyValue }; + /** + * 检查属性值是否有效 + * @param propertyType + * @returns + */ + function isPropertyValueValid(propertyType: PropertyType,propertyValue:any): boolean { + switch (propertyType) { + case 'Const': + return propertyValue !== undefined; + case 'Variable': + return propertyValue && propertyValue.field; + case 'Custom': + return propertyValue !== undefined; + case 'Expression': + return propertyValue && propertyValue.expressionInfo && propertyValue.expressionInfo.value; + case 'StateMachine': + return propertyValue && propertyValue.field;; + } + } + + return { triggerValueChange, getPropertyValue, isPropertyValueValid }; } diff --git a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx index de64ebd412d..27411089dba 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.component.tsx +++ b/packages/ui-vue/components/property-editor/src/property-editor.component.tsx @@ -43,7 +43,7 @@ export default defineComponent({ /** 右侧-属性值相关方法 */ const usePropertyValueComposition = usePropertyValue(props, context, currentPropertyType.value); - const { getPropertyValue, triggerValueChange } = usePropertyValueComposition; + const { getPropertyValue, triggerValueChange, isPropertyValueValid } = usePropertyValueComposition; /** 渲染右侧内容 */ const renderConst = getConstRender(props, context, usePropertyValueComposition); const renderVariable = getVariableRender(props, context, usePropertyValueComposition); @@ -63,7 +63,7 @@ export default defineComponent({ const propertyValue = getPropertyValue(currentPropertyType.value); // 2、如果属性值不为空,触发属性值变更 - if (propertyValue.value) { + if (isPropertyValueValid(currentPropertyType.value,propertyValue.value)) { triggerValueChange(propertyValue.value); } } diff --git a/packages/ui-vue/components/property-editor/src/property-editor.props.ts b/packages/ui-vue/components/property-editor/src/property-editor.props.ts index 31647b12c95..9ba44286bef 100644 --- a/packages/ui-vue/components/property-editor/src/property-editor.props.ts +++ b/packages/ui-vue/components/property-editor/src/property-editor.props.ts @@ -24,6 +24,7 @@ import { constPropertyProps } from './components/const/const-property.props'; import { variablePropertyProps } from './components/variable/variable-property.props'; import { stateMachinePropertyProps } from './components/state-machine/state-machine-property.props'; import { customPropertyProps } from './components/custom/custom-property.props'; +import { expressionPropertyProps } from './components/expression/expression-property.props'; export type PropertyType = 'Const' | 'Variable' | 'Custom' | 'StateMachine' | 'Expression'; @@ -32,6 +33,7 @@ export const propertyEditorProps = { ...variablePropertyProps, ...customPropertyProps, ...stateMachinePropertyProps, + ...expressionPropertyProps, id: { Type: String, default: '' }, modelValue: { type: [Number, String, Boolean, Object] }, diff --git a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json index 65a19971f75..f8e390c41fd 100644 --- a/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json +++ b/packages/ui-vue/components/property-editor/src/schema/property-editor.schema.json @@ -105,7 +105,12 @@ "description": "", "type": "Array", "default": [] - } + }, + "expressionConfig": { + "description": "", + "type": "Object", + "default": {} + } }, "required": [ "type" diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts index 3e7bb862a0f..b0d33867694 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts @@ -214,4 +214,70 @@ export class BaseControlProperty { } } + /** + * 更新表达式到expressions节点 + * @param changeObject + */ + public updateExpressionValue(changeObject: PropertyChangeObject) { + const newPropertyValue = changeObject.propertyValue; + const newValueType = newPropertyValue && newPropertyValue.type; + + // 1、判断是否需要更新表达式 + const needUpdateExpression = newValueType === 'Expression' && newPropertyValue.expressionInfo; + if (!needUpdateExpression) { + return; + } + + const { expressionId, expressionInfo } = newPropertyValue; + const { targetId, targetType, expressionType, value, message } = expressionInfo; + const module = this.formSchemaUtils.getModule(); + module.expressions ??= []; + const { expressions } = module; + + // 2、获取目标表达式,如果不存在,则创建一个空的目标表达式 + let targetExpression = expressions.find(expression => expression.target === targetId); + if (!targetExpression) { + targetExpression = { target: targetId, rules: [], targetType }; + expressions.push(targetExpression); + } + + // 3、更新表达式 + const expressionItem = targetExpression.rules.find(rule => rule.type === expressionType); + if (expressionItem) { + expressionItem.value = value; + expressionItem.message = message; + } else { + const newExpressionRule = { id: expressionId, type: expressionType, value, message }; + targetExpression.rules.push(newExpressionRule); + } + delete newPropertyValue.expressionInfo; + } + + /** + * 属性类型切换为非表达式后,清除原表达式 + * @param changeObject + * @param propertyData + * @returns + */ + clearExpression(changeObject: PropertyChangeObject, propertyData: any) { + const newPropertyValue = changeObject.propertyValue; + const isExpression = newPropertyValue && newPropertyValue.type === 'Expression'; + // 1、如果为当前属性为表达式,则不需要清空 + if (isExpression) { + return; + } + + // 2、属性值不是表达式后,需要清空表达式 + const expressionType = changeObject.propertyID; + const expressions = this.formSchemaUtils.getExpressions(); + + const targetId = propertyData.binding ? propertyData.binding.field : propertyData.id; + const targetExpression = expressions.find(expression => expression.target === targetId); + if (!targetExpression || !targetExpression.rules) { + return; + } + targetExpression.rules = targetExpression.rules.filter(rule => rule.type !== expressionType); + + } + } diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/expression-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/expression-property.ts index 99373ddbcae..8b045a7b203 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/expression-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/expression-property.ts @@ -172,7 +172,7 @@ export class ExpressionProperty { const rule = this.getExpressionRule(expressionId, expressionType); const entitiesAndVariables = this.getEntitiesAndVariables(); return { - message: expressionType === 'validate' && rule? rule.message : '', + message: ['validate','required'].includes(expressionType) && rule? rule.message : '', ...entitiesAndVariables }; } @@ -285,6 +285,19 @@ export class ExpressionProperty { }, {}); } + private getExpressionInfo(propertyData: any, targetType: 'Field' | 'Button' | 'Container', expressionType: string){ + const targetId = targetType === 'Field' ? propertyData.binding.field : propertyData.id; + const expressionRule = this.getExpressionRule(targetId, expressionType); + const expressionInfo = { + value: expressionRule && expressionRule.value, + message: expressionRule && expressionRule.message, + targetId, + targetType, + expressionType + } + return expressionInfo + } + getExpressionConfig(propertyData: any, type: 'Field'|'Button'|'Container', expressionTypes: string[] = ['compute', 'dependency', 'validate']) { return { description: "表达式", @@ -294,4 +307,16 @@ export class ExpressionProperty { } }; } + + getExpressionOptions(propertyData: any, targetType: 'Field' | 'Button' | 'Container', expressionType: string) { + const expressionInfo = this.getExpressionInfo(propertyData, targetType, expressionType); + return { + singleExpand: false, + showMessage: expressionType === 'require', + beforeOpen: () => { + return this.onBeforeOpenExpression(propertyData, expressionType, targetType); + }, + expressionInfo + }; + } } diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts index 43669b23014..6fae7d90dd4 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts @@ -44,7 +44,7 @@ export class InputBaseProperty extends BaseControlProperty { // 外观 this.propertyConfig.categories['appearance'] = this.getAppearanceProperties(propertyData, componentInstance); // 编辑器 - this.propertyConfig.categories['editor'] = this.getEditorProperties(propertyData); + this.propertyConfig.categories['editor'] = this.getEditorProperties(propertyData); // 表达式编辑器 this.propertyConfig.categories['expressons'] = this.getExpressionConfig(propertyData, 'Field'); // 事件 @@ -328,7 +328,7 @@ export class InputBaseProperty extends BaseControlProperty { $converter: "/converter/property-editor.converter" }, info); - const { getVariables, getControlName } = usePropertyEditor(this.designerHostService) + const { getVariables, getControlName, getStateMachines } = usePropertyEditor(this.designerHostService) const editorProperties = { readonly: { @@ -336,15 +336,15 @@ export class InputBaseProperty extends BaseControlProperty { title: "只读", editor: { type: "property-editor", - propertyTypes: ['Const', 'Variable', 'Custom', 'StateMachine'], + propertyTypes: ['Const', 'Variable', 'Custom', 'StateMachine', 'Expression'], constType: 'enum', constEnums: [{ id: true, name: '是' }, { id: false, name: '否' }], controlName: getControlName(propertyData), newVariablePrefix: 'is', newVariableType: 'Boolean', variables: getVariables(this.viewModelId), - stateMachines: [ - ] + stateMachines: getStateMachines(), + expressionConfig: this.getExpressionOptions(propertyData, 'Field', 'readonly') } }, disabled: { @@ -369,8 +369,10 @@ export class InputBaseProperty extends BaseControlProperty { editorProperties[key] = Object.assign(editorProperties[key] || {}, properties[key]); } if (!setPropertyRelates) { - setPropertyRelates = (changeObject) => { + setPropertyRelates = (changeObject, propertyData) => { this.addNewVariableToViewModel(changeObject, this.viewModelId); + this.updateExpressionValue(changeObject) + this.clearExpression(changeObject, propertyData); } } @@ -612,4 +614,8 @@ export class InputBaseProperty extends BaseControlProperty { getExpressionConfig(propertyData: any, type: 'Field' | 'Button' | 'Container') { return new ExpressionProperty(this.formSchemaUtils).getExpressionConfig(propertyData, type); } -} + + getExpressionOptions(propertyData: any, targetType: 'Field' | 'Button' | 'Container', expressionType: string) { + return new ExpressionProperty(this.formSchemaUtils).getExpressionOptions(propertyData, targetType, expressionType); + } +} \ No newline at end of file -- Gitee From 230582ea13f7cd221e330a66f03ccde80e4cf34c Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 24 Mar 2025 09:07:40 +0800 Subject: [PATCH 24/34] =?UTF-8?q?chore:=20=20=E5=AE=8C=E5=96=84property-ed?= =?UTF-8?q?itor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/composition/entity/base-property.ts | 44 ++++--------------- 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts index aa8e906bde1..5424928700d 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts @@ -5,6 +5,7 @@ import { refreshCanvas } from "../../../../designer-canvas/src/composition/updat import { canvasChanged } from "../../../../designer-canvas/src/composition/designer-canvas-changed"; import { PropertyChangeObject } from "./property-entity"; import { usePropertyEditor } from "../../../../property-editor/src/composition/use-property-editor"; +import { ExpressionProperty } from "./expression-property"; /** * 控件属性基类 @@ -123,7 +124,7 @@ export class BaseControlProperty { }; } protected getPropertyEditorParams(propertyData, propertyTypes:any = []) { - const { getVariables, getControlName } = usePropertyEditor(this.designerHostService); + const { getVariables, getControlName, getStateMachines } = usePropertyEditor(this.designerHostService); return { type: "property-editor", propertyTypes: propertyTypes && propertyTypes.length > 0 ? propertyTypes : ['Const', 'Variable', 'Custom', 'StateMachine'], @@ -133,41 +134,8 @@ export class BaseControlProperty { newVariablePrefix: 'is', newVariableType: 'Boolean', variables: getVariables(this.viewModelId), - // 先预置数据,待多值编辑器完善后替换 - stateMachines: [ - { - "id": "canRemove", - "name": "删除" - }, - { - "id": "editable", - "name": "可编辑" - }, - { - "id": "canEdit", - "name": "编辑" - }, - { - "id": "canRemoveDetail", - "name": "删除明细" - }, - { - "id": "canAdd", - "name": "新增" - }, - { - "id": "canSave", - "name": "保存" - }, - { - "id": "canCancel", - "name": "取消" - }, - { - "id": "canAddDetail", - "name": "新增明细" - } - ] + stateMachines: getStateMachines(), + expressionConfig: this.getExpressionOptions(propertyData, 'Field', 'readonly') } } protected getVisibleProperty(propertyData, position = '') { @@ -336,4 +304,8 @@ export class BaseControlProperty { } + getExpressionOptions(propertyData: any, targetType: 'Field' | 'Button' | 'Container', expressionType: string) { + return new ExpressionProperty(this.formSchemaUtils).getExpressionOptions(propertyData, targetType, expressionType); + } + } -- Gitee From daf7b5138c2a9dced7c49ab48cd09e865555d7d1 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 24 Mar 2025 09:38:25 +0800 Subject: [PATCH 25/34] =?UTF-8?q?chore:=20=20=E4=BB=A3=E7=A0=81=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expression/expression-property.component.tsx | 8 ++++++++ .../src/composition/entity/base-property.ts | 2 +- .../src/composition/entity/input-base-property.ts | 8 -------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx index b799d0fcc44..2bd7d6707a5 100644 --- a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx @@ -49,6 +49,13 @@ export default function ( expressionValue.value.expressionInfo.message = message; triggerValueChange(expressionValue.value); } + function beforeSubmit({ expression, notifyService }) { + if (expression) { + return true; + } + notifyService.warning('请先配置表达式'); + return false; + } return () => { return ( @@ -59,6 +66,7 @@ export default function ( validateMessage={expressionMessage.value} enableClear={false} readonly={readOnly.value} + beforeSubmit={beforeSubmit} onSubmitModal={onSubmitModal} >
diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts index 5424928700d..54da6089ccc 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts @@ -127,7 +127,7 @@ export class BaseControlProperty { const { getVariables, getControlName, getStateMachines } = usePropertyEditor(this.designerHostService); return { type: "property-editor", - propertyTypes: propertyTypes && propertyTypes.length > 0 ? propertyTypes : ['Const', 'Variable', 'Custom', 'StateMachine'], + propertyTypes: propertyTypes && propertyTypes.length > 0 ? propertyTypes : ['Const', 'Variable', 'Custom', 'StateMachine', 'Expression'], constType: 'enum', constEnums: [{ id: true, name: '是' }, { id: false, name: '否' }], controlName: getControlName(propertyData), diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts index ec547b3a497..c2922c3c8cd 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/input-base-property.ts @@ -41,14 +41,6 @@ export class InputBaseProperty extends BaseControlProperty { } public getGridFieldEdtiorPropConfig(propertyData: any, componentInstance: DesignerComponentInstance) { this.propertyConfig.categories = {}; - // 基本信息 - this.propertyConfig.categories['basic'] = this.getBasicProperties(propertyData, componentInstance); - // 外观 - this.propertyConfig.categories['appearance'] = this.getAppearanceProperties(propertyData, componentInstance); - // 编辑器 - this.propertyConfig.categories['editor'] = this.getEditorProperties(propertyData); - // 表达式编辑器 - this.propertyConfig.categories['expressons'] = this.getExpressionConfig(propertyData, 'Field'); this.getCommonPropertyConfig(propertyData,componentInstance); // 事件 this.propertyConfig.categories['eventsEditor'] = this.getEventPropertyConfig(propertyData, 'gridFieldEditor'); -- Gitee From a171d25eae004c347f556bf5ee86556429d6d4a7 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 24 Mar 2025 15:22:38 +0800 Subject: [PATCH 26/34] =?UTF-8?q?chore:=20property-editor=E9=9B=86?= =?UTF-8?q?=E6=88=90=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/composition/use-expression.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/ui-vue/components/property-editor/src/composition/use-expression.ts b/packages/ui-vue/components/property-editor/src/composition/use-expression.ts index c4dee062f96..8a41cb88c2f 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-expression.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-expression.ts @@ -1,6 +1,6 @@ import { Ref, SetupContext, ref } from "vue"; import { PropertyEditorProps } from "../property-editor.props"; -import { ExpressionValue, UseExpression, UsePropertyValue } from "./types"; +import { ExpressionInfo, ExpressionValue, UseExpression, UsePropertyValue } from "./types"; export function useExpression( props: PropertyEditorProps, @@ -10,8 +10,9 @@ export function useExpression( const { getPropertyValue } = usePropertyValueComposition; const expressionType = props.id; - const { expressionConfig } = props; - const { targetId } = expressionConfig && expressionConfig.expressionInfo; + const { expressionConfig = {} } = props; + const { expressionInfo = { value: '', message: '', targetId: '', targetType: '', expressionType: '' } } = expressionConfig; + const { targetId } = expressionInfo; /** * 生成表达式内码 @@ -22,14 +23,14 @@ export function useExpression( } /** - * 生成有个空的表达式值 + * 生成一个空的表达式值 * @returns */ function generateExpressionValue(): ExpressionValue { return { type: 'Expression', expressionId: generateExpressionId(), - expressionInfo: expressionConfig.expressionInfo + expressionInfo: expressionInfo } } @@ -45,7 +46,7 @@ export function useExpression( } // 2、记录expressionInfo的值 - propertyValue.value.expressionInfo = expressionConfig.expressionInfo; + propertyValue.value.expressionInfo = expressionInfo; return propertyValue; } -- Gitee From 3e8d026a9a89a05d9ee57c2dc7835ec1ee24297d Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Mon, 24 Mar 2025 15:55:00 +0800 Subject: [PATCH 27/34] =?UTF-8?q?chore:=20propertyEditor=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=8E=A7=E4=BB=B6=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/composition/use-property-editor.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts b/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts index 66043c05fbb..5a563fb65fa 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-property-editor.ts @@ -15,20 +15,20 @@ export function usePropertyEditor(designerHostService: DesignerHostService): Use * @param variable * @returns */ - function convertToEditorVariable(variable: FormVariable, pathPrefix: string = ''):VariableItem { + function convertToEditorVariable(variable: FormVariable, pathPrefix: string = ''): VariableItem { return { path: pathPrefix + variable.code, field: variable.id, fullPath: variable.code }; } - + /** * 获取视图模型上的变量 * @param viewModelId * @returns */ - function getVariablesByViewModelId(viewModelId: string, pathPrefix: string = ''):VariableItem[] { + function getVariablesByViewModelId(viewModelId: string, pathPrefix: string = ''): VariableItem[] { const viewModel = formSchemaUtils.getViewModelById(viewModelId); return viewModel.states.map(state => convertToEditorVariable(state, pathPrefix)); } @@ -55,9 +55,8 @@ export function usePropertyEditor(designerHostService: DesignerHostService): Use * @returns */ function getControlName(propertyData: any): string { - const bindingPath = propertyData && propertyData.binding && propertyData.binding.path; - return bindingPath || ''; - + const controlName = propertyData.binding && propertyData.binding.path || propertyData.id || ''; + return controlName; } /** -- Gitee From 135aab66a6b068017c3d27cf4effaa117e4e5430 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 25 Mar 2025 10:31:37 +0800 Subject: [PATCH 28/34] =?UTF-8?q?chore:=20=E7=BB=B4=E6=8A=A4=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=8A=9F=E8=83=BD=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../use-array-and-object-editor.tsx | 4 +- .../composition/use-variable-data.ts | 41 +++++++++++++++++-- .../default-value-column-formatter.tsx | 17 +++++++- .../variable-manager.component.tsx | 8 ++-- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-array-and-object-editor.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-array-and-object-editor.tsx index b84fb3fde5d..232db07c30f 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-array-and-object-editor.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-array-and-object-editor.tsx @@ -14,7 +14,7 @@ export function useArrayAndObjectEditor() { function renderEditor(value: any): () => JSX.Element { return () => { return ( - + ); }; } @@ -27,6 +27,8 @@ export function useArrayAndObjectEditor() { function showArrayAndObjectEditor(value: any, confirmHandler: (newValue: any) => boolean) { const monacoEditorModal = modalService?.open({ fitContent: false, + enableEsc: true, + draggable: true, width: 840, height: 445, title: '默认值编辑器', diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts index 093f1b0f39d..1744778736e 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -4,6 +4,7 @@ import { useVariableDefaultValue } from "./use-variable-default-value"; import { FNotifyService } from "@farris/ui-vue/components"; import { IdService } from "../../method-manager/service/id.service"; import { useViewModelName } from '../../method-manager/composition/use-view-model-name'; +import { cloneDeep } from "lodash-es"; export function useVariableData(gridComponentInstance: Ref) { @@ -138,6 +139,38 @@ export function useVariableData(gridComponentInstance: Ref) { return true; } + function checkBeforeEndEditCell(data: any): boolean { + const currentEditingCell = data && data.cell; + if (!currentEditingCell) { + return true; + } + + const { field, editingData } = currentEditingCell; + const newValue = editingData.trim(); + + // 1、编辑编号和名称列时,需要校验是否为空 + if (field === 'code' || field === 'name') { + if (!newValue) { + return false; + } + } + + // 2、编辑编号列时,需要校验编号是否重复 + if (field === 'code') { + const newVariable = cloneDeep(data.row.raw); + newVariable.code = newValue; + return checkUniqueCode(newVariable); + } + + // 3、编辑默认值列时,打开数组和对象编辑器时,不允许结束编辑 + if (field === 'value') { + const canNotEndEdit = document.getElementById('variable-array-and-object-editor'); + return !canNotEndEdit; + } + + return true; + } + /** * 从视图模型中删除变量 * @param variable @@ -155,7 +188,7 @@ export function useVariableData(gridComponentInstance: Ref) { * @returns */ function deleteVariables() { - const variablesToBeDeleted = gridComponentInstance.value.getSelectedItems(); + let variablesToBeDeleted = gridComponentInstance.value.getSelectedItems(); // 1、要删除的变量不能为空 if (!variablesToBeDeleted || !variablesToBeDeleted.length) { notifyService.info('请勾选要删除的行'); @@ -168,6 +201,7 @@ export function useVariableData(gridComponentInstance: Ref) { } // 3、从视图模型中删除变量 + variablesToBeDeleted = variablesToBeDeleted.filter(variableToBeDeleted => variableToBeDeleted.category === FormVariableCategory.locale); variablesToBeDeleted.forEach(variableToBeDeleted => { variableList.value = variableList.value.filter(variable => variable.id !== variableToBeDeleted.id); deleteVariableFromViewModel(variableToBeDeleted); @@ -207,7 +241,7 @@ export function useVariableData(gridComponentInstance: Ref) { } const variableCode = variable.code && variable.code.trim(); const variableName = variable.name && variable.name.trim(); - + // 2、变量编号、名称、类型不能为空 if (!variableCode || !variableName || !variable.type) { return false; @@ -335,6 +369,7 @@ export function useVariableData(gridComponentInstance: Ref) { deleteVariables, addVariableToDataGrid, updateVariableToViewModel, - refreshRemoteVariables + refreshRemoteVariables, + checkBeforeEndEditCell }; } diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx index 0215e637d80..22faed2eb77 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/formatters/default-value-column-formatter.tsx @@ -7,11 +7,24 @@ import { JSX } from "vue/jsx-runtime"; */ export default function defaultValueColumnFormatter(visualDataCell: VisualDataCell, visualDataRow: VisualData): () => JSX.Element { const { data } = visualDataCell; - const displayText = data; + + /** + * 格式化单元格数据 + * @returns + */ + function formatCellData(data: any): string { + let displayText = data; + // 1、如果默认值为布尔值,则转换为字符串 + if (typeof displayText === 'boolean') { + displayText = displayText + ""; + } + + return displayText; + } return (
- {displayText} + {formatCellData(data)}
); diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index 923982799a3..9164eebddd8 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -32,7 +32,7 @@ export default defineComponent({ /** 变量默认值相关方法 */ const { clearDefaultValueWhenModifyType } = useVariableDefaultValue(); /** 变量数据相关方法 */ - const { variableList, loadVariables, deleteVariables, addVariableToDataGrid, updateVariableToViewModel, refreshRemoteVariables } = useVariableData(gridComponentInstance); + const { variableList, loadVariables, deleteVariables, addVariableToDataGrid, updateVariableToViewModel, refreshRemoteVariables, checkBeforeEndEditCell } = useVariableData(gridComponentInstance); loadVariables(); /** @@ -79,11 +79,11 @@ export default defineComponent({ /** * 单元格结束编辑前事件, 用于检查输入内容是否合法 - * @param cell + * @param data * @returns */ - function onBeforeEndEditCell(cell: any): boolean { - return true; + function onBeforeEndEditCell(data: any): boolean { + return checkBeforeEndEditCell(data); } /** -- Gitee From d7f6e98770420893333aece8a9a951fa0e425364 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 25 Mar 2025 10:33:49 +0800 Subject: [PATCH 29/34] =?UTF-8?q?chore:=20=E5=B1=8F=E8=94=BD=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=A0=B7=E5=BC=8F=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/form-designer/form-designer.component.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/components/components/form-designer/form-designer.component.tsx b/packages/designer/src/components/components/form-designer/form-designer.component.tsx index 96bd49bda4f..1950679adc5 100644 --- a/packages/designer/src/components/components/form-designer/form-designer.component.tsx +++ b/packages/designer/src/components/components/form-designer/form-designer.component.tsx @@ -229,8 +229,8 @@ export default defineComponent({ class={formDesignerViewClass.value}>可视化设计器
onChangeDesignerView('formDesignerCode')} class={formDesignerCodeViewClass.value}>设计时代码
-
onChangeDesignerView('customClassEditor')} - class={customClassEditorClass.value}>自定义样式
+ {/*
onChangeDesignerView('customClassEditor')} + class={customClassEditorClass.value}>自定义样式
*/} -- Gitee From 8bcbf6a4a0863d06a6e1e1d26e21538becc28869 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Tue, 25 Mar 2025 21:59:25 +0800 Subject: [PATCH 30/34] =?UTF-8?q?chore:=20property-editor=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/expression/expression-property.component.tsx | 6 +++--- .../state-machine/state-machine-property.component.tsx | 2 +- .../property-panel/src/composition/entity/base-property.ts | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx index 2bd7d6707a5..3429c676ff8 100644 --- a/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/expression/expression-property.component.tsx @@ -49,11 +49,11 @@ export default function ( expressionValue.value.expressionInfo.message = message; triggerValueChange(expressionValue.value); } - function beforeSubmit({ expression, notifyService }) { - if (expression) { + function beforeSubmit({ expressionValue, notifyService }) { + if (expressionValue) { return true; } - notifyService.warning('请先配置表达式'); + notifyService.warning({ message: '请先配置表达式', position: 'top-center' }); return false; } diff --git a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx index 9db1949e968..fbacd752008 100644 --- a/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx +++ b/packages/ui-vue/components/property-editor/src/components/state-machine/state-machine-property.component.tsx @@ -70,7 +70,7 @@ export default function ( return (
- {status.value ? '是' : '否'} + {status.value ? '是' : '非'}
); } diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts index a30803ddbd8..03c0c49e235 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts @@ -185,12 +185,16 @@ export class BaseControlProperty { // 合并属性,保留原属性值 behaviorPoperties[key] = Object.assign(behaviorPoperties[key] || {}, properties[key]); } + const self= this; return { ...behaviorBasic, properties: { ...behaviorPoperties }, setPropertyRelates(changeObject, parameters: any) { if (!changeObject) { return; } + self.addNewVariableToViewModel(changeObject, this.viewModelId); + self.updateExpressionValue(changeObject) + self.clearExpression(changeObject, propertyData); if (setPropertyRelates) { setPropertyRelates(changeObject, parameters); } -- Gitee From 0581973f30d264ed856075d5984dd959d93a504f Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Wed, 26 Mar 2025 11:36:42 +0800 Subject: [PATCH 31/34] =?UTF-8?q?chore:=20=E5=8F=98=E9=87=8F=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../variable-manager/composition/use-variable-data.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts index 1744778736e..7dee3f78f0c 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/composition/use-variable-data.ts @@ -146,10 +146,10 @@ export function useVariableData(gridComponentInstance: Ref) { } const { field, editingData } = currentEditingCell; - const newValue = editingData.trim(); // 1、编辑编号和名称列时,需要校验是否为空 if (field === 'code' || field === 'name') { + const newValue = editingData.trim(); if (!newValue) { return false; } @@ -157,6 +157,7 @@ export function useVariableData(gridComponentInstance: Ref) { // 2、编辑编号列时,需要校验编号是否重复 if (field === 'code') { + const newValue = editingData.trim(); const newVariable = cloneDeep(data.row.raw); newVariable.code = newValue; return checkUniqueCode(newVariable); -- Gitee From d3c3b81f45738f427fd2ffe962c1553015b2c101 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Wed, 26 Mar 2025 16:58:54 +0800 Subject: [PATCH 32/34] =?UTF-8?q?chore:=20=E8=BF=98=E5=8E=9F=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../property-panel/src/composition/entity/base-property.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts index 03c0c49e235..a30803ddbd8 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts @@ -185,16 +185,12 @@ export class BaseControlProperty { // 合并属性,保留原属性值 behaviorPoperties[key] = Object.assign(behaviorPoperties[key] || {}, properties[key]); } - const self= this; return { ...behaviorBasic, properties: { ...behaviorPoperties }, setPropertyRelates(changeObject, parameters: any) { if (!changeObject) { return; } - self.addNewVariableToViewModel(changeObject, this.viewModelId); - self.updateExpressionValue(changeObject) - self.clearExpression(changeObject, propertyData); if (setPropertyRelates) { setPropertyRelates(changeObject, parameters); } -- Gitee From 3aefe6f891efad518efd8e167ac3c75d99a40988 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Fri, 28 Mar 2025 09:03:56 +0800 Subject: [PATCH 33/34] =?UTF-8?q?feature:=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=9A=90=E8=97=8F=E5=8C=BA=E5=9F=9F=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designer-canvas/src/components/maps.ts | 2 + .../src/composition/dg-control.ts | 5 +- .../src/designer-canvas.component.tsx | 13 ++ .../designer-hidden-area.css | 127 ++++++++++++++++++ .../components/designer-hidden-area/index.ts | 31 +++++ .../hidden-component-selector.component.tsx | 78 +++++++++++ .../hidden-component-selector.props.ts | 13 ++ .../hidden-component-template.component.tsx | 44 ++++++ .../hidden-component-container.component.tsx | 107 +++++++++++++++ .../hidden-component.component.tsx | 105 +++++++++++++++ .../hidden-component.props.ts | 16 +++ .../src/composition/drag-resolve.tsx | 85 ++++++++++++ .../src/composition/types.ts | 16 +++ .../src/composition/use-designer-rules.ts | 36 +++++ .../composition/use-hidden-area-dragula.ts | 69 ++++++++++ .../src/composition/use-hidden-component.ts | 52 +++++++ .../src/designer-hidden-area.component.tsx | 55 ++++++++ .../src/designer-hidden-area.props.ts | 8 ++ .../hidden-component.property-config.ts | 16 +++ .../src/schema/hidden-component.schema.json | 32 +++++ .../src/schema/schema-mapper.ts | 4 + .../src/schema/schema-resolver.ts | 6 + packages/ui-vue/components/designer.ts | 1 + 23 files changed, 920 insertions(+), 1 deletion(-) create mode 100644 packages/ui-vue/components/designer-hidden-area/designer-hidden-area.css create mode 100644 packages/ui-vue/components/designer-hidden-area/index.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.component.tsx create mode 100644 packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.props.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-template/hidden-component-template.component.tsx create mode 100644 packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component-container.component.tsx create mode 100644 packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.component.tsx create mode 100644 packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.props.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/composition/drag-resolve.tsx create mode 100644 packages/ui-vue/components/designer-hidden-area/src/composition/types.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/composition/use-designer-rules.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-area-dragula.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-component.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.component.tsx create mode 100644 packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.props.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/property-config/hidden-component.property-config.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/schema/hidden-component.schema.json create mode 100644 packages/ui-vue/components/designer-hidden-area/src/schema/schema-mapper.ts create mode 100644 packages/ui-vue/components/designer-hidden-area/src/schema/schema-resolver.ts diff --git a/packages/ui-vue/components/designer-canvas/src/components/maps.ts b/packages/ui-vue/components/designer-canvas/src/components/maps.ts index 8124dd0a400..8622f452950 100644 --- a/packages/ui-vue/components/designer-canvas/src/components/maps.ts +++ b/packages/ui-vue/components/designer-canvas/src/components/maps.ts @@ -57,6 +57,7 @@ import FTreeGrid from '@farris/ui-vue/components/tree-grid'; import FFieldset from '@farris/ui-vue/components/fieldset'; import FDrawer from '@farris/ui-vue/components/drawer'; import FHtmlTemplate from '@farris/ui-vue/components/html-template'; +import FDesignerHiddenArea from '@farris/ui-vue/components/designer-hidden-area'; const componentMap: Record = {}; const componentPropsConverter: Record = {}; @@ -130,6 +131,7 @@ function loadDesignerRegister() { FFieldset.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); FDrawer.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); FHtmlTemplate.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); + FDesignerHiddenArea.registerDesigner(componentMap, componentPropsConverter, componentPropertyConfigConverter); } } diff --git a/packages/ui-vue/components/designer-canvas/src/composition/dg-control.ts b/packages/ui-vue/components/designer-canvas/src/composition/dg-control.ts index 853950e6426..816e428eff2 100644 --- a/packages/ui-vue/components/designer-canvas/src/composition/dg-control.ts +++ b/packages/ui-vue/components/designer-canvas/src/composition/dg-control.ts @@ -83,5 +83,8 @@ export const DgControl = { 'external-container': { type: 'external-container', name: '外部容器', icon: 'content-container' }, - 'list-nav': { type: 'list-nav', name: '列表导航' } + 'list-nav': { type: 'list-nav', name: '列表导航' }, + + 'hidden-component': { type: 'hidden-component', name: '隐藏组件' } + }; diff --git a/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx b/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx index f51372a3c5f..d92ebf1a1f7 100644 --- a/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx +++ b/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx @@ -11,6 +11,7 @@ import './composition/class/control.css'; import { loadDesignerRegister } from './components/maps'; import { F_MODAL_SERVICE_TOKEN } from '../../modal'; import { canvasKey, refreshCanvas } from './composition/update-cancas'; +import { FDesignerHiddenArea } from '@farris/ui-vue/components/designer-hidden-area'; export default defineComponent({ name: 'FDesignerCanvas', @@ -99,6 +100,17 @@ export default defineComponent({ setPositionOfButtonGroupInContainer(designerCanvasContainerElementRef.value); }); } + + /** + * 选择HiddenComponent后,触发属性面板更新 + * @param schemaValue + * @param componentInstance + */ + function onSelectHiddenComponent(schemaValue: ComponentSchema, componentInstance) { + const schemaType = schemaValue.type; + context.emit('selectionChange', schemaType, schemaValue, '', componentInstance); + } + onMounted(() => { if (designerCanvasElementRef.value) { useDragulaComposition.initializeDragula(designerCanvasElementRef.value); @@ -123,6 +135,7 @@ export default defineComponent({
{schema.value && } + {/* {schema.value && } */}
diff --git a/packages/ui-vue/components/designer-hidden-area/designer-hidden-area.css b/packages/ui-vue/components/designer-hidden-area/designer-hidden-area.css new file mode 100644 index 00000000000..0061975a696 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/designer-hidden-area.css @@ -0,0 +1,127 @@ +/* 主内容 */ +.f-designer-hidden-area-container { + z-index: 999; +} + +.f-designer-hidden-area-main-content { + display: flex; + height: 400px; + background: #F8FAFC; + border-radius: 10px 10px 0px 0px; + box-shadow: 0px -10px 10px -10px rgba(215, 223, 244, 1); +} + +.f-designer-hidden-area-top-bar-container { + display: flex; + justify-content: flex-end; + margin-right: 30px; +} + +/* 右侧模板 */ +.f-designer-hidden-area-template-container { + background: white; + margin: 10px 10px 10px 0px; + width: 15%; + display: flex; + flex-direction: column; + align-items: center; + border-radius: 6px; +} + +.f-designer-hidden-area-usual-template-text { + width: 65px; + height: 26px; + background: #F0F3F9; + border-radius: 0px 0px 12px 12px; + text-align: center; + color: #8DA3CE; +} + +.f-designer-hidden-area-template-box-container { + width: 140px; + height: 140px; + border: 1px solid #EBEBEB; + border-radius: 4px; + margin-top: 10px; +} + +.f-designer-hidden-area-template-img-container { + width: 138px; + height: 109px; +} + +.f-designer-hidden-area-template-text-container { + height: 28px; + box-shadow: rgb(215, 223, 244) 0px -10px 10px -10px; + background: rgb(248, 250, 251); + display: flex; + align-items: center; + padding-left: 5px; +} + +/* 左侧HiddenComponent */ +.f-designer-hidden-area-component { + display: inline-block; + margin: 10px 0px 0px 10px; +} + +.f-designer-hidden-area-component-container { + display: flex; + margin: 10px; + width: 85%; + border-radius: 6px; +} + +.f-designer-hidden-area-component-list-container { + display: flex; + flex: 1; + border-radius: 6px; + box-shadow: rgba(91, 163, 255, 0.1) 0px 0px 8px 0px; + flex-wrap: wrap; + overflow: auto; +} + +.f-designer-hidden-area-component-white-background { + background-color: white; +} + +.hidden-area-drag-over:not(.no-drop) { + background-color: #f3f8ff !important; + border: 0.8px dashed #388fff !important; +} + +.f-designer-hidden-area-form-box-container { + width: 140px; + height: 140px; + border: 1px solid #EBEBEB; + border-radius: 4px; +} + +.f-designer-hidden-area-form-box-selected { + border: 2px solid #388fff !important; +} + +.f-designer-hidden-area-empty-container { + display: flex; + flex: 1; + box-shadow: rgba(91, 163, 255, 0.1) 0px 0px 8px 0px; + border-radius: 6px; + display: flex; + justify-content: center; + align-items: center; +} + +.f-designer-hidden-area-empty-container-border { + border: 0.8px dashed rgb(143, 157, 176); +} + +.f-designer-hidden-area-empty-drap-text { + width: 140px; + height: 20px; + opacity: 0.55; + font-family: PingFangSC-Regular; + font-size: 14px; + color: #3F4764; + text-align: center; + font-weight: 400; +} \ No newline at end of file diff --git a/packages/ui-vue/components/designer-hidden-area/index.ts b/packages/ui-vue/components/designer-hidden-area/index.ts new file mode 100644 index 00000000000..e7e98c71655 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/index.ts @@ -0,0 +1,31 @@ +/** + * 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 type { App } from 'vue'; +import FDesignerHiddenArea from './src/designer-hidden-area.component'; +import FHiddenComponent from './src/components/hidden-component/hidden-component.component'; +import { propsResolver } from './src/components/hidden-component/hidden-component.props'; + +export { FDesignerHiddenArea }; + +export default { + install(app: App): void { + app.component(FDesignerHiddenArea.name as string, FDesignerHiddenArea); + }, + registerDesigner(componentMap: Record, propsResolverMap: Record, configResolverMap: Record): void { + componentMap['hidden-component'] = FHiddenComponent; + propsResolverMap['hidden-component'] = propsResolver; + } +}; diff --git a/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.component.tsx b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.component.tsx new file mode 100644 index 00000000000..2658935ef9e --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.component.tsx @@ -0,0 +1,78 @@ +import { computed, defineComponent, Ref, ref } from "vue"; +import { FNotifyService } from "@farris/ui-vue/components/notify"; +import { FSchemaSelector, SchemaItem } from "@farris/ui-vue/components/schema-selector"; +import { FormSchemaRepositorySymbol } from '../../../../common'; +import { hiddenComponentSelectorProps, HiddenComponentSelectorProps } from "./hidden-component-selector.props"; +import { LookupSchemaRepositoryToken } from "@farris/ui-vue/components/lookup"; + +export default defineComponent({ + name: 'FHiddenComponentSelector', + props: hiddenComponentSelectorProps, + emits: ['close', 'submit'], + setup(props: HiddenComponentSelectorProps, context) { + const selectedComponent: Ref = ref(); + const { hiddenComponentType, designerHostService } = props; + const notifyService = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + + const formBasicInfo = designerHostService.formSchemaUtils.getFormMetadataBasicInfo(); + const editorParams = { formBasicInfo }; + const viewOptions = [ + { id: 'recommend', title: '推荐', type: 'Card', dataSource: 'Recommand', pagination: false }, + { id: 'total', title: '全部', type: 'Card', dataSource: 'Total', pagination: false } + ]; + const injectSymbolToken = computed(() => { + return hiddenComponentType === 'Popup' ? FormSchemaRepositorySymbol : LookupSchemaRepositoryToken; + }) + + /** + * 选择HiddenComponent + * @param $event + */ + function onSelectionChange($event) { + if (hiddenComponentType === 'Help') { + selectedComponent.value = $event[0].data; + } else { + selectedComponent.value = $event[0]; + } + } + + /** + * 校验HiddenComponent + * @returns + */ + async function validate() { + if (!selectedComponent.value) { + notifyService.warning('请选择表单'); + return false; + } + return true; + } + + function onSubmit() { + context.emit('submit', selectedComponent.value); + } + + function onCancel() { + context.emit('close'); + } + + return () => { + return ( + + + ) + } + } + +}) diff --git a/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.props.ts b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.props.ts new file mode 100644 index 00000000000..69af9e460e1 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-selector/hidden-component-selector.props.ts @@ -0,0 +1,13 @@ +import { ExtractPropTypes, PropType } from "vue"; +import { HiddenComponentType } from "../../composition/types"; + +export const hiddenComponentSelectorProps = { + id: { type: String, default: '' }, + modelValue: { type: Object }, + designerHostService: { type: String, Object: {} }, + hiddenComponentType: { type: String as PropType, default: 'Popup' }, + +} as Record; + +export type HiddenComponentSelectorProps = ExtractPropTypes; + diff --git a/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-template/hidden-component-template.component.tsx b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-template/hidden-component-template.component.tsx new file mode 100644 index 00000000000..a06b30e34ae --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component-template/hidden-component-template.component.tsx @@ -0,0 +1,44 @@ +import { ref } from "vue"; + +export default function () { + const templates = ref([ + { + code: 'Popup', + name: '弹窗', + imagePath: './image/弹窗.png', + + }, { + code: 'Help', + name: '帮助', + imagePath: './image/帮助.png', + }, + ]); + + function renderTemplate(template: { code: string, name: string, imagePath: string }) { + const { code, name, imagePath } = template; + return ( +
+
+
+ +
+
+
{name}
+
+
+
+ ); + } + + return () => { + return ( +
+
常用模板
+
+ {templates.value.map(renderTemplate)} +
+
+ ) + } +} diff --git a/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component-container.component.tsx b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component-container.component.tsx new file mode 100644 index 00000000000..0daf3db2824 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component-container.component.tsx @@ -0,0 +1,107 @@ +import { computed, inject, onMounted, Ref, ref, SetupContext } from "vue"; +import { useHiddenAreaDragula } from "../../composition/use-hidden-area-dragula"; +import { DesignerHiddenAreaProps } from "../../designer-hidden-area.props"; +import { DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import FHiddenComponent from './hidden-component.component'; +import useHiddenComponent from "../../composition/use-hidden-component"; +import { HiddenComponentSchema } from "../../composition/types"; + +export default function ( + props: DesignerHiddenAreaProps, + context: SetupContext, +) { + /** HiddenComponent的容器 */ + const componentContainerRef = ref(); + /** 选中组件的内码 */ + const selectedComponentId: Ref = ref(); + const designerHostService = inject('designer-host-service') as DesignerHostService; + const hiddenComponentComposition = useHiddenComponent(designerHostService); + /** 拖拽相关方法 */ + const { initDragula, attachToDragulaContainer } = useHiddenAreaDragula(designerHostService, hiddenComponentComposition); + + const module = designerHostService.formSchemaUtils.getModule(); + module.hiddenComponents ??= []; + const hiddenComponents = ref(module.hiddenComponents); + /** 存在HiddenComponents */ + const hasHiddenComponents = computed(() => { + return hiddenComponents.value.length > 0; + }) + /** HiddenComponent是否选中 */ + const isSelected = computed(() => { + return (hiddenComponentSchema: HiddenComponentSchema) => hiddenComponentSchema.id === selectedComponentId.value; + }) + + /** + * 点击HiddenComponent + * @param selectedComponent + * @param componentInstance + */ + function onClick(selectedComponent: HiddenComponentSchema, componentInstance: any) { + selectedComponentId.value = selectedComponent.id; + context.emit('selectionChange', selectedComponent, componentInstance); + } + + /** + * 删除HiddenComponent + * @param component + */ + function onDelete(hiddenComponentSchema: HiddenComponentSchema) { + hiddenComponentComposition.deleteComponent(hiddenComponentSchema); + } + + onMounted(() => { + initDragula(componentContainerRef.value); + attachToDragulaContainer(); + }) + + /** + * 渲染HiddenComponent + * @returns + */ + function renderComponent(hiddenComponentSchema: HiddenComponentSchema) { + return ( + + + ) + } + + /** + * 渲染HiddenComponent所在的容器 + * @returns + */ + function renderComponentContainer() { + return ( +
+ {hiddenComponents.value.map(renderComponent)} +
+ ) + } + + /** + * 渲染空容器 + * @returns + */ + function renderEmptyContainer() { + return ( +
+
+ 从右侧拖拽模版到这里 +
+
+ ) + } + + return () => { + return ( +
+ {hasHiddenComponents.value ? renderComponentContainer() : renderEmptyContainer()} +
+ ) + } + +} diff --git a/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.component.tsx b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.component.tsx new file mode 100644 index 00000000000..dffda2cedcf --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.component.tsx @@ -0,0 +1,105 @@ +import { computed, defineComponent, inject, onMounted, ref, watch } from "vue"; +import { FNotifyService } from "@farris/ui-vue/components/notify"; +import { DesignerHostService, useDesignerComponent } from "@farris/ui-vue/components/designer-canvas"; +import { hiddenComponentProps, HiddenComponentProps } from "./hidden-component.props"; +import { useDesignerRules } from "../../composition/use-designer-rules"; +import { HiddenComponentSchema } from "../../composition/types"; + +export default defineComponent({ + name: 'FHiddenComponent', + props: hiddenComponentProps, + emits: ['click', 'delete'] as (string[] & ThisType) | undefined, + setup(props: HiddenComponentProps, context) { + const elementRef = ref(); + const notifyService = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + /** HiddenComponent的Schema */ + const hiddenComponentSchema: HiddenComponentSchema = props.modelValue; + const { name, componentType } = hiddenComponentSchema; + /** 当前组件是否选中 */ + const isSelected = ref(props.isSelected); + + const designerHostService = inject('designer-host-service') as DesignerHostService; + const designerRulesComposition = useDesignerRules(hiddenComponentSchema, designerHostService); + const componentInstance = useDesignerComponent(elementRef, undefined, designerRulesComposition); + + /** 删除按钮的样式 */ + const deleteButtonStyle = computed(() => { + return isSelected.value ? 'display: flex;position:relative' : 'display: none'; + }) + /** 图片路径 */ + const imagePath = computed(() => { + return componentType === 'Popup' ? './image/弹窗.png' : './image/弹窗.png'; + }) + + /** + * 点击HiddenComponent + */ + function onClick() { + context.emit('click', hiddenComponentSchema, componentInstance.value); + } + + /** + * 删除HiddenComponent + */ + function onDelete() { + context.emit('delete', hiddenComponentSchema); + } + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + watch( + () => props.isSelected, + () => { + isSelected.value = props.isSelected; + } + ); + + context.expose(componentInstance.value); + + function renderDeleteButton() { + return ( +
+
+ +
+
+ ); + } + + function renderHidenComponent() { + return ( +
+
+
+ +
+
+
{name}
+
+
+
+ ); + } + + return () => { + return ( +
+ {renderDeleteButton()} + {renderHidenComponent()} +
+ ); + } + } + +}) diff --git a/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.props.ts b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.props.ts new file mode 100644 index 00000000000..95d7bf5ba84 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/components/hidden-component/hidden-component.props.ts @@ -0,0 +1,16 @@ +import { ExtractPropTypes } from "vue"; +import { createPropsResolver } from '../../../../dynamic-resolver'; +import { schemaMapper } from '../../schema/schema-mapper'; +import { schemaResolver } from '../../schema/schema-resolver'; +import hiddenComponentSchema from '../../schema/hidden-component.schema.json'; + +export const hiddenComponentProps = { + id: { type: String, default: '' }, + modelValue: { type: Object, default: {} }, + isSelected: { type: Boolean, default: false }, + +} as Record; + +export type HiddenComponentProps = ExtractPropTypes; + +export const propsResolver = createPropsResolver(hiddenComponentProps, hiddenComponentSchema, schemaMapper, schemaResolver); diff --git a/packages/ui-vue/components/designer-hidden-area/src/composition/drag-resolve.tsx b/packages/ui-vue/components/designer-hidden-area/src/composition/drag-resolve.tsx new file mode 100644 index 00000000000..f23f3eeaeaf --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/composition/drag-resolve.tsx @@ -0,0 +1,85 @@ +import { DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import { ModalFunctions } from "@farris/ui-vue/components/modal/src/composition/type"; +import FHiddenAreaFormSelector from '../components/hidden-component-selector/hidden-component-selector.component'; +import { DesignerHTMLElement } from "@farris/ui-vue/components/designer-canvas/src/composition/types"; +import { HiddenComponentType, UseHiddenComponent } from "./types"; +import { SchemaItem } from "@farris/ui-vue/components/schema-selector"; + +export function dragResolveService(designerHostService: DesignerHostService, hiddenComponentComposition: UseHiddenComponent) { + let modalEditor: ModalFunctions; + + /** + * 关闭模态框 + */ + function closeModal() { + const closeFunction = modalEditor?.modalRef?.value.close; + if (closeFunction) { + closeFunction(); + } + } + + /** + * 确定选择HiddenComponent + * @param selectedComponent + * @param hiddenComponentType + * @returns + */ + function onSubmit(selectedComponent: SchemaItem, hiddenComponentType: HiddenComponentType) { + hiddenComponentComposition.addComponent(selectedComponent, hiddenComponentType); + closeModal(); + } + + /** + * 渲染HiddenComponent选择器 + * @param hiddenComponentType + * @returns + */ + function renderComponentSelector(hiddenComponentType: HiddenComponentType) { + return () => { + return ( + { onSubmit(selectedComponent, hiddenComponentType) }} + onClose={closeModal} hiddenComponentType={hiddenComponentType}> + ) + } + } + + /** + * 弹出HiddenComponent选择器 + * @param element + * @returns + */ + function showModel(element: DesignerHTMLElement) { + const hiddenComponentType = element.getAttribute('data-code') as HiddenComponentType; + if (!hiddenComponentType) { + console.error('HiddenComponentType is null'); + return; + } + const title = hiddenComponentType === 'Help' ? '选择帮助' : '选择表单'; + modalEditor = designerHostService.modalService.open({ + title: title, + width: 950, + height: 600, + fitContent: false, + showButtons: false, + render: renderComponentSelector(hiddenComponentType), + enableEsc: true, + draggable: true + }); + } + + /** + * 拖拽落下事件 + * @param element + * @param target + * @param source + * @param sibling + * @returns + */ + function onDrop(element: DesignerHTMLElement, target: DesignerHTMLElement, source: DesignerHTMLElement, sibling: DesignerHTMLElement) { + showModel(element); + } + + return { + onDrop + }; +} diff --git a/packages/ui-vue/components/designer-hidden-area/src/composition/types.ts b/packages/ui-vue/components/designer-hidden-area/src/composition/types.ts new file mode 100644 index 00000000000..1bfdd277938 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/composition/types.ts @@ -0,0 +1,16 @@ +import { SchemaItem } from "@farris/ui-vue/components/schema-selector"; + +export type HiddenComponentType = 'Popup' | 'Help'; + +export interface HiddenComponentSchema { + id: string; + type: 'hidden-component'; + name: string; + componentType: HiddenComponentType; + component: SchemaItem; +} + +export interface UseHiddenComponent { + addComponent: (component: SchemaItem, hiddenComponentType: HiddenComponentType) => void; + deleteComponent: (hiddenComponentSchema: HiddenComponentSchema) => void; +} \ No newline at end of file diff --git a/packages/ui-vue/components/designer-hidden-area/src/composition/use-designer-rules.ts b/packages/ui-vue/components/designer-hidden-area/src/composition/use-designer-rules.ts new file mode 100644 index 00000000000..3a46d3621c6 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/composition/use-designer-rules.ts @@ -0,0 +1,36 @@ +import { DesignerHostService, UseDesignerRules } from "../../../designer-canvas/src/composition/types"; +import { ComponentSchema } from "../../../designer-canvas/src/types"; +import { HiddenComponentProperty } from "../property-config/hidden-component.property-config"; + +export function useDesignerRules(schema: ComponentSchema, designerHostService: DesignerHostService): UseDesignerRules { + + function canAccepts(): boolean { + return false; + } + + function checkCanDeleteComponent() { + return false; + } + + function checkCanMoveComponent() { + return false; + } + + function hideNestedPaddingInDesginerView() { + return false; + } + function getStyles(): string { + return ''; + } + + /** + * 构造属性配置方法 + * @param componentId + * @returns + */ + function getPropsConfig(componentId: string) { + const properties = new HiddenComponentProperty(componentId, designerHostService); + return properties.getPropertyConfig(schema); + } + return { canAccepts, checkCanDeleteComponent, checkCanMoveComponent, hideNestedPaddingInDesginerView, getStyles, getPropsConfig }; +} diff --git a/packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-area-dragula.ts b/packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-area-dragula.ts new file mode 100644 index 00000000000..e6a39e6877e --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-area-dragula.ts @@ -0,0 +1,69 @@ +import dragula from '@farris/designer-dragula'; +import { DesignerHTMLElement } from '../../../designer-canvas/src/composition/types'; +import { dragResolveService } from './drag-resolve'; +import { DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import { UseHiddenComponent } from './types'; + +export function useHiddenAreaDragula(designerHostService: DesignerHostService, hiddenComponentComposition: UseHiddenComponent) { + + let dragulaInstance: any; + /** 拖拽所需的服务 */ + const dragResolveUtil = dragResolveService(designerHostService, hiddenComponentComposition); + + const COMPONENT_CONTAINER_CLASS = "f-designer-hidden-area-component-container"; + const TEMPLATE_BOX_CLASS = "f-designer-hidden-area-template-box-container"; + + /** + * 初始化拖拽 + */ + function initDragula(containerElement: DesignerHTMLElement) { + if (dragulaInstance) { + dragulaInstance.destroy(); + } + if (!dragula || !containerElement) { + return; + } + + dragulaInstance = dragula([containerElement], { + direction: 'horizontal', + revertOnSpill: true, + moves(element: DesignerHTMLElement): boolean { + return !element.classList.contains('no-drag'); + }, + getMirrorText(element: DesignerHTMLElement): string { + return element.innerText; + }, + accepts(element: HTMLElement, target: DesignerHTMLElement, source: HTMLElement, sibling: DesignerHTMLElement): boolean { + const canAccept = target.className.includes(COMPONENT_CONTAINER_CLASS); + return canAccept; + } + }).on('over', (element: DesignerHTMLElement, container: DesignerHTMLElement) => { + if (container.className.includes(COMPONENT_CONTAINER_CLASS)) { + container.className += ' hidden-area-drag-over'; + } + }).on('out', (el: DesignerHTMLElement, container: DesignerHTMLElement) => { + container.className = container.className.replace('hidden-area-drag-over', '').replace(' ', ''); + }).on('drop', (element: DesignerHTMLElement, target: DesignerHTMLElement, source: DesignerHTMLElement, sibling: DesignerHTMLElement + ) => dragResolveUtil.onDrop(element, target, source, sibling)); + + } + + /** + * 把右侧模板添加到可拖拽容器中 + * @returns + */ + function attachToDragulaContainer() { + if (!dragulaInstance) { + return; + } + const templateBoxs = document.getElementsByClassName(TEMPLATE_BOX_CLASS); + const formContainer = document.getElementsByClassName(COMPONENT_CONTAINER_CLASS); + dragulaInstance.containers = [...templateBoxs, ...formContainer]; + } + + + return { + initDragula, + attachToDragulaContainer + }; +} diff --git a/packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-component.ts b/packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-component.ts new file mode 100644 index 00000000000..a6ddc0f05c1 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/composition/use-hidden-component.ts @@ -0,0 +1,52 @@ +import { Ref, ref } from "vue"; +import { HiddenComponentSchema, HiddenComponentType, UseHiddenComponent } from "./types"; +import { FNotifyService } from "@farris/ui-vue/components/notify"; +import { DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import { useGuid } from "@farris/ui-vue/components/common"; +import { SchemaItem } from "@farris/ui-vue/components/schema-selector"; + +export default function (designerHostService: DesignerHostService): UseHiddenComponent { + + const notifyService = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + + const module = designerHostService.formSchemaUtils.getModule(); + module.hiddenComponents ??= []; + const hiddenComponents: Ref = ref(module.hiddenComponents); + + /** + * 添加HiddenComponent + * @param component + * @param hiddenComponentType + */ + function addComponent(component: SchemaItem, hiddenComponentType: HiddenComponentType) { + const { uuid } = useGuid(); + const id = `hidden-component-${uuid(4)}`; + const hiddenComponentSchema: HiddenComponentSchema = { + id, + type: 'hidden-component', + name: component.name, + componentType: hiddenComponentType, + component + } + + hiddenComponents.value.push(hiddenComponentSchema); + } + + /** + * 删除HiddenComponent + * @param hiddenComponentSchema + */ + function deleteComponent(hiddenComponentSchema: HiddenComponentSchema) { + const componentIndex = hiddenComponents.value.findIndex(component => component.id === hiddenComponentSchema.id); + if (componentIndex > -1) { + hiddenComponents.value.splice(componentIndex, 1); + } + } + + + return { + addComponent, + deleteComponent, + } +} diff --git a/packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.component.tsx b/packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.component.tsx new file mode 100644 index 00000000000..e1a767fdee0 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.component.tsx @@ -0,0 +1,55 @@ +import { defineComponent, ref, } from 'vue'; +import { DesignerHiddenAreaProps, designerHiddenAreaProps } from './designer-hidden-area.props'; +import getHiddenComponentTemplateRender from './components/hidden-component-template/hidden-component-template.component'; +import getHiddenComponentContainerRender from './components/hidden-component/hidden-component-container.component'; + +import '../designer-hidden-area.css' + +export default defineComponent({ + name: 'FDesignerHiddenArea', + props: designerHiddenAreaProps, + emits: ['selectionChange'] as (string[] & ThisType) | undefined, + setup(props: DesignerHiddenAreaProps, context) { + const showHiddenArea = ref(false); + /** 渲染HiddenComponent的容器 */ + const renderHiddenComponentContainer = getHiddenComponentContainerRender(props, context); + /** 渲染HiddenComponent的模板 */ + const renderHiddenComponentTemplate = getHiddenComponentTemplateRender(); + + /** + * 点击顶部按钮 + */ + function onClickTopBar() { + showHiddenArea.value = !showHiddenArea.value; + } + + function renderTopBar() { + return ( +
+ + + + {showHiddenArea.value ? '隐藏区域' : '收起面板'} + + +
+ ) + } + + return () => { + return ( +
+ {renderTopBar()} + +
+ ); + } + } + +}); + diff --git a/packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.props.ts b/packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.props.ts new file mode 100644 index 00000000000..c72f5faeb13 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/designer-hidden-area.props.ts @@ -0,0 +1,8 @@ +import { ExtractPropTypes } from "vue"; + +export const designerHiddenAreaProps = { + id: { type: String, default: '' }, + modelValue: { type: Object }, +} as Record; + +export type DesignerHiddenAreaProps = ExtractPropTypes; diff --git a/packages/ui-vue/components/designer-hidden-area/src/property-config/hidden-component.property-config.ts b/packages/ui-vue/components/designer-hidden-area/src/property-config/hidden-component.property-config.ts new file mode 100644 index 00000000000..24c4ecd9d37 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/property-config/hidden-component.property-config.ts @@ -0,0 +1,16 @@ +import { ComponentSchema, DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import { BaseControlProperty } from "@farris/ui-vue/components/property-panel"; + +export class HiddenComponentProperty extends BaseControlProperty { + + constructor(componentId: string, designerHostService: DesignerHostService) { + super(componentId, designerHostService); + } + public getPropertyConfig(propertyData: ComponentSchema) { + // 基本信息 + this.propertyConfig.categories['basic'] = this.getBasicPropConfig(propertyData); + + return this.propertyConfig; + } + +} diff --git a/packages/ui-vue/components/designer-hidden-area/src/schema/hidden-component.schema.json b/packages/ui-vue/components/designer-hidden-area/src/schema/hidden-component.schema.json new file mode 100644 index 00000000000..0293e5d71b4 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/schema/hidden-component.schema.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/hidden-component.schema.json", + "title": "hidden-component", + "description": "A Farris Visual Component", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a hidden-component", + "type": "string" + }, + "type": { + "description": "The type string of hidden-component", + "type": "string", + "default": "hidden-component" + }, + "componentType": { + "type": "string", + "default": "" + }, + "component": { + "type": "ojbect", + "default": {} + } + }, + "required": [ + "id", + "type", + "componentType", + "component" + ] +} \ No newline at end of file diff --git a/packages/ui-vue/components/designer-hidden-area/src/schema/schema-mapper.ts b/packages/ui-vue/components/designer-hidden-area/src/schema/schema-mapper.ts new file mode 100644 index 00000000000..e7bbde5239e --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/schema/schema-mapper.ts @@ -0,0 +1,4 @@ +import { resolveAppearance, MapperFunction } from '../../../dynamic-resolver'; + +export const schemaMapper = new Map([ +]); diff --git a/packages/ui-vue/components/designer-hidden-area/src/schema/schema-resolver.ts b/packages/ui-vue/components/designer-hidden-area/src/schema/schema-resolver.ts new file mode 100644 index 00000000000..75fe61bbed0 --- /dev/null +++ b/packages/ui-vue/components/designer-hidden-area/src/schema/schema-resolver.ts @@ -0,0 +1,6 @@ +import { DesignerComponentInstance, DesignerHostService, DgControl } from "../../../designer-canvas"; +import { DynamicResolver } from "../../../dynamic-resolver"; + +export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record, designerHostService?: DesignerHostService): Record { + return schema; +} \ No newline at end of file diff --git a/packages/ui-vue/components/designer.ts b/packages/ui-vue/components/designer.ts index b8aabcb5d13..45ca914df5c 100644 --- a/packages/ui-vue/components/designer.ts +++ b/packages/ui-vue/components/designer.ts @@ -10,4 +10,5 @@ export * from './schema-selector'; export * from './dynamic-resolver'; export * from './field-selector'; export { resolverMap } from './dynamic-view'; +export { FDesignerHiddenArea} from './designer-hidden-area'; -- Gitee From 7c9b3408c47a0f5df496535a1dcd6be67b59eac3 Mon Sep 17 00:00:00 2001 From: lijiangkun Date: Fri, 28 Mar 2025 09:11:19 +0800 Subject: [PATCH 34/34] =?UTF-8?q?chore:=20=20=E8=BD=AC=E6=8D=A2=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9C=BA=E6=A0=BC=E5=BC=8F=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../property-editor/src/composition/use-state-machine.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts index d96ccaa36db..671f78ca35a 100644 --- a/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts +++ b/packages/ui-vue/components/property-editor/src/composition/use-state-machine.ts @@ -29,9 +29,10 @@ export function useStateMachine( } // 3、转化为新的格式 + const status = matchResult[1] === '!' ? false : true; const newStateMachineFormat: StateMachineValue = { type: 'StateMachine', - status: matchResult[1], + status, field: matchResult[2] } -- Gitee