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 index da2a3b6fd2bf5d9e7930caf9655f682c305f89dd..28b9375b4e359fad6a5083be3b525c795209c6cd 100644 --- 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 @@ -31,7 +31,10 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe } function getDesignerClass(): string { - return ' '; + if (designItemContext.schema.block !== false) { + return ' fm-button--block '; + } + return ''; } /** @@ -42,16 +45,16 @@ export function useDesignerRules(designItemContext: DesignerItemContext, designe const { schema } = designItemContext; return componentProp.getPropertyConfig(schema); } - + return { canAccepts, - // triggerBelongedComponentToMoveWhenMoved, - // triggerBelongedComponentToDeleteWhenDeleted, - // checkCanMoveComponent, - // checkCanDeleteComponent, + triggerBelongedComponentToMoveWhenMoved, + triggerBelongedComponentToDeleteWhenDeleted, + checkCanMoveComponent, + checkCanDeleteComponent, hideNestedPaddingInDesginerView, - // getStyles, - // getDesignerClass, + getStyles, + getDesignerClass, getPropsConfig }; } diff --git a/packages/mobile-ui-vue/components/date-picker/src/designer/date-picker.design.component.tsx b/packages/mobile-ui-vue/components/date-picker/src/designer/date-picker.design.component.tsx index 6bf49f080e9dc0cdd996dbbdca9b5fbc51b8c630..f670582894e1010da090718e004763f160bbae38 100644 --- a/packages/mobile-ui-vue/components/date-picker/src/designer/date-picker.design.component.tsx +++ b/packages/mobile-ui-vue/components/date-picker/src/designer/date-picker.design.component.tsx @@ -34,7 +34,9 @@ export default defineComponent({ const inputProps = computed(() => ({ ...props, - editable: false + editable: false, + rightIcon: 's-arrow', + placeholder: props.placeholder || '请选择日期' })); return () => ; diff --git a/packages/mobile-ui-vue/components/date-picker/src/property-config/date-picker.property-config.ts b/packages/mobile-ui-vue/components/date-picker/src/property-config/date-picker.property-config.ts index e915e2bd2271fd8122e4503855080d4e3f87a7ea..060c423f2fffa854b3aeb502e35f20b080e8d771 100644 --- a/packages/mobile-ui-vue/components/date-picker/src/property-config/date-picker.property-config.ts +++ b/packages/mobile-ui-vue/components/date-picker/src/property-config/date-picker.property-config.ts @@ -12,11 +12,6 @@ export class DatePickerProperty extends InputBaseProperty { propertyData, { type: 'date-picker' }, { - title: { - description: '', - title: '标题', - type: 'string', - }, displayFormat: { description: '', title: '日期格式', 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 index 27d9818b323ed66272e04daf5618c76f91cbd69c..66d9a859d4bdb876b529a765efec22b6bc9bede0 100644 --- 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 @@ -19,6 +19,15 @@ export class InputGroupProperty extends InputBaseProperty { getEditorProperties(propertyData: any) { const self = this; + // 获取绑定字段schema中的长度属性 + let maxLength; + if (propertyData?.binding?.type === 'Form') { + const fieldInfo = this.schemaService.getFieldByIDAndVMID(propertyData.binding.field, this.viewModelId); + if (fieldInfo?.schemaField?.type) { + maxLength = fieldInfo.schemaField.type.length; + } + } + const editorProperties = self.getComponentConfig( propertyData, {}, @@ -29,7 +38,9 @@ export class InputGroupProperty extends InputBaseProperty { type: 'number', editor: { nullable: true, - min: 0 + min: 0, + useThousands: false, + max: maxLength } } }, 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 4e2924c5f6d35599614a1271be71cce7ba9759fd..5d090e1359e8ac188891e3a32394ef11a644b9cb 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 @@ -56,6 +56,11 @@ "type": "object", "default": {} }, + "maxLength": { + "description": "最大长度", + "type": "number", + "default": false + }, "onUpdate:modelValue": { "description": "值更新事件", "type": "string", 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 0a55f2f851e2818c19a39870b387eefe8fa3837f..5f579bf0c9c3cf95fbaaebeda614c6991234c206 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 @@ -33,7 +33,7 @@ export default defineComponent({ function renderItemTemplate() { return ( -
+
); } diff --git a/packages/mobile-ui-vue/components/lookup/src/designer/lookup.design.component.tsx b/packages/mobile-ui-vue/components/lookup/src/designer/lookup.design.component.tsx index 17407092fa7230fd9ebcba18d7293b1dcf7a41d4..1814c31f1c63ca22a8f747c8ca78cbc67746d161 100644 --- a/packages/mobile-ui-vue/components/lookup/src/designer/lookup.design.component.tsx +++ b/packages/mobile-ui-vue/components/lookup/src/designer/lookup.design.component.tsx @@ -34,7 +34,9 @@ export default defineComponent({ const inputProps = computed(() => ({ ...props, - editable: false + editable: false, + rightIcon: 's-arrow', + placeholder: props.placeholder || '请选择' })); return () => ; diff --git a/packages/mobile-ui-vue/components/number-input/src/property-config/number-input.property-config.ts b/packages/mobile-ui-vue/components/number-input/src/property-config/number-input.property-config.ts index b54c783ecea6dc5feb1ee9bc60dc28def61e6084..02d8c88f1449fe473f8f1237b068ac390dc322b0 100644 --- a/packages/mobile-ui-vue/components/number-input/src/property-config/number-input.property-config.ts +++ b/packages/mobile-ui-vue/components/number-input/src/property-config/number-input.property-config.ts @@ -6,14 +6,27 @@ export class NumberInputProperty extends InputBaseProperty { } getEditorProperties(propertyData: any) { + let maxPrecision; + if (propertyData?.binding?.type === 'Form') { + const fieldInfo = this.schemaService.getFieldByIDAndVMID(propertyData.binding.field, this.viewModelId); + if (fieldInfo?.schemaField?.type) { + maxPrecision = fieldInfo.schemaField.type.precision; + } + } return this.getComponentConfig( propertyData, { type: 'number-spinner' }, { precision: { - description: '', - title: '精度', - type: 'number' + description: "", + title: "精度", + type: "number", + editor: { + readonly: maxPrecision === 0, + min: 0, + max: maxPrecision + }, + refreshPanelAfterChanged: true }, max: { description: '', 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 6a35ae959782306737902bf343caa37898f39846..23099f4fd85af7a1c2bf072178a4738ae19ac669 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 @@ -9,7 +9,7 @@ export default defineComponent({ emits: [], setup(props: PageBodyContainerProps, context: SetupContext) { const elementRef = ref(); - const designerHostService = inject('designer-host-service'); + const designerHostService = inject('designer-host-service') as DesignerHostService; const designItemContext = inject('design-item-context') as DesignerItemContext; const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); 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 22c581508dc7b5239827e274180caa3c596cf360..5d800295fffc3de1d4a67362ac0cbfd997a2ae90 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 @@ -9,7 +9,7 @@ export default defineComponent({ emits: [], setup(props: PageFooterContainerProps, context: SetupContext) { const elementRef = ref(); - const designerHostService = inject('designer-host-service'); + const designerHostService = inject('designer-host-service') as DesignerHostService; const designItemContext = inject('design-item-context') as DesignerItemContext; const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); 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 0f354e8dd11850bf48437b2db722ebaf12ef295e..8cd5b13c5c92b5b5202c3ce761b9093046a58016 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 @@ -10,7 +10,7 @@ export default defineComponent({ setup(props: PageHeaderContainerProps, context: SetupContext) { const elementRef = ref(); const designItemContext = inject('design-item-context') as DesignerItemContext; - const designerHostService = inject('designer-host-service'); + const designerHostService = inject('designer-host-service') as DesignerHostService; const designerRulesComposition = useDesignerRules(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, designerRulesComposition); 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 a8c5c8ddd40646428759c6625f2c0047bdb9b7e6..89e42ddd5a084f9f21ac1f742ad57aea4b0a6bcc 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,16 +1,17 @@ import { ref } from "vue"; import { PAGE_HEADER_CONTAINER_NAME } from '../page-header-container.props'; -import { DesignerItemContext, UseDesignerRules, useDragulaCommonRule } from "@farris/mobile-ui-vue/common"; +import { DesignerHostService, DesignerItemContext, UseDesignerRules, useDragulaCommonRule } from "@farris/mobile-ui-vue/common"; import { DraggingResolveContext } from "@farris/mobile-ui-vue/common"; import { PageHeaderContainerProperty } from "../property-config/page-header-container.property-config"; -export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { +export function useDesignerRules(designItemContext: DesignerItemContext, designerHostService: DesignerHostService): UseDesignerRules { const triggerBelongedComponentToMoveWhenMoved = ref(false); const triggerBelongedComponentToDeleteWhenDeleted = ref(false); const hideNestedPadding = true; + const { formSchemaUtils } = designerHostService; function canAccepts(draggingContext: DraggingResolveContext): boolean { const { componentType, parentComponentInstance } = draggingContext; diff --git a/packages/mobile-ui-vue/components/picker/src/designer/enum-field-input.design.component.tsx b/packages/mobile-ui-vue/components/picker/src/designer/enum-field-input.design.component.tsx deleted file mode 100644 index a8e103fb4d70e23265d0139c39f32bafe9200d7a..0000000000000000000000000000000000000000 --- a/packages/mobile-ui-vue/components/picker/src/designer/enum-field-input.design.component.tsx +++ /dev/null @@ -1,75 +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 { computed, defineComponent, inject, onMounted, readonly, ref, SetupContext } from 'vue'; -import { DesignerHostService, DesignerItemContext, useDesignerComponent } from '@farris/mobile-ui-vue/designer-canvas'; -import { pickerProps } from '../picker.props'; -import Picker from '../picker.component'; -import { useEnumFieldDesignerRules } from './use-designer-rules';; - -export default defineComponent({ - name: 'FmEnumFieldInputDesign', - props: pickerProps, - emits: [] as (string[] & ThisType) | undefined, - setup(props, 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/src/designer/picker.design.component.tsx b/packages/mobile-ui-vue/components/picker/src/designer/picker.design.component.tsx index 8f16c721e373e8f193977523ca2864f95ba1bc74..b146f229496e020fe744cc9e467118f4b99a5963 100644 --- a/packages/mobile-ui-vue/components/picker/src/designer/picker.design.component.tsx +++ b/packages/mobile-ui-vue/components/picker/src/designer/picker.design.component.tsx @@ -54,7 +54,9 @@ export default defineComponent({ const inputProps = computed(() => ({ ...props, - editable: false + editable: false, + rightIcon: 's-arrow', + placeholder: props.placeholder || '请选择' })); return () => ; diff --git a/packages/mobile-ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/mobile-ui-vue/components/property-panel/src/composition/entity/base-property.ts deleted file mode 100644 index 9ec35abb2781993bf624f01ed354760fdba42526..0000000000000000000000000000000000000000 --- a/packages/mobile-ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { DesignerComponentInstance } from "@farris/mobile-ui-vue/designer-canvas"; -import { DgControl } from "../../../../designer-canvas/src/composition/dg-control"; -import { cloneDeep } from "lodash-es"; - -/** - * 控件属性基类 - */ -export class BaseControlProperty { - public componentId: string; - - public viewModelId: string; - - public eventsEditorUtils: any; - - public formSchemaUtils: any; - public formMetadataConverter: any; - public designViewModelUtils: any; - public designViewModelField: any; - public controlCreatorUtils: any; - public designerHostService: any; - - schemaService: any = null; - - metadataService: any = null; - - protected propertyConfig = { - type: 'object', - categories: {} - }; - - constructor(componentId: string, designerHostService: any) { - this.componentId = componentId; - this.designerHostService = designerHostService; - this.eventsEditorUtils = designerHostService['eventsEditorUtils']; - this.formSchemaUtils = designerHostService['formSchemaUtils']; - this.formMetadataConverter = designerHostService['formMetadataConverter']; - this.viewModelId = this.formSchemaUtils?.getViewModelIdByComponentId(componentId) || ''; - this.designViewModelUtils = designerHostService['designViewModelUtils']; - this.controlCreatorUtils = designerHostService['controlCreatorUtils']; - this.metadataService = designerHostService['metadataService']; - this.schemaService = designerHostService['schemaService']; - } - - getTableInfo() { - return this.schemaService?.getTableInfoByViewModelId(this.viewModelId); - } - - setDesignViewModelField(propertyData: any) { - const bindingFieldId = propertyData.binding && propertyData.binding.type === 'Form' && propertyData.binding.field; - // 视图模型中[字段更新时机]属性现在要在控件上维护,所以在控件上复制一份属性值 - if (bindingFieldId) { - if (!this.designViewModelField) { - const dgViewModel = this.designViewModelUtils.getDgViewModel(this.viewModelId); - this.designViewModelField = dgViewModel.fields.find(f => f.id === bindingFieldId); - } - propertyData.updateOn = this.designViewModelField?.updateOn; - } - } - - getBasicPropConfig(propertyData: any): any { - return { - description: 'Basic Information', - title: '基本信息', - properties: { - id: { - description: '组件标识', - title: '标识', - type: 'string', - readonly: true - }, - type: { - description: '组件类型', - title: '控件类型', - type: 'select', - editor: { - type: 'combo-list', - textField: 'name', - valueField: 'value', - editable: false, - data: [{ value: propertyData.type, name: DgControl[propertyData.type] && DgControl[propertyData.type].name }] - } - } - } - }; - - } - - - protected getAppearanceConfig(propertyData = null): any { - return { - title: "外观", - description: "Appearance", - properties: { - class: { - title: "class样式", - type: "string", - description: "组件的CSS样式", - $converter: "/converter/appearance.converter" - }, - style: { - title: "style样式", - type: "string", - description: "组件的样式", - $converter: "/converter/appearance.converter" - } - } - }; - } - - /** - * - * @param propertyId - * @param componentInstance - * @returns - */ - public updateElementByParentContainer(propertyId:string, componentInstance: DesignerComponentInstance){ - // 1、定位控件父容器 - const parentContainer = componentInstance && componentInstance.parent && componentInstance.parent['schema']; - if (!parentContainer) { - return; - } - const index = parentContainer.contents.findIndex(c => c.id === propertyId); - // 通过cloneDeep方式的触发更新 - const controlSchema = cloneDeep(parentContainer.contents[index]); - // 5、替换控件 - parentContainer.contents.splice(index, 1); - parentContainer.contents.splice(index, 0, controlSchema); - } - -} diff --git a/packages/mobile-ui-vue/components/property-panel/src/composition/entity/input-base-property.ts b/packages/mobile-ui-vue/components/property-panel/src/composition/entity/input-base-property.ts deleted file mode 100644 index a8dd354e6067426eb0e27353b1acef9625e8172c..0000000000000000000000000000000000000000 --- a/packages/mobile-ui-vue/components/property-panel/src/composition/entity/input-base-property.ts +++ /dev/null @@ -1,390 +0,0 @@ - -import { BaseControlProperty } from "./base-property"; -import { SchemaDOMMapping } from './schema-dom-mapping'; -import { canvasChanged } from '../../../../designer-canvas/src/composition/designer-canvas-changed'; -import { DesignerComponentInstance } from "../../../../designer-canvas/src/types"; -import { FormUnifiedColumnLayout } from "../type"; -import { - ResponseFormLayoutContext, - UseResponseLayoutEditorSetting, -} from "@farris/mobile-ui-vue/response-layout-editor"; -import { useResponseLayoutEditorSetting } from "../../../../response-layout-editor/src/composition/converter/use-response-layout-editor-setting"; -import { FormSchemaEntityFieldType$Type } from "@farris/mobile-ui-vue/common"; - -export class InputBaseProperty extends BaseControlProperty { - public responseLayoutEditorFunction: UseResponseLayoutEditorSetting; - constructor(componentId: string, designerHostService: any) { - super(componentId, designerHostService); - this.responseLayoutEditorFunction = useResponseLayoutEditorSetting(this.formSchemaUtils); - } - - public getPropertyConfig(propertyData: any, componentInstance: DesignerComponentInstance) { - // 基本信息 - this.propertyConfig.categories['basic'] = this.getBasicProperties(propertyData, componentInstance); - // 外观 - this.propertyConfig.categories['appearance'] = this.getAppearanceProperties(propertyData, componentInstance); - // 编辑器 - this.propertyConfig.categories['editor'] = this.getEditorProperties(propertyData); - return this.propertyConfig; - } - - public getBasicProperties(propertyData, componentInstance): any { - const self = this; - this.setDesignViewModelField(propertyData); - return { - description: 'Basic Information', - title: '基本信息', - properties: { - id: { - description: '组件标识', - title: '标识', - type: 'string', - readonly: true - }, - type: { - description: '编辑器类型', - title: '编辑器类型', - type: 'string', - refreshPanelAfterChanged: true, - $converter: '/converter/change-editor.converter', - editor: { - type: 'combo-list', - textField: 'value', - valueField: 'key', - editable: false, - data: self.designViewModelField ? SchemaDOMMapping.getEditorTypesByMDataType(self.designViewModelField.type?.name) : SchemaDOMMapping.getAllInputTypes() - } - }, - label: { - title: "标签", - type: "string", - $converter: '/converter/form-group-label.converter' - }, - binding: { - description: "绑定的表单字段", - title: "绑定", - editor: { - type: "binding-selector", - bindingType: { "enable": false }, - editorParams: { - componentSchema: propertyData, - needSyncToViewModel: true, - viewModelId: this.viewModelId, - designerHostService: this.designerHostService, - disableOccupiedFields: true - }, - textField: 'bindingField' - } - } - }, - setPropertyRelates(changeObject, prop) { - if (!changeObject) { - return; - } - switch (changeObject && changeObject.propertyID) { - case 'type': { - self.changeControlType(propertyData, changeObject, componentInstance); - break; - } - case 'label': { - changeObject.needRefreshControlTree = true; - break; - } - } - } - }; - } - public getAppearanceProperties(propertyData, componentInstance): any { - - const self = this; - return { - title: "外观", - description: "Appearance", - properties: { - class: { - title: "class样式", - type: "string", - description: "组件的CSS样式", - $converter: "/converter/appearance.converter" - }, - style: { - title: "style样式", - type: "string", - description: "组件的样式", - $converter: "/converter/appearance.converter" - }, - responseLayout: { - description: "响应式列宽", - title: "响应式列宽", - type: "boolean", - visible: true, - // 这个属性,标记当属性变更得时候触发重新更新属性 - refreshPanelAfterChanged: true, - editor: { - type: "response-layout-editor-setting", - initialState: self.responseLayoutEditorFunction.checkCanOpenLayoutEditor(propertyData, self.componentId) - } - } - }, - setPropertyRelates(changeObject, prop) { - if (!changeObject) { - return; - } - switch (changeObject && changeObject.propertyID) { - case 'responseLayout': - self.responseLayoutEditorFunction.changeFormControlsByResponseLayoutConfig(changeObject.propertyValue, self.componentId || propertyData.id); - self.updateUnifiedLayoutAfterResponseLayoutChanged(self.componentId); - self.updateElementByParentContainer(propertyData.id, componentInstance); - delete propertyData.responseLayout; - break; - case 'class': - self.updateUnifiedLayoutAfterControlChanged(changeObject.propertyValue, propertyData.id, this.componentId); - self.updateElementByParentContainer(propertyData.id, componentInstance); - break; - } - - } - }; - }; - - public getEditorProperties(propertyData): any { - return this.getComponentConfig(propertyData); - } - - - /** - * 卡片控件:切换控件类型后事件 - * @param propertyData 控件DOM属性 - * @param newControlType 新控件类型 - */ - private changeControlType(propertyData, changeObject, componentInstance: DesignerComponentInstance) { - const newControlType = changeObject.propertyValue; - - // 1、定位控件父容器 - const parentContainer = componentInstance && componentInstance.parent && componentInstance.parent['schema']; - if (!parentContainer) { - return; - } - - const index = parentContainer.contents.findIndex(c => c.id === propertyData.id); - const oldControl = parentContainer.contents[index]; - - let newControl; - // 2、记录绑定字段viewModel的变更 - if (this.designViewModelField) { - const dgViewModel = this.designViewModelUtils.getDgViewModel(this.viewModelId); - dgViewModel.changeField(this.designViewModelField.id, { - editor: { - $type: newControlType - }, - name: this.designViewModelField.name, - require: this.designViewModelField.require, - readonly: this.designViewModelField.readonly - }, false); - // 3、创建新控件 - newControl = this.controlCreatorUtils.setFormFieldProperty(this.designViewModelField, newControlType); - } - if (!newControl) { - newControl = this.controlCreatorUtils.createFormGroupWithoutField(newControlType); - } - // 4、保留原id样式等属性 - Object.assign(newControl, { - id: oldControl.id, - appearance: oldControl.appearance, - size: oldControl.size, - label: oldControl.label, - binding: oldControl.binding, - visible: oldControl.visible - }); - Object.assign(newControl.editor, { - isTextArea: newControl.isTextArea && oldControl.isTextArea, - placeholder: oldControl.editor?.placeholder, - holdPlace: oldControl.editor?.holdPlace, - readonly: oldControl.editor?.readonly, - required: oldControl.editor?.required, - }); - - // 5、替换控件 - parentContainer.contents.splice(index, 1); - parentContainer.contents.splice(index, 0, newControl); - componentInstance.schema = Object.assign(oldControl, newControl); - - // 6、暂时移除旧控件的选中样式(后续考虑更好的方式) - Array.from(document.getElementsByClassName('dgComponentSelected') as HTMLCollectionOf).forEach( - (element: HTMLElement) => element.classList.remove('dgComponentSelected') - ); - - Array.from(document.getElementsByClassName('dgComponentFocused') as HTMLCollectionOf).forEach( - (element: HTMLElement) => element.classList.remove('dgComponentFocused') - ); - // 7、触发刷新 - canvasChanged.value++; - - } - - public getComponentConfig(propertyData, info = {}, properties = {}, setPropertyRelates?: any) { - const editorBasic = Object.assign({ - description: "编辑器", - title: "编辑器", - type: "input-group", - $converter: "/converter/property-editor.converter" - }, info); - - const editorProperties = Object.assign({ - readonly: { - description: "", - title: "只读", - type: "boolean", - editor: { - enableClear: true, - editable: true - } - }, - disabled: { - description: "", - title: "禁用", - type: "boolean", - visible: false - }, - // required: { - // description: "", - // title: "必填", - // type: "boolean" - // }, - placeholder: { - description: "空值时,输入控件内的占位文本", - title: "提示文本", - type: "string" - } - }, properties); - - return { ...editorBasic, properties: { ...editorProperties }, setPropertyRelates }; - - } - - - /** - * 修改某一输入控件的样式后更新Form的统一布局配置 - * @param controlClass 控件样式 - * @param controlId 控件Id - * @param componentId 控件所在组件id - */ - private updateUnifiedLayoutAfterControlChanged(controlClass: string, controlId: string, componentId: string) { - const controlClassArray = controlClass.split(' '); - - let colClass = controlClassArray.find(item => /^col-([1-9]|10|11|12)$/.test(item)); - let colMDClass = controlClassArray.find(item => /^col-md-([1-9]|10|11|12)$/.test(item)); - let colXLClass = controlClassArray.find(item => /^col-xl-([1-9]|10|11|12)$/.test(item)); - let colELClass = controlClassArray.find(item => /^col-el-([1-9]|10|11|12)$/.test(item)); - - colClass = colClass || 'col-12'; - colMDClass = colMDClass || 'col-md-' + colClass.replace('col-', ''); - colXLClass = colXLClass || 'col-xl-' + colMDClass.replace('col-md-', ''); - colELClass = colELClass || 'col-el-' + colXLClass.replace('col-xl-', ''); - - const latestControlLayoutConfig = { - id: controlId, - columnInSM: parseInt(colClass.replace('col-', ''), 10), - columnInMD: parseInt(colMDClass.replace('col-md-', ''), 10), - columnInLG: parseInt(colXLClass.replace('col-xl-', ''), 10), - columnInEL: parseInt(colELClass.replace('col-el-', ''), 10), - }; - - this.updateUnifiedLayoutAfterResponseLayoutChanged(componentId, latestControlLayoutConfig); - } - - /** - * 修改控件布局配置后更新Form统一布局配置 - * @param componentId 组件Id - * @param controlLayoutConfig 某单独变动的控件配置项,FormResponseLayoutContext类型 - */ - private updateUnifiedLayoutAfterResponseLayoutChanged(componentId: string, controlLayoutConfig?: any): FormUnifiedColumnLayout | undefined { - const { formNode } = this.responseLayoutEditorFunction.checkCanFindFormNode(componentId); - // 更改form上的统一配置 - if (!formNode || !formNode.unifiedLayout) { - return; - } - const responseLayoutConfig: ResponseFormLayoutContext[] = []; - this.responseLayoutEditorFunction.getResonseFormLayoutConfig(formNode, responseLayoutConfig, 1); - if (controlLayoutConfig) { - const changedControl = responseLayoutConfig.find(c => c.id === controlLayoutConfig.id); - Object.assign(changedControl || {}, controlLayoutConfig); - } - - // 收集每种屏幕下的列数 - const columnInSMArray = responseLayoutConfig.map(config => config.columnInSM); - const columnInMDArray = responseLayoutConfig.map(config => config.columnInMD); - const columnInLGArray = responseLayoutConfig.map(config => config.columnInLG); - const columnInELArray = responseLayoutConfig.map(config => config.columnInEL); - - // 只有每个控件的宽度都一样时,才认为form上有统一宽度,否则认为是自定义的控件宽度,此处传递null - const uniqueColClassInSM = this.checkIsUniqueColumn(columnInSMArray) ? columnInSMArray[0] : null; - const uniqueColClassInMD = this.checkIsUniqueColumn(columnInMDArray) ? columnInMDArray[0] : null; - const uniqueColClassInLG = this.checkIsUniqueColumn(columnInLGArray) ? columnInLGArray[0] : null; - const uniqueColClassInEL = this.checkIsUniqueColumn(columnInELArray) ? columnInELArray[0] : null; - - - Object.assign(formNode.unifiedLayout, { - uniqueColClassInSM, - uniqueColClassInMD, - uniqueColClassInLG, - uniqueColClassInEL - }); - } - /** - * 校验宽度样式值是否一致 - */ - private checkIsUniqueColumn(columnsInScreen: number[]) { - const keySet = new Set(columnsInScreen); - const exclusiveKeys = Array.from(keySet); - - if (exclusiveKeys.length === 1) { - return true; - } - return false; - } - /** - * 枚举项编辑器 - * @param propertyData - * @param valueField - * @param textField - * @returns - */ - protected getItemCollectionEditor(propertyData, valueField, textField) { - valueField = valueField || 'value'; - textField = textField || 'name'; - return { - editor: { - columns: [ - { field: valueField, title: '值', dataType: 'string' }, - { field: textField, title: '名称', dataType: 'string' }, - { field: 'disabled', title: '禁用', visible: false, dataType: 'boolean', editor: { type: 'switch' } }, - ], - type: "item-collection-editor", - valueField: valueField, - nameField: textField, - requiredFields: [valueField, textField], - uniqueFields: [valueField, textField], - readonly: this.checkEnumDataReadonly(propertyData) - } - }; - } - /** - * 判断枚举数据是否只读 - * 1、没有绑定信息或者绑定变量,可以新增、删除、修改 - * 2、绑定类型为字段,且字段为枚举字段,则不可新增、删除、修改枚举值。只能从be修改然后同步到表单上。 - * @param propertyData 下拉框控件属性值 - */ - private checkEnumDataReadonly(propertyData: any): boolean { - // 没有绑定信息或者绑定变量 - if (!propertyData.binding || propertyData.binding.type !== 'Form') { - return false; - } - if (this.designViewModelField && this.designViewModelField.type && - this.designViewModelField.type.$type === FormSchemaEntityFieldType$Type.EnumType) { - // 低代码、零代码,枚举字段均不可以改 - return true; - } - return false; - } -} diff --git a/packages/mobile-ui-vue/components/property-panel/src/composition/entity/use-input-rules.ts b/packages/mobile-ui-vue/components/property-panel/src/composition/entity/use-input-rules.ts deleted file mode 100644 index de3ba04fcd660f2b6fc64cf73ad1c6c597d8d2a9..0000000000000000000000000000000000000000 --- a/packages/mobile-ui-vue/components/property-panel/src/composition/entity/use-input-rules.ts +++ /dev/null @@ -1,62 +0,0 @@ - -import { ref } from "vue"; -import { DesignerHTMLElement, DraggingResolveContext, UseDesignerRules } from '../../../../designer-canvas/src/composition/types'; -import { ComponentSchema, DesignerItemContext } from "@farris/mobile-ui-vue/designer-canvas"; - -export function useInputDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { - const schema = designItemContext.schema as ComponentSchema; - /** 组件在拖拽时需要将所属的Component一起拖拽 */ - const triggerBelongedComponentToMoveWhenMoved = ref(true); - /** 组件在删除时需要将所属的Component一起拖拽 */ - const triggerBelongedComponentToDeleteWhenDeleted = ref(true); - /** data-grid所属的上级组件控制规则 */ - /** - * 判断是否可以接收拖拽新增的子级控件 - */ - function canAccepts(draggingContext: DraggingResolveContext): boolean { - return false; - } - - /** - * data-grid是否支持删除,取决于所属组件是否支持删除 - */ - function checkCanDeleteComponent() { - return false; - } - /** - * data-grid是否支持移动,取决于所属组件是否支持移动 - */ - function checkCanMoveComponent() { - return false; - } - - function hideNestedPaddingInDesginerView() { - return true; - } - - function onAcceptMovedChildElement(sourceElement: DesignerHTMLElement) { - } - /** - * 判断data-grid上下文 - */ - function resolveComponentContext() { - - } - // 构造属性配置方法 - function getPropsConfig(componentId: string) { - return null; - } - - return { - canAccepts, - checkCanDeleteComponent, - checkCanMoveComponent, - hideNestedPaddingInDesginerView, - onAcceptMovedChildElement, - resolveComponentContext, - triggerBelongedComponentToMoveWhenMoved, - triggerBelongedComponentToDeleteWhenDeleted, - getPropsConfig - } as UseDesignerRules; - -} 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 index a56bdc8759e9c2b0e07bbd89424a3faa49b5962d..3c1ee440398bc8e6d71e9232a59d3f4bfe26895f 100644 --- 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 @@ -11,7 +11,7 @@ import { useInputGroupDesignerRules } from './use-designer-rules'; export default defineComponent({ name: 'FmSwitchDesign', inheritAttrs: false, - props: extractProperties(switchProps, ['activeColor', 'inactiveColor']), + props: extractProperties(switchProps, ['activeColor', 'inactiveColor', 'size']), setup(props, context) { const elementRef = ref(); const designerHostService = inject('designer-host-service'); 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 index 4697e9c71d46ac6b383fb7e1424e91bc7dde07f1..1dd3bf46812959c5775759a8cb5f0aec2251bb4e 100644 --- a/packages/mobile-ui-vue/components/switch/src/schema/switch.schema.json +++ b/packages/mobile-ui-vue/components/switch/src/schema/switch.schema.json @@ -58,6 +58,10 @@ "onUpdate:modelValue": { "description": "值更新事件", "type": "string" + }, + "size": { + "description": "尺寸", + "type": "string" } }, "events": [ diff --git a/packages/mobile-ui-vue/components/time-picker/index.ts b/packages/mobile-ui-vue/components/time-picker/index.ts index 62ab9fe9bdab934a2e7da805fdc43236492c7c6c..95d3c5e281916bf8dad2ba06e4bbbe92f7f13f10 100644 --- a/packages/mobile-ui-vue/components/time-picker/index.ts +++ b/packages/mobile-ui-vue/components/time-picker/index.ts @@ -1,11 +1,18 @@ -import { withInstall } from '@farris/mobile-ui-vue/common'; +import { withInstall, withRegister, withRegisterDesigner } from '@farris/mobile-ui-vue/common'; import TimePickerInstallless from './src/time-picker.component'; +import TimePickerDesign from './src/designer/time-picker.design.component'; import TimePickerPanelInstallless from './src/time-picker-panel.component'; +import { propsResolverGenerator } from '../time-picker/src/time-picker.props'; export { TimePickerType } from './src/composition'; +const TIME_PICKER_REGISTERED_NAME = 'time-picker'; + const TimePickerPanel = withInstall(TimePickerPanelInstallless); const TimePicker = withInstall(TimePickerInstallless); +withRegister(TimePicker, { name: TIME_PICKER_REGISTERED_NAME, propsResolverGenerator }); +withRegisterDesigner(TimePicker, { name: TIME_PICKER_REGISTERED_NAME, propsResolverGenerator, designerComponent: TimePickerDesign }); + export { TimePicker, TimePickerPanel }; export default TimePicker; diff --git a/packages/mobile-ui-vue/components/time-picker/src/designer/time-picker.design.component.tsx b/packages/mobile-ui-vue/components/time-picker/src/designer/time-picker.design.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..98e3d1aee4188dd52bf24783584614e8906a28f2 --- /dev/null +++ b/packages/mobile-ui-vue/components/time-picker/src/designer/time-picker.design.component.tsx @@ -0,0 +1,71 @@ +/** + * 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 { + DesignerHostService, + DesignerItemContext, + extractProperties, + useDesignerComponent +} from '@farris/mobile-ui-vue/common'; +import { useTimePickerDesignerRules } from './use-designer-rules'; +import { timePickerProps } from '../time-picker.props'; +import InputGroup from '@farris/mobile-ui-vue/input-group'; + +export default defineComponent({ + name: 'FmTimePickerDesign', + inheritAttrs: false, + props: extractProperties(timePickerProps, ['placeholder']), + setup(props, context) { + const elementRef = ref(); + const designerHostService = inject('designer-host-service'); + const designItemContext = inject( + 'design-item-context' + ) as DesignerItemContext; + const designerRulesComposition = useTimePickerDesignerRules( + designItemContext, + designerHostService + ); + const componentInstance = useDesignerComponent( + elementRef, + designItemContext, + designerRulesComposition + ); + + onMounted(() => { + elementRef.value.componentInstance = componentInstance; + }); + + context.expose(componentInstance.value); + + const inputProps = computed(() => { + return { + ...props, + editable: false, + rightIcon: 's-arrow', + placeholder: props.placeholder || '请选择时间' + }; + }); + + return () => { + return ( + + ); + }; + } +}); diff --git a/packages/mobile-ui-vue/components/time-picker/src/designer/use-designer-rules.ts b/packages/mobile-ui-vue/components/time-picker/src/designer/use-designer-rules.ts new file mode 100644 index 0000000000000000000000000000000000000000..adc7fa0b3ce33876fcfc148fc97d46cd1de0256c --- /dev/null +++ b/packages/mobile-ui-vue/components/time-picker/src/designer/use-designer-rules.ts @@ -0,0 +1,15 @@ +import { ComponentSchema, DesignerComponentInstance, DesignerItemContext, UseDesignerRules } from "@farris/mobile-ui-vue/common"; +import { TimePickerProperty } from "../property-config/time-picker.property-config"; +export function useTimePickerDesignerRules(designItemContext: DesignerItemContext, designerHostService): UseDesignerRules { + + const schema = designItemContext.schema as ComponentSchema; + + // 构造属性配置方法 + function getPropsConfig(componentId: string, componentInstance: DesignerComponentInstance) { + const timePickerProps = new TimePickerProperty(componentId, designerHostService); + return timePickerProps.getPropertyConfig(schema, componentInstance); + } + + return { getPropsConfig } as UseDesignerRules; + +} diff --git a/packages/mobile-ui-vue/components/time-picker/src/property-config/time-picker.property-config.ts b/packages/mobile-ui-vue/components/time-picker/src/property-config/time-picker.property-config.ts new file mode 100644 index 0000000000000000000000000000000000000000..7cf6b9054e36361ff325906c7188886f71d4f940 --- /dev/null +++ b/packages/mobile-ui-vue/components/time-picker/src/property-config/time-picker.property-config.ts @@ -0,0 +1,52 @@ +import { DesignerComponentInstance, InputBaseProperty } from '@farris/mobile-ui-vue/common'; + + +export class TimePickerProperty extends InputBaseProperty { + constructor(componentId: string, designerHostService: any) { + super(componentId, designerHostService); + } + + public getPropertyConfig(propertyData: any, componentInstance: DesignerComponentInstance) { + super.getPropertyConfig(propertyData, componentInstance); + return this.propertyConfig; + } + + getEditorProperties(propertyData: any) { + const self = this; + const editorProperties = self.getComponentConfig( + propertyData, + {}, + { + format: { + description: "", + title: "格式", + type: "enum", + editor: { + type: "combo-list", + textField: "name", + valueField: "value", + data: [ + { value: "HH:mm:ss", name: "HH:mm:ss" }, + { value: "HH:mm", name: "HH:mm" } + ] + } + }, + maxTime: { + title: '最大时间', + type: 'string' + }, + minTime: { + title: '最小时间', + type: 'string' + } + }, + (changeObject) => { + if (!changeObject) { + return; + } + } + ); + + return editorProperties; + } +} diff --git a/packages/mobile-ui-vue/components/time-picker/src/schema/schema-mapper.ts b/packages/mobile-ui-vue/components/time-picker/src/schema/schema-mapper.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7d510235fbef8c5ca38418da2d6cac6c5b5b996 --- /dev/null +++ b/packages/mobile-ui-vue/components/time-picker/src/schema/schema-mapper.ts @@ -0,0 +1,6 @@ +import { resolveAppearance, MapperFunction } from '../../../dynamic-resolver'; + +export const schemaMapper = new Map([ + ['appearance', resolveAppearance], + ['binding', 'modelValue'] +]); diff --git a/packages/mobile-ui-vue/components/time-picker/src/schema/schema-resolver.ts b/packages/mobile-ui-vue/components/time-picker/src/schema/schema-resolver.ts new file mode 100644 index 0000000000000000000000000000000000000000..b02bdf93eec9060948f579c53aa81e3963a7d706 --- /dev/null +++ b/packages/mobile-ui-vue/components/time-picker/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/time-picker/src/schema/time-picker.schema.json b/packages/mobile-ui-vue/components/time-picker/src/schema/time-picker.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..0840c2016922785bfbcb897df8dc8de5fe5c6394 --- /dev/null +++ b/packages/mobile-ui-vue/components/time-picker/src/schema/time-picker.schema.json @@ -0,0 +1,78 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/time-picker.schema.json", + "title": "time-picker", + "description": "", + "type": "object", + "properties": { + "id": { + "description": "标识", + "type": "string" + }, + "type": { + "description": "控件类型", + "type": "string", + "default": "time-picker" + }, + "appearance": { + "description": "外观", + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "style": { + "type": "string" + } + }, + "default": {} + }, + "binding": { + "description": "绑定", + "type": "object", + "default": {} + }, + "required": { + "description": "必填", + "type": "boolean", + "default": false + }, + "readonly": { + "description": "只读", + "type": "boolean", + "default": false + }, + "placeholder": { + "description": "提示文本", + "type": "string" + }, + "format": { + "description": "格式", + "type": "string" + }, + "maxTime": { + "description": "最大时间", + "type": "string" + }, + "minTime": { + "description": "最小时间", + "type": "string" + }, + "onUpdate:modelValue": { + "description": "值更新事件", + "type": "string", + "default": "" + } + }, + "events": [ + "onUpdate:modelValue" + ], + "required": [ + "type" + ], + "ignore": [ + "id", + "appearance", + "visible" + ] +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/time-picker/src/time-picker.props.ts b/packages/mobile-ui-vue/components/time-picker/src/time-picker.props.ts index 6fe0505ec0793698f8a5d44f2f4b54073d3e4701..96075299dd86ea0c38a20a5652ad6234c1a504b0 100644 --- a/packages/mobile-ui-vue/components/time-picker/src/time-picker.props.ts +++ b/packages/mobile-ui-vue/components/time-picker/src/time-picker.props.ts @@ -1,6 +1,10 @@ import { ExtractPropTypes } from 'vue'; import { buttonEditProps } from '@farris/mobile-ui-vue/button-edit'; import { timePickerPanelProps } from './time-picker-panel.props'; +import { getPropsResolverGenerator } from '@farris/mobile-ui-vue/dynamic-resolver'; +import timePickerSchema from './schema/time-picker.schema.json'; +import { schemaMapper } from './schema/schema-mapper'; +import { schemaResolver } from './schema/schema-resolver'; export const TIME_PICKER_NAME = 'FmTimePicker'; @@ -14,3 +18,9 @@ export const timePickerProps = { }; export type TimePickerInputProps = ExtractPropTypes; +export const propsResolverGenerator = getPropsResolverGenerator( + timePickerProps, + timePickerSchema, + schemaMapper, + schemaResolver +);