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 696474c61609cc37b17323177815cab15b70a31b..b9ceb7530f6239eab81db61316f6b2e8f9708dad 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 @@ -377,7 +377,9 @@ export default defineComponent({ if (selectionSchema?.type === 'Module') { formSchemaCodes.value = JSON.stringify(schema.value, null, 4); } else { - formSchemaCodes.value = JSON.stringify(selectionNode.rawSchema, null, 4); + // 使用 useFormSchema.getComponentById(id, true) 深层递归查找最新控件 JSON,而非 treeViewData 中的深拷贝旧快照 + const latestSchema = useFormSchema.getComponentById(selectionSchema.id, true); + formSchemaCodes.value = JSON.stringify(latestSchema || selectionNode.rawSchema, null, 4); } // monacoEditorRef.value?.setPosition(`"id": "${selectionSchema.id}"`); } diff --git a/packages/designer/src/components/components/view-model-designer/method-manager/components/method-selector/use-web-command-selector.ts b/packages/designer/src/components/components/view-model-designer/method-manager/components/method-selector/use-web-command-selector.ts index f174907cb1f72ad9bad71b738e00902f50797a46..536dfaa4bc7aae38e234b397a24402c48ff3e910 100644 --- a/packages/designer/src/components/components/view-model-designer/method-manager/components/method-selector/use-web-command-selector.ts +++ b/packages/designer/src/components/components/view-model-designer/method-manager/components/method-selector/use-web-command-selector.ts @@ -135,7 +135,7 @@ export function useWebCommandSelector() { // 点击 模型=》方法=》添加方法时,会触发此方法 axios.all(requestCommandsMetadata).then(axios.spread((...commandsMetadata) => { const commandsMetadataContent = commandsMetadata.filter((item: any) => { - if (!item.data) { + if (!item?.data) { return false; } if(item.data.extendProperty){ diff --git a/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-name.ts b/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-name.ts index 99d60aaee5d35f703a9e3519efce93f742547738..b3af4fc1f193303a19615b16520f837b782e7900 100644 --- a/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-name.ts +++ b/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-name.ts @@ -64,9 +64,6 @@ export function useViewModelName(useFormSchema: UseFormSchema) { case ComponentType.calendar: { return getComponentParentTitle(formSchema, component.id) || '日历组件'; } - case ComponentType.calendar: { - return getComponentParentTitle(formSchema, component.id) || '日历组件'; - } case ComponentType.table: { return '表格布局组件'; } diff --git a/packages/designer/src/components/composition/control-creator/use-pc-control-creator.service.ts b/packages/designer/src/components/composition/control-creator/use-pc-control-creator.service.ts index c59e46f3cdfa906551d935848865459758196e03..6afad079823be513773de7e06c61266aaed9c067 100644 --- a/packages/designer/src/components/composition/control-creator/use-pc-control-creator.service.ts +++ b/packages/designer/src/components/composition/control-creator/use-pc-control-creator.service.ts @@ -1,16 +1,16 @@ -import { getSchemaByType } from "@farris/ui-vue/components"; +import { getSchemaByType, SchemaDOMMapping } from "@farris/ui-vue/components"; import { omit } from "lodash-es"; -import { FormBindingType, FormSchemaEntityField, FormSchemaEntityFieldTypeName, UseControlCreator, UseFormStateMachine, UseSchemaService } from "../../types"; +import { FormBindingType, FormSchemaEntityField, FormSchemaEntityFieldTypeName, FormVariable, FormVariableCategory, UseControlCreator, UseFormSchema, UseFormStateMachine, UseSchemaService } from "../../types"; import { FormMetadataConverter } from "../form-metadata-converter"; -export function usePCControlCreator(schemaService: UseSchemaService, formStateMachineUtils: UseFormStateMachine): UseControlCreator { +export function usePCControlCreator(schemaService: UseSchemaService, formStateMachineUtils: UseFormStateMachine, useFormSchema: UseFormSchema): UseControlCreator { /** * 获取控件的只读属性值 */ - function resolveControlReadonly(field: FormSchemaEntityField): any { + function resolveControlReadonly(field?: FormSchemaEntityField): any { // 若字段为只读,则控件为只读 - if (field.readonly) { + if (field?.readonly) { return true; } // 根据当前页面状态机中是否包含editable状态,判断控件的只读 @@ -108,12 +108,12 @@ export function usePCControlCreator(schemaService: UseSchemaService, formStateMa } // 图像 if (formEditor.type === 'image') { - formGroupMetadata.showLabelType='none'; + formGroupMetadata.showLabelType = 'none'; formEditor.rootId = 'default-root'; } // 头像 if (formEditor.type === 'avatar') { - formGroupMetadata.showLabelType='none'; + formGroupMetadata.showLabelType = 'none'; } // 帮助类型 if (formEditor.type === 'lookup' && field.editor?.$type === 'lookup') { @@ -305,23 +305,161 @@ export function usePCControlCreator(schemaService: UseSchemaService, formStateMa formEditor.textField = 'name'; break; } - case 'image':{ - formGroupMetadata.showLabelType='none'; + case 'image': { + formGroupMetadata.showLabelType = 'none'; formEditor.rootId = 'default-root'; break; } - case 'avatar':{ - formGroupMetadata.showLabelType='none'; + case 'avatar': { + formGroupMetadata.showLabelType = 'none'; break; } } return formGroupMetadata; } + function getViewModelIdOfVariable(variableId: string) { + const viewModels = useFormSchema.getViewModels(); + if (!viewModels || viewModels.length === 0) { + return; + } + + for (const viewModel of viewModels) { + const variable = viewModel.states.find(v => v.id === variableId); + if (variable) { + return viewModel.id; + } + } + } + /** + * 获取表单变量在schema中的记录。 + */ + function getRemoteVariableInSchema(variableId: string): FormSchemaEntityField | undefined { + + const schema = useFormSchema.getSchemas(); + const voVariables = schema?.variables || []; + + return voVariables?.find(v => v.id === variableId); + } + /** + * 组装变量的绑定信息 + */ + function resolveBindingForVariable(varField: FormVariable, componentId?: string): any { + if (!varField.category || varField.category === FormVariableCategory.locale) { + // 本地变量 + // 判断本地变量是否为当前组件的,若不是,需要修改path属性 + let isVaribleAndControlInSameComponent = true; + if (componentId) { + const variableViewModelId = getViewModelIdOfVariable(varField.id); + const cmp = useFormSchema.getComponentById(componentId); + isVaribleAndControlInSameComponent = variableViewModelId === cmp?.viewModel; + } + return { + type: FormBindingType.Variable, + path: isVaribleAndControlInSameComponent ? varField.code : 'root-component.' + varField.code, + field: varField.id, + fullPath: varField.code + }; + } else { + // 后端变量 + return { + type: FormBindingType.Variable, + path: 'root-component.' + varField.code, + field: varField.id, + fullPath: varField.code + }; + } + } + /** + * 根据变量创建输入控件 + * @param varField 变量 + * @param editorType 设定的编辑器类型 + * @param controlClass 控件 样式 + * @param componentId 输入控件所在组件id + * @returns form-group控件 + */ + function createFormGroupWithVariable(varField: FormVariable, editorType?: string, controlClass = 'col-12 col-md-6 col-xl-3 col-el-2', componentId?: string): any { + + const formGroupMetadata = getSchemaByType('form-group') || {}; + formGroupMetadata.id = varField.id.length > 8 ? varField.id.slice(0, 8) : varField.id; + formGroupMetadata.id = varField.code + '_' + formGroupMetadata.id.replace(/-/g, '_') + '_' + Math.random().toString(36).substring(2, 4); + formGroupMetadata.label = varField.name; + formGroupMetadata.appearance = { class: controlClass || '' }; + formGroupMetadata.binding = resolveBindingForVariable(varField, componentId); + + const resolvedEditorType = editorType || SchemaDOMMapping.getEditorTypeByVariableType(varField.type); + const formEditor = getSchemaByType(resolvedEditorType) || {}; + formGroupMetadata.editor = formEditor?.type ? formEditor : { type: 'input-group' }; + formEditor.readonly = resolveControlReadonly(); + + // 表单变量在schema中的记录 + const varInSchema = getRemoteVariableInSchema(varField.id); + + switch (varField.type) { + // 数字类型 + case 'Number': { + if (formEditor.type === 'check-box' || formEditor.type === 'switch') { + formEditor.trueValue = 1; + formEditor.falseValue = 0; + } else { + formEditor.precision = varInSchema?.type?.precision || 0; + formEditor.nullable = true; + + } + if (varInSchema?.type?.length) { + formEditor.maxLength = varInSchema.type.length; + } + break; + } + case 'String': { + if (formEditor.type === 'check-box' || formEditor.type === 'switch') { + formEditor.trueValue = 'true'; + formEditor.falseValue = 'false'; + } + if (varInSchema?.type?.length) { + formEditor.maxLength = varInSchema.type.length; + } + break; + } + } + switch (formEditor.type) { + // 多行文本 + case 'textarea': { + formEditor.resizable = true; + break; + } + // 日期 + case 'date-picker': { + formEditor.fieldType = varField.type; + + // 日期时间类型字段:启用时间选择属性 + if (varField.type === 'DateTime') { + formEditor.showTime = true; + formEditor.displayFormat = 'yyyy-MM-dd HH:mm:ss'; + formEditor.valueFormat = 'yyyy-MM-dd HH:mm:ss'; + } + break; + } + // 图像 + case 'image': { + formGroupMetadata.showLabelType = 'none'; + formEditor.rootId = 'default-root'; + break; + } + // 头像 + case 'avatar': { + formGroupMetadata.showLabelType = 'none'; + break; + } + } + + return formGroupMetadata; + } return { setFormFieldProperty, setGridFieldProperty, createFormGroupWithoutField, mapControlType2GridFieldType, - setGridFieldFormatter + setGridFieldFormatter, + createFormGroupWithVariable }; } diff --git a/packages/designer/src/components/designer.component.tsx b/packages/designer/src/components/designer.component.tsx index 14992da8e53647aae139d582cd769113f5684780..236f4635ba8cc1161954a553928d2d5f6be87b41 100644 --- a/packages/designer/src/components/designer.component.tsx +++ b/packages/designer/src/components/designer.component.tsx @@ -84,7 +84,7 @@ export default defineComponent({ // metadatFullPath const metadataPath: string = inject(MetadataPathToken, ''); // 控件创建服务 - const controlCreatorService = designerContext.useControlCreator(schemaService, useFormStateMachineComposition); + const controlCreatorService = designerContext.useControlCreator(schemaService, useFormStateMachineComposition, useFormSchemaComposition); provide('controlCreatorUtils', controlCreatorService); provide('formMetadataConverter', new FormMetadataConverter()); diff --git a/packages/designer/src/components/types/designer-context.ts b/packages/designer/src/components/types/designer-context.ts index 8aaed3a0b5fa9420b3a4d7873aa750fe5fa0794f..829f54e66eb31b42e946450128e92ac91947b86c 100644 --- a/packages/designer/src/components/types/designer-context.ts +++ b/packages/designer/src/components/types/designer-context.ts @@ -42,14 +42,14 @@ export interface UseDesignerContext { dgControl?: any; uiModel?: any; instances?: Record; - responsiveForm?:boolean; + responsiveForm?: boolean; designerMode: DesignerMode; terminalRef: Ref; toolboxItems: Ref; componentsToRegister: any[]; supportedControllers: any; controllCategories: any; - useControlCreator: (schemaService: UseSchemaService, useFormStateMachineComposition: UseFormStateMachine) => UseControlCreator; + useControlCreator: (schemaService: UseSchemaService, useFormStateMachineComposition: UseFormStateMachine, useFormSchema: UseFormSchema) => UseControlCreator; getPageComponents: (useFormSchema: UseFormSchema) => FormComponent[]; /** 查询元数据内容 */ @@ -77,5 +77,5 @@ export interface UseDesignerContext { schemaDOMMapping?: Record; - dynamicScriptService?: DynamicScriptService|undefined; + dynamicScriptService?: DynamicScriptService | undefined; } diff --git a/packages/designer/src/components/types/metadata.ts b/packages/designer/src/components/types/metadata.ts index d1856be4cc67ea27b564c9eb79bc3379d0148512..feef408052f65b22f897beabe62a1a842edce8df 100644 --- a/packages/designer/src/components/types/metadata.ts +++ b/packages/designer/src/components/types/metadata.ts @@ -216,7 +216,7 @@ export interface UseFormSchema { setFormSchema: (newSchema: FormMetadaDataDom) => void; /** 根据Comonent id 获取组件节点*/ - getComponentById: (targetComponentId: string) => FormComponent | undefined; + getComponentById: (targetComponentId: string, deep?: boolean) => FormComponent | undefined; /** 根据viewmodel id 获取组件节点*/ getComponentByViewModelId: (targetViewModelId: string) => FormComponent | undefined; @@ -337,6 +337,8 @@ export interface UseControlCreator { createFormGroupWithoutField: (editorType: string, controlClass: string) => any; setGridFieldFormatter: (gridFieldType: string, metadata: any, schemaField: any) => void; mapControlType2GridFieldType: (field: FormSchemaEntityField) => string; + createFormGroupWithVariable(varField: FormVariable, editorType?: string, controlClass?: string, componentId?: string): any; + } export interface UseFormStateMachine { diff --git a/packages/designer/src/components/types/toolbox/pc-toolbox.json b/packages/designer/src/components/types/toolbox/pc-toolbox.json index 53dbc3571b88d05e78af76af84806ee4a3e75798..babca2d5b7d0d4d44fb63cb1161baef73a2863fa 100644 --- a/packages/designer/src/components/types/toolbox/pc-toolbox.json +++ b/packages/designer/src/components/types/toolbox/pc-toolbox.json @@ -128,6 +128,12 @@ "name": "日历", "category": "dataCollection", "icon": "date-picker" + }, + { + "id": "table", + "type": "table", + "name": "表格布局", + "category": "dataCollection" } ] }, diff --git a/packages/ui-vue/components/binding-selector/src/binding-selector.component.tsx b/packages/ui-vue/components/binding-selector/src/binding-selector.component.tsx index 67fa390f5bbba864429b7f536d1dc7466ae133b7..df4f7cf536350230eff6fa195cecc5a974e2cca1 100644 --- a/packages/ui-vue/components/binding-selector/src/binding-selector.component.tsx +++ b/packages/ui-vue/components/binding-selector/src/binding-selector.component.tsx @@ -106,7 +106,7 @@ export default defineComponent({ function onClearBinding() { clearViewModel(); clearExpresssionConfig(); - clearComponentSchema() + clearComponentSchema(); setDisplayText(null); props.onFieldSelected(undefined, undefined); } diff --git a/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts b/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts index 406678c14888a0cb3c8c75d85d9db2cf3c61d232..754b68de81f9c126affa371fe72d7be19e8be16b 100644 --- a/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts +++ b/packages/ui-vue/components/binding-selector/src/composition/use-field-selection.ts @@ -13,7 +13,7 @@ export function useFieldSelection(props: BindingSelectorProps) { let localeVariableTreeData = []; let formVariableTreeData = []; /** 字段类型是否发生变化 */ - let fieldTypeChanged = ref(false); + const fieldTypeChanged = ref(false); const notifyService: any = new FNotifyService(); notifyService.globalConfig = { position: 'top-center' }; @@ -454,7 +454,7 @@ export function useFieldSelection(props: BindingSelectorProps) { * 清除组件schema的绑定信息 */ function clearComponentSchema() { - const componentSchema = props.editorParams.componentSchema; + const { componentSchema } = props.editorParams; if (!componentSchema) { return; } diff --git a/packages/ui-vue/components/button/src/button.props.ts b/packages/ui-vue/components/button/src/button.props.ts index 40b4889f87dae8d89892ccdeaaf0ded60c39fd73..0faa131c6f9b48c615fe5dc47c3cce05080fcb1b 100644 --- a/packages/ui-vue/components/button/src/button.props.ts +++ b/packages/ui-vue/components/button/src/button.props.ts @@ -104,4 +104,4 @@ export const buttonProps = { * Button 组件 props 的推导类型。 */ export type ButtonProps = ExtractPropTypes; -export const propsResolver = createPropsResolver(buttonProps, componentSchema, schemaMapper, schemaResolver); +export const propsResolver = createPropsResolver(buttonProps, componentSchema, schemaMapper, schemaResolver); diff --git a/packages/ui-vue/components/designer-canvas/src/composition/class/designer-canvas.css b/packages/ui-vue/components/designer-canvas/src/composition/class/designer-canvas.css index 230155e007671fa2801e0cb1218f4986038d515a..38d81a5c3098c04bb0ab35b8d15d580ee6854dff 100644 --- a/packages/ui-vue/components/designer-canvas/src/composition/class/designer-canvas.css +++ b/packages/ui-vue/components/designer-canvas/src/composition/class/designer-canvas.css @@ -231,7 +231,7 @@ } /** 解决由ng升级的vue带导航的卡片模板中,子表容器宽度不足的问题 */ -.editorDiv .f-page-navigate .f-page.f-page-card>.drag-container>.f-page-main:not(.f-page-child-fill)>.drag-container { +.editorDiv .f-page-navigate .f-page-content-main >.drag-container> .f-page.f-page-card>.drag-container>.f-page-main:not(.f-page-child-fill)>.drag-container { display: block; overflow: unset; } diff --git a/packages/ui-vue/components/dynamic-form/src/property-config/base-form.property-config.ts b/packages/ui-vue/components/dynamic-form/src/property-config/base-form.property-config.ts index 567907ae166c2f05f21c455b6060a6129c2c01ad..02efef674f3d1e757b4c8ec226f5c63bad7396d7 100644 --- a/packages/ui-vue/components/dynamic-form/src/property-config/base-form.property-config.ts +++ b/packages/ui-vue/components/dynamic-form/src/property-config/base-form.property-config.ts @@ -9,11 +9,14 @@ export class BaseFormProperty extends BaseControlProperty { constructor(componentId: string, designerHostService: any) { super(componentId, designerHostService); } - public getBaseFormAppearanceConfig(formType:'dynamic'|'default',propertyData,componentInstance: DesignerComponentInstance){ + public getBaseFormAppearanceConfig(formType: 'dynamic' | 'default', propertyData, componentInstance: DesignerComponentInstance) { const self = this; const { checkIsInFormComponent, assembleUnifiedLayoutContext, changeFormControlsByUnifiedLayoutConfig, changeControlClassInByColumn } = useResponseFormLayoutSetting(this.formSchemaUtils, this.componentId); const appearanceCategory = this.getAppearanceConfig(propertyData); - // const issInFormComponent = checkIsInFormComponent(this.componentId); + const isInFormComponent = checkIsInFormComponent(this.componentId); + if (!isInFormComponent) { + return appearanceCategory; + } appearanceCategory.properties['adaptForLanguage'] = { title: "控件布局响应国际化", description: "启用国际化后:简体中文、繁体中文环境下控件标签与输入框在一行展示,其他语言环境下控件标签与输入框上下排列。", @@ -41,7 +44,7 @@ export class BaseFormProperty extends BaseControlProperty { switch (changeObject && changeObject.propertyID) { case 'unifiedLayout': { propertyData.layout = changeControlClassInByColumn('', changeObject.propertyValue); - if(formType === 'dynamic'){ + if (formType === 'dynamic') { propertyData.layout = changeControlClassInByColumn('', changeObject.propertyValue); } else { changeFormControlsByUnifiedLayoutConfig(null, changeObject.propertyValue, propertyData.id); @@ -59,14 +62,14 @@ export class BaseFormProperty extends BaseControlProperty { return appearanceCategory; } - public getBaseFormBehaviorConfig(formType:'dynamic'|'default',propertyData: any) { + public getBaseFormBehaviorConfig(formType: 'dynamic' | 'default', propertyData: any) { const self = this; // 外观 const fieldsEditor = this.getPropertyEditorParams(propertyData, ['Variable', 'Custom'], 'fields', {}, { newVariablePrefix: '', newVariableType: 'Array' }); const formDataEditor = this.getPropertyEditorParams(propertyData, ['Variable', 'Custom'], 'formData', {}, { newVariablePrefix: '', newVariableType: 'Object' }); let extendBehavior = {}; - if(formType === 'dynamic'){ - extendBehavior= { + if (formType === 'dynamic') { + extendBehavior = { fields: { title: '动态控件列表', type: 'string', @@ -85,7 +88,7 @@ export class BaseFormProperty extends BaseControlProperty { type: "enum", editor: { default: "quick", - readonly:true, + readonly: true, data: [ { id: "quick", name: "快速模式" }, { id: "full", name: "完整模式" } diff --git a/packages/ui-vue/components/list-view/src/components/item/single-item.component.tsx b/packages/ui-vue/components/list-view/src/components/item/single-item.component.tsx index c965982794b07e70f32cab2469d976d9755f2b64..e5cd2c15b83724684cb350443392fdf593f4e7fa 100644 --- a/packages/ui-vue/components/list-view/src/components/item/single-item.component.tsx +++ b/packages/ui-vue/components/list-view/src/components/item/single-item.component.tsx @@ -26,7 +26,7 @@ export default function ( props.selection?.multiSelect && props.selection?.showCheckbox ); - const { onMouseenterItem, onMouseoverItem, onMouseoutItem } = useHoverComposition; + const { onMouseenterItem, onMouseoverItem, onMouseleaveItem } = useHoverComposition; const { getKey, listViewItemClass, listViewItemStyle, onCheckItem, onClickItem } = useItemCompostion; const contentStyle = computed(() => { @@ -56,7 +56,7 @@ export default function ( onClick={(payload: MouseEvent) => onClickItem(item, index, payload)} onMouseenter={(payload: MouseEvent) => onMouseenterItem(payload, item, index)} onMouseover={(payload: MouseEvent) => onMouseoverItem(payload, item, index)} - onMouseout={(payload: MouseEvent) => onMouseoutItem(payload, item, index)} + onMouseleave={(payload: MouseEvent) => onMouseleaveItem(payload, item, index)} > {enableMultiSelect.value && (
payload.stopPropagation()}> diff --git a/packages/ui-vue/components/list-view/src/composition/types.ts b/packages/ui-vue/components/list-view/src/composition/types.ts index df7ca00f619861acca2a0290fef83e72def41d3d..9992589b4f90f18c4e9cebefa70751b7042f29a4 100644 --- a/packages/ui-vue/components/list-view/src/composition/types.ts +++ b/packages/ui-vue/components/list-view/src/composition/types.ts @@ -66,7 +66,7 @@ export interface UseHover { onMouseoverItem($event: MouseEvent, item: any, index: number): any; - onMouseoutItem($event: MouseEvent, item: any, index: number): any; + onMouseleaveItem($event: MouseEvent, item: any, index: number): any; resumeHover(): void; diff --git a/packages/ui-vue/components/list-view/src/composition/use-hover.ts b/packages/ui-vue/components/list-view/src/composition/use-hover.ts index d046d88dbba67ae3d955929f6db293b2808a9a04..0199f7f7bfde8cfd94a7afd55c27b1fafbdaa9bc 100644 --- a/packages/ui-vue/components/list-view/src/composition/use-hover.ts +++ b/packages/ui-vue/components/list-view/src/composition/use-hover.ts @@ -19,7 +19,7 @@ export function useHover(): UseHover { hoverIndex.value = index; } - function onMouseoutItem($event: MouseEvent, item: any, index: number) { + function onMouseleaveItem($event: MouseEvent, item: any, index: number) { hoverIndex.value = -1; } @@ -44,7 +44,7 @@ export function useHover(): UseHover { clearActiveItem, onMouseenterItem, onMouseoverItem, - onMouseoutItem, + onMouseleaveItem, resumeHover, suspendHover }; 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 a04e89bd2b985d9a382471bc4f7b9f1cf3aa1c52..83cb25674aecd2d9dbe0b52c7f2d8b2d7e425a81 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 @@ -306,7 +306,7 @@ export class InputBaseProperty extends BaseControlProperty { return { canChangeControlType: false, editorTypeList: [{ - key: propertyData.editor.type, + key: propertyData.editor?.type, value: DgControl[propertyData.editor.type]?.name || propertyData.editor.type }] }; diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/schema-dom-mapping.ts b/packages/ui-vue/components/property-panel/src/composition/entity/schema-dom-mapping.ts index 2a08d4fe2db1edc2aaf5ab8123d241ce5d30f4de..7dbb8c3e24bfa07e363050fd32983294bafd25f0 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/schema-dom-mapping.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/schema-dom-mapping.ts @@ -1,6 +1,7 @@ import { DgControl } from "@farris/ui-vue/components/designer-canvas"; import { FormPropertyChangeObject } from "./property-entity"; +import { GSPElementDataType } from "@farris/ui-vue/components/common"; export class SchemaDOMMapping { @@ -177,4 +178,26 @@ export class SchemaDOMMapping { } return array; } + /** + * 根据变量类型获取默认控件编辑器类型 + */ + static getEditorTypeByVariableType(type: string) { + switch (type) { + case 'String': { + return DgControl['input-group'].type; + } + case 'Number': { + return DgControl['number-spinner'].type; + } + case 'Boolean': { + return DgControl['check-box'].type; + } + case 'Date': case 'DateTime': { + return DgControl['date-picker'].type; + } + case 'Text': { + return DgControl['textarea'].type; + } + } + } } diff --git a/packages/ui-vue/components/table/index.ts b/packages/ui-vue/components/table/index.ts index 7eaf7936d77bb2204e7e5069c11a19c8651bca41..a948e70652d80733f5fce49241ac17e2cbd0c7e3 100644 --- a/packages/ui-vue/components/table/index.ts +++ b/packages/ui-vue/components/table/index.ts @@ -17,7 +17,7 @@ import type { App } from 'vue'; import FTable from './src/table.component'; import TableTd from './src/table-td.component'; import TableDesign from './src/designer/table.design.component'; -import { propsResolverGenerator, TableCellPropsResolver } from './src/table.props'; +import { propsResolverGenerator, TableCellPropsResolver, TableRowPropsResolver } from './src/table.props'; import { RegisterContext } from '../common'; import { createFormGroupEditorResolver, createTableTdBindingResolver } from '../dynamic-resolver'; @@ -44,6 +44,7 @@ export default { registerContext: RegisterContext): void { componentMap['table'] = TableDesign; propsResolverMap['table'] = propsResolverGenerator(registerContext); + propsResolverMap['table-row'] = TableRowPropsResolver; propsResolverMap['table-td'] = TableCellPropsResolver; } }; diff --git a/packages/ui-vue/components/table/src/components/context-menu.component.tsx b/packages/ui-vue/components/table/src/components/context-menu.component.tsx index a9ee806ffa42ec4b1056a5045451f6dacb493e7d..2dd4ca40de40dabf212a709d8b27d521537a6578 100644 --- a/packages/ui-vue/components/table/src/components/context-menu.component.tsx +++ b/packages/ui-vue/components/table/src/components/context-menu.component.tsx @@ -44,7 +44,7 @@ export default defineComponent({ const displayPos = ref({ x: 0, y: 0 }); const doAdjust = () => { - if (!menuRef.value) return; + if (!menuRef.value) { return; }; const menu = menuRef.value; const rect = menu.getBoundingClientRect(); const vpW = window.innerWidth; diff --git a/packages/ui-vue/components/table/src/composition/common.ts b/packages/ui-vue/components/table/src/composition/common.ts index 683fbb75ff5de23b1ca96cd82d05987623409460..d2f1a8a1710732013774e62759f697c1a1552e0b 100644 --- a/packages/ui-vue/components/table/src/composition/common.ts +++ b/packages/ui-vue/components/table/src/composition/common.ts @@ -54,4 +54,4 @@ export class TableUtils { }); return !!target; } -} \ No newline at end of file +} diff --git a/packages/ui-vue/components/table/src/composition/td-factory.ts b/packages/ui-vue/components/table/src/composition/td-factory.ts index 11fd1b74baa51bb778dafadd940bdcdf988cac15..da5af975b630fbd223f23de92d64a8df2facb19a 100644 --- a/packages/ui-vue/components/table/src/composition/td-factory.ts +++ b/packages/ui-vue/components/table/src/composition/td-factory.ts @@ -1,15 +1,15 @@ import { TableCell, TableRow } from './types'; +import { getSchemaByType } from "@farris/ui-vue/components/dynamic-resolver"; /** 与 Angular `new IdService().generate()` 等价的唯一 id 生成。 */ export function generateId(): string { return 'x' + Math.random().toString(36).slice(2, 10) + Date.now().toString(36).slice(-4); } -/** 对齐 Angular `TableTdSchema` 的默认单元格(等价 cloneDeep(TableTdSchema) + 新 id)。 */ export function createTableTdMetadata(): TableCell { - return { - id: generateId(), - type: 'table-td', + const tdMetadata = getSchemaByType('table-td') as TableCell; + return Object.assign({}, tdMetadata, { + id: `td_${generateId()}`, tdType: 'editor', staticText: { text: '', require: false }, editor: { type: null }, @@ -17,10 +17,9 @@ export function createTableTdMetadata(): TableCell { colspan: 1, rowspan: 1, align: 'right', - valign: 'top', - appearance: { class: 'farris-group-wrap--input', style: '' }, - size: null - }; + valign: 'middle', + appearance: { class: 'farris-group-wrap--input', style: '' } + }); } /** 生成默认 R×C 稠密网格(全部为独立锚点,markCol/markRow 缺省即视为 0)。 */ @@ -29,7 +28,7 @@ export function createDefaultTableRows(rowCount: number, colCount: number): Tabl for (let r = 0; r < rowCount; r++) { const columns: TableCell[] = []; for (let c = 0; c < colCount; c++) { columns.push(createTableTdMetadata()); } - rows.push({ id: generateId(), type: 'table-row', columns }); + rows.push({ id: `tr_${generateId()}`, type: 'table-row', columns }); } return rows; } diff --git a/packages/ui-vue/components/table/src/composition/td-manager.spec.ts b/packages/ui-vue/components/table/src/composition/td-manager.spec.ts index 60a3f39215729a2420f118ad198154836740e0c7..ea882f94e76d9c8e563ccd977f64289584024bd5 100644 --- a/packages/ui-vue/components/table/src/composition/td-manager.spec.ts +++ b/packages/ui-vue/components/table/src/composition/td-manager.spec.ts @@ -28,7 +28,7 @@ function makeManager(rows: any[]) { formSchemaUtils: { getExpressions: () => [], getComponents: () => [], getControlsInCmpWidthBinding: () => [] }, messageBox: { question: (_m: string, _d: string, ok: () => void) => ok() } }; - const mgr = new TableTdManager({ id: 't', rows }, services, redraw, canvas); + const mgr = new TableTdManager({ id: 't', rows }, services, redraw, canvas, 'test-vm-id'); return { mgr, redraw, canvas }; } diff --git a/packages/ui-vue/components/table/src/composition/td-manager.ts b/packages/ui-vue/components/table/src/composition/td-manager.ts index 474b318bf7753ad414e27f0251bdde679d6438fb..78e6f4787537b39272c117b798210aec37f48024 100644 --- a/packages/ui-vue/components/table/src/composition/td-manager.ts +++ b/packages/ui-vue/components/table/src/composition/td-manager.ts @@ -105,8 +105,7 @@ export class TableTdManager { // ===== Merge right ===== showMergeColumnToRight(): boolean { - const rowspan = this.targetColumn.rowspan; - const colspan = this.targetColumn.colspan; + const { rowspan, colspan } = this.targetColumn; if (this.selectedColumnIndex + colspan < this.targetRow.columns.length) { const n = this.targetRow.columns[colspan + this.selectedColumnIndex]; if (!n.invisible && rowspan === n.rowspan) { return true; } @@ -178,8 +177,7 @@ export class TableTdManager { return this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex].colspan > 1; } splitColumns() { - const colspan = this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex].colspan; - const rowspan = this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex].rowspan; + const { colspan, rowspan } = this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex]; for (let i = 0; i < colspan; i++) { this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex + i].invisible = false; this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex + i].colspan = 1; @@ -192,8 +190,7 @@ export class TableTdManager { return this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex].rowspan > 1; } splitRows() { - const colspan = this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex].colspan; - const rowspan = this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex].rowspan; + const { colspan, rowspan } = this.component.rows[this.selectedRowIndex].columns[this.selectedColumnIndex]; for (let i = 0; i < rowspan; i++) { this.component.rows[this.selectedRowIndex + i].columns[this.selectedColumnIndex].invisible = false; this.component.rows[this.selectedRowIndex + i].columns[this.selectedColumnIndex].rowspan = 1; @@ -205,7 +202,7 @@ export class TableTdManager { // ===== Remove column ===== showRemoveColumn(): boolean { - const rows = this.component.rows; + const { rows } = this.component; if (rows[this.selectedRowIndex].columns.length > 1) { const t = rows[this.selectedRowIndex].columns[this.selectedColumnIndex].colspan; if (t === 1) { return true; } @@ -220,11 +217,10 @@ export class TableTdManager { } } confirmRemoveColumn() { - const rows = this.component.rows; + const { rows } = this.component; const deletedColumns: any[] = []; for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) { - const colspan = rows[rowIndex].columns[this.selectedColumnIndex].colspan; - const rowspan = rows[rowIndex].columns[this.selectedColumnIndex].rowspan; + const { colspan, rowspan } = rows[rowIndex].columns[this.selectedColumnIndex]; if (rows[rowIndex].columns[this.selectedColumnIndex].invisible) { const r = this.tableTdHelper.findPrevColIndex(rowIndex, this.selectedColumnIndex, rows); if (r !== this.selectedColumnIndex && rows[rowIndex].columns[r].colspan > 1) { @@ -255,7 +251,7 @@ export class TableTdManager { // ===== Remove row ===== showRemoveRow(): boolean { - const rows = this.component.rows; + const { rows } = this.component; if (rows.length > 1) { const t = rows[this.selectedRowIndex].columns[this.selectedColumnIndex].rowspan; if (t === 1) { return true; } @@ -276,7 +272,7 @@ export class TableTdManager { return false; } confirmRemoveRow() { - const rows = this.component.rows; + const { rows } = this.component; for (let e = 0; e < rows[this.selectedRowIndex].columns.length; e++) { const n = rows[this.selectedRowIndex].columns[e].rowspan; const o = rows[this.selectedRowIndex].columns[e].colspan; diff --git a/packages/ui-vue/components/table/src/composition/types.ts b/packages/ui-vue/components/table/src/composition/types.ts index c8af8462c3abb8e7db288eee90b494d395866386..5428cedf46b0c7a4bff58c5caf23ffc3c6a137ee 100644 --- a/packages/ui-vue/components/table/src/composition/types.ts +++ b/packages/ui-vue/components/table/src/composition/types.ts @@ -13,7 +13,6 @@ export interface TableCell { align: 'left' | 'center' | 'right'; valign: 'top' | 'middle' | 'bottom'; appearance: { class: string; style: string; }; - size?: any; // 合并区域内偏移量(锚点=0,0);缺省即视为 0 markRow?: number; markCol?: number; @@ -35,4 +34,4 @@ export interface TableSchema { font: { size: number; enableColor: boolean; color: string; family: string; }; appearance: { class: string; style: string; }; visible: boolean; -} \ No newline at end of file +} diff --git a/packages/ui-vue/components/table/src/designer/table.design.component.tsx b/packages/ui-vue/components/table/src/designer/table.design.component.tsx index f8b275b694080dccbede31b6b0fb249e7e95b086..021593bed1c774842f4a823f09842711ac01ee2a 100644 --- a/packages/ui-vue/components/table/src/designer/table.design.component.tsx +++ b/packages/ui-vue/components/table/src/designer/table.design.component.tsx @@ -19,7 +19,7 @@ export default defineComponent({ const elementRef = ref(); const designerHostService = inject('designer-host-service'); const designItemContext = inject('design-item-context') as DesignerItemContext; - const designViewModelUtils = designerHostService?.designViewModelUtils + const designViewModelUtils = designerHostService?.designViewModelUtils; const formSchemaUtils = designerHostService?.formSchemaUtils; const rules = useDesignerRulesForTable(designItemContext, designerHostService); const componentInstance = useDesignerComponent(elementRef, designItemContext, rules); @@ -64,7 +64,7 @@ export default defineComponent({ /** 清除设计器已有的选中状态 */ function clearCanvasSelection() { const panel = document.querySelector('.editorPanel'); - if (!panel) return; + if (!panel) { return; } panel.querySelectorAll('.dgComponentSelected').forEach( (el: Element) => el.classList.remove('dgComponentSelected') ); @@ -89,7 +89,6 @@ export default defineComponent({ (designItemContext as any).setupContext?.emit( 'selectionChange', 'table-td', cell, cid, buildCellComponentInstance(cell) ); - } function onCellMouseDown(evt: MouseEvent) { @@ -98,7 +97,7 @@ export default defineComponent({ function onDocMouseDown(evt: MouseEvent) { const panel = document.querySelector('.editorPanel'); - if (!panel || !panel.contains(evt.target as Node)) return; + if (!panel || !panel.contains(evt.target as Node)) { return; } if (elementRef.value && !elementRef.value.contains(evt.target as Node)) { selectedCellId.value = ''; } diff --git a/packages/ui-vue/components/table/src/designer/use-designer-rules.ts b/packages/ui-vue/components/table/src/designer/use-designer-rules.ts index db67b1abb0a668a86364904298348f5d3e295cae..c811e89040f675c5edf8759eab67c72b13c4e814 100644 --- a/packages/ui-vue/components/table/src/designer/use-designer-rules.ts +++ b/packages/ui-vue/components/table/src/designer/use-designer-rules.ts @@ -44,16 +44,16 @@ export function useDesignerRulesForTable( schema.rows.forEach(row => { if (row.columns?.length) { row.columns.forEach(cell => { - if (cell.tdType === 'editor' && cell.editor.type) { - const editorLabel = cell.editor.label || '单元格'; + if (cell.tdType === 'editor' && cell.editor?.type) { + const editorLabel = cell.editor?.label || '单元格'; controlBasicInfoMap.set(cell.id, { showName: editorLabel, parentPathName: `${tableName} > ${tableTdName} > ${editorLabel}` }); } - }) + }); } - }) + }); } } return { diff --git a/packages/ui-vue/components/table/src/designer/use-table-creator.ts b/packages/ui-vue/components/table/src/designer/use-table-creator.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d700ea6f1b923ae70f22b3de6b33b54f8e35694 --- /dev/null +++ b/packages/ui-vue/components/table/src/designer/use-table-creator.ts @@ -0,0 +1,201 @@ +import { ComponentBuildInfo } from "@farris/ui-vue/components/component"; +import { ComponentSchema, DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import { DynamicResolver } from "@farris/ui-vue/components/dynamic-resolver"; +import { generateId } from "../composition/td-factory"; +import { TableCell, TableSchema } from "../composition/types"; +import { FormSchemaEntityField } from "@farris/ui-vue/components/common/entity/entity-schema"; +const ROOT_VIEW_MODEL_ID = 'root-viewmodel'; + +export function useTableCreator( + resolver: DynamicResolver, + designerHostService: DesignerHostService) { + + const { + formSchemaUtils, + designViewModelUtils, + } = designerHostService; + + /** + * 添加viewModel节点 + */ + function createViewModelNode(buildInfo: ComponentBuildInfo): any { + const viewModelNode = { + id: `${buildInfo.componentId}-component-viewmodel`, + code: `${buildInfo.componentId}-component-viewmodel`, + name: buildInfo.componentName, + bindTo: buildInfo.bindTo, + parent: ROOT_VIEW_MODEL_ID, + fields: [], + commands: [], + states: [], + enableValidation: true + }; + return viewModelNode; + } + + function createComponentRefNode(buildInfo: ComponentBuildInfo): ComponentSchema { + const componentRefNodeTemplate = resolver.getSchemaByType('component-ref') as ComponentSchema; + const componentRefNode = Object.assign({}, componentRefNodeTemplate, { + id: `${buildInfo.componentId}-component-ref`, + component: `${buildInfo.componentId}-component`, + }); + return componentRefNode; + } + + function createLabelTd(field: FormSchemaEntityField | null): TableCell[] { + const tdTemplate = resolver.getSchemaByType('table-td') as ComponentSchema; + const td = Object.assign({}, tdTemplate, { + id: `td_${generateId()}`, + appearance: { + class: 'farris-group-wrap--label' + }, + tdType: 'staticText', + staticText: { + text: '', + require: false + } + }); + if (field) { + td.staticText.text = field.name; + td.staticText.require = field.require || false; + } + return [td as unknown as TableCell]; + } + + function createEditorTd(field: FormSchemaEntityField | null): TableCell[] { + const editorTdTemplate = resolver.getSchemaByType('table-td') as ComponentSchema; + const controlCreatorUtils = designerHostService?.controlCreatorUtils; + if (!controlCreatorUtils) { + return []; + } + // 可编辑单元格 + const editorTd = Object.assign({}, editorTdTemplate, { + id: `td_${generateId()}`, + appearance: { + class: 'farris-group-wrap--input' + }, + colspan: 2, + tdType: 'editor', + editor: { + type: null, + binding: null + } + }); + // 可编辑单元格 + if (field) { + const formGroupSchema = controlCreatorUtils.setFormFieldProperty(field); + Object.assign(editorTd, { + editorLabel: field.name, + editor: formGroupSchema?.editor, + binding: formGroupSchema?.binding, + path: formGroupSchema?.path + }); + } + + + // 隐藏单元格 + const invisibleTdTemplate = resolver.getSchemaByType('table-td') as ComponentSchema; + const invisibleTd = Object.assign({}, invisibleTdTemplate, { + id: `td_${generateId()}`, + invisible: true, + markCol: 1, + markRow: 0 + }); + return [editorTd as unknown as TableCell, invisibleTd as unknown as TableCell]; + } + + function resolveTableColumns(selectedFields: FormSchemaEntityField[], table: TableSchema) { + table.rows = []; + + // 计算table行数(向上取整) + const rowCounts = Math.ceil(selectedFields.length / 2); + + for (let rowIndex = 0, fieldCount = 0; rowIndex < rowCounts; rowIndex++) { + let columns: TableCell[] = []; + for (let index = 0; index < 2; index++) { + const field = fieldCount < selectedFields.length ? selectedFields[fieldCount] : null; + const labelTds = createLabelTd(field); + const editorTds = createEditorTd(field); + columns = columns.concat(labelTds).concat(editorTds); + + fieldCount++; + } + + table.rows.push({ + id: `tr_${generateId()}`, + type: 'table-row', + columns + }); + } + } + /** + * 创建table组件内层级结构 + */ + function createTableComponentContents(buildInfo: ComponentBuildInfo) { + const tableTemplate = resolver.getSchemaByType('table') as ComponentSchema; + const sectionTemplate = resolver.getSchemaByType('section') as ComponentSchema; + const responseFormTemplate = resolver.getSchemaByType('response-form') as ComponentSchema; + + const table = Object.assign({}, tableTemplate) as TableSchema; + resolveTableColumns(buildInfo.selectedFields || [], table); + + Object.assign(table, { + id: buildInfo.componentId, + appearance: { + class: 'table table-bordered f-table-has-form' + } + }); + const responseForm = Object.assign({}, responseFormTemplate, { + id: buildInfo.componentId + '-form', + appearance: { + class: 'f-form-layout farris-form f-form-is-table' + }, + contents: [table] + }); + const section = Object.assign({}, sectionTemplate, { + id: buildInfo.componentId + '-section', + appearance: { + class: 'f-section-oa-table f-section-in-mainsubcard' + }, + showHeader: false, + contents: [responseForm] + }); + + + return [section]; + } + + function createComponentNode(buildInfo: ComponentBuildInfo): ComponentSchema { + const componentNodeTemplate = resolver.getSchemaByType('component') as ComponentSchema; + const contents = createTableComponentContents(buildInfo); + + const componentNode = Object.assign({}, componentNodeTemplate, { + id: `${buildInfo.componentId}-component`, + viewModel: `${buildInfo.componentId}-component-viewmodel`, + componentType: buildInfo.componentType, + contents, + appearance: { + class: 'f-struct-wrapper' + } + }); + return componentNode; + } + + function createComponent(buildInfo: ComponentBuildInfo) { + const componentRefNode = createComponentRefNode(buildInfo); + + const componentNode = createComponentNode(buildInfo); + + const viewModelNode = createViewModelNode(buildInfo); + + const formSchema = formSchemaUtils.getFormSchema(); + formSchema.module.viewmodels.push(viewModelNode); + formSchema.module.components.push(componentNode); + + designViewModelUtils.assembleDesignViewModel(); + + return componentRefNode; + } + + return { createComponent }; +} diff --git a/packages/ui-vue/components/table/src/property-config/converter/border-converter.ts b/packages/ui-vue/components/table/src/property-config/converter/border-converter.ts index bd1f6b2120832d66cbf3b0fb4e28e7cf5da24d4b..b06f36c50ce6e73e285eb0145e2db2fd61015970 100644 --- a/packages/ui-vue/components/table/src/property-config/converter/border-converter.ts +++ b/packages/ui-vue/components/table/src/property-config/converter/border-converter.ts @@ -3,7 +3,7 @@ import { ComponentSchema, PropertyConverter, SchemaService } from "@farris/ui-vu export default { convertTo: (schema: ComponentSchema, propertyKey: string, propertyValue: any, schemaService: SchemaService) => { if (!schema.border) { - schema.border = {}; + schema.border = { width: 1, enableColor: false, color: '#eaecf3' }; } schema.border[propertyKey] = propertyValue; }, diff --git a/packages/ui-vue/components/table/src/property-config/converter/font-converter.ts b/packages/ui-vue/components/table/src/property-config/converter/font-converter.ts index 7c17d9a966cd7629eb0c96b1c3e7feae76aedbcd..15e6dd18976d09ab438ff906839ed1ed920d911b 100644 --- a/packages/ui-vue/components/table/src/property-config/converter/font-converter.ts +++ b/packages/ui-vue/components/table/src/property-config/converter/font-converter.ts @@ -3,7 +3,7 @@ import { ComponentSchema, PropertyConverter, SchemaService } from "@farris/ui-vu export default { convertTo: (schema: ComponentSchema, propertyKey: string, propertyValue: any, schemaService: SchemaService) => { if (!schema.font) { - schema.font = {}; + schema.font = { size: 13, enableColor: false, color: '#2d2f33', family: 'sans-serif' }; } schema.font[propertyKey] = propertyValue; }, diff --git a/packages/ui-vue/components/table/src/property-config/table-td.property-config.ts b/packages/ui-vue/components/table/src/property-config/table-td.property-config.ts index ddebe5a9d721e427dcce10fe3aeb1cb9d1ef9ba5..2bd945146bf40210846a89a5ac01019ccd3e3a31 100644 --- a/packages/ui-vue/components/table/src/property-config/table-td.property-config.ts +++ b/packages/ui-vue/components/table/src/property-config/table-td.property-config.ts @@ -147,7 +147,9 @@ export class TableTdProperty extends InputBaseProperty { */ private getEditorBindingAndTypePropConfig(cell: any) { const self = this; - + if (cell.tdType !== 'editor') { + return; + } const { canChangeControlType, editorTypeList } = this.getAvailableEditorType(cell); this.propertyConfig.categories['tableTdEditor_editorBinding'] = { @@ -205,10 +207,7 @@ export class TableTdProperty extends InputBaseProperty { setPropertyRelates(changeObject: FormPropertyChangeObject, propData, parameters) { switch (changeObject.propertyID) { case 'binding': { - // 变更字段类型:修改原控件DOM结构 self.changeControlAfterBindingChanged(changeObject, cell, parameters); - // 编辑器内自动为cell赋值Binding,但是td的binding是存在cell.editor.binding的,所以这里单独删除一份 - // delete cell.binding; // 刷新实体树 changeObject.needRefreshEntityTree = true; break; @@ -233,7 +232,9 @@ export class TableTdProperty extends InputBaseProperty { } - + /** + * 切换绑定后,需要更新控件结构 + */ private changeControlAfterBindingChanged(changeObject: FormPropertyChangeObject, propertyData: any, parameters: any) { // 清除绑定:触发界面更新 @@ -242,9 +243,9 @@ export class TableTdProperty extends InputBaseProperty { propertyData.editor = { type: null, binding: null }; return; } - const fieldTypeChanged = parameters?.fieldTypeChanged + const fieldTypeChanged = parameters?.fieldTypeChanged; // 若变更字段类型,或新绑定字段,则走新建控件逻辑 - if (fieldTypeChanged || !propertyData.editor.type) { + if (fieldTypeChanged || !propertyData.editor?.type) { const bindingType = changeObject.propertyValue.type; const newEditorInfo = this.createControl(bindingType, parameters); if (newEditorInfo) { @@ -255,16 +256,13 @@ export class TableTdProperty extends InputBaseProperty { changeObject['controlEditorChanged'] = true; } else { - // 没有变更字段类型:不需要清除原控件结构,只需要同步更新path属性和帮助相关属性 // 没有变更字段类型,只同步单元格文本即可 propertyData.editorLabel = parameters.name; - // this.updateControlDomAfterChangingBinding(changeObject, propertyData.editor, parameters, viewModelId); } - - // 切换绑定信息后,需要使用新字段的受控规则 - } - + /** + * 创建新控件 + */ private createControl(bindingType: string, selectedField: any, editorType?: string, oldEditor?: any) { let newControl; if (!bindingType) { @@ -274,8 +272,7 @@ export class TableTdProperty extends InputBaseProperty { if (bindingType === FormBindingType.Form) { newControl = this.controlCreatorUtils.setFormFieldProperty(selectedField, editorType); } else { - // 暂不支持变量 - // newEditor = this.controlCreatorUtils.create(selectedField, editorType, this.componentId); + newControl = this.controlCreatorUtils.createFormGroupWithVariable(selectedField, editorType, '', this.componentId); } @@ -393,7 +390,7 @@ export class TableTdProperty extends InputBaseProperty { const eventConfig = this.editorTypeConfig.getEventPropertyConfig(cell); if (eventConfig) { // 过滤掉 onClickLabel 事件 - const properties = eventConfig.properties; + const { properties } = eventConfig; if (properties) { Object.values(properties).forEach((prop: any) => { if (prop?.editor?.initialData?.getEventList) { @@ -402,7 +399,7 @@ export class TableTdProperty extends InputBaseProperty { const originalResult = originalGetEventList(); const filteredEvents = (originalResult.events || []).filter((item: any) => item.label !== 'onClickLabel'); return { ...originalResult, events: filteredEvents }; - } + }; } }); } diff --git a/packages/ui-vue/components/table/src/property-config/table.property-config.ts b/packages/ui-vue/components/table/src/property-config/table.property-config.ts index 4c7d684abd003e865412f4927a93770bb85ef2a9..afbcf3c4dc871249f8c574d5dd6c1b7fdcb39add 100644 --- a/packages/ui-vue/components/table/src/property-config/table.property-config.ts +++ b/packages/ui-vue/components/table/src/property-config/table.property-config.ts @@ -29,13 +29,12 @@ export class TableProperty extends BaseControlProperty { type: 'boolean', description: '', refreshPanelAfterChanged: true - }, color: { title: '自定义颜色', type: 'string', description: '统一设置表格边框颜色', - visible: propertyData.border?.enableColor + visible: !!propertyData.border?.enableColor } } }; @@ -63,7 +62,7 @@ export class TableProperty extends BaseControlProperty { title: '自定义颜色', type: 'string', description: '设置字体框颜色', - visible: propertyData.font?.enableColor + visible: !!propertyData.font?.enableColor }, family: { title: '字体', diff --git a/packages/ui-vue/components/table/src/schema/schema-resolver.ts b/packages/ui-vue/components/table/src/schema/schema-resolver.ts index 2347a870dc00c3d0b932abc60fa226d5e45799ab..b6c74a76f5def9327f3e26fb32ca7213276976c7 100644 --- a/packages/ui-vue/components/table/src/schema/schema-resolver.ts +++ b/packages/ui-vue/components/table/src/schema/schema-resolver.ts @@ -1,9 +1,32 @@ import { DynamicResolver } from '@farris/ui-vue/components/dynamic-resolver'; -import { createDefaultTableRows } from '../composition/td-factory'; +import { DesignerComponentInstance, DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; +import { ComponentBuildInfo } from "@farris/ui-vue/components/component"; +import { useTableCreator } from '../designer/use-table-creator'; +import { generateId } from '../composition/td-factory'; -export function schemaResolver(resolver: DynamicResolver, schema: Record, context: Record): Record { - if (!schema.rows || schema.rows.length === 0) { - schema.rows = createDefaultTableRows(2, 2); +export function schemaResolver( + resolver: DynamicResolver, + schema: Record, + context: Record, + designerHostService?: DesignerHostService): Record { + const parentComponentInstance = context.parentComponentInstance as DesignerComponentInstance; + if (parentComponentInstance && designerHostService) { + const randomNumber = generateId(); + const componentBuildInfo: ComponentBuildInfo = { + componentId: `table-${randomNumber}`, + componentName: context.bindingSourceContext?.entityTitle || context.bindingSourceContext?.bindingEntity?.name || `表格-${randomNumber}`, + componentType: 'table', + parentContainerId: parentComponentInstance.schema.id, + parentComponentInstance: parentComponentInstance, + bindTo: context.bindingSourceContext?.bindTo || '', + dataSource: context.bindingSourceContext?.bindingEntity?.label, + selectedFields: context.bindingSourceContext?.bindingEntityFields + }; + const { createComponent } = useTableCreator(resolver, designerHostService); + const componentRefNode = createComponent(componentBuildInfo); + + return componentRefNode; + } else { + return schema; } - return schema; } diff --git a/packages/ui-vue/components/table/src/schema/table-row.schema.json b/packages/ui-vue/components/table/src/schema/table-row.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..50f2e8f59e8be15d2b38c40ea574e14efa750973 --- /dev/null +++ b/packages/ui-vue/components/table/src/schema/table-row.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://farris-design.gitee.io/table-row.schema.json", + "title": "table-row", + "description": "A Farris design-time layout table row", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "default": "table-row" + }, + "columns": { + "type": "array", + "default": [] + } + }, + "required": [ + "id", + "type", + "columns" + ] +} \ No newline at end of file diff --git a/packages/ui-vue/components/table/src/schema/table-td.schema.json b/packages/ui-vue/components/table/src/schema/table-td.schema.json index 33f95187098241f6f4f2de32d2a3f84f790d801a..66864a725b76a1513325799b6470e31e713f3c4d 100644 --- a/packages/ui-vue/components/table/src/schema/table-td.schema.json +++ b/packages/ui-vue/components/table/src/schema/table-td.schema.json @@ -10,7 +10,7 @@ }, "type": { "type": "string", - "default": "" + "default": "table-td" }, "tdType": { "type": "string", @@ -23,12 +23,9 @@ "type": "string" }, "require": { - "type": "boolean" + "type": "boolean", + "default": false } - }, - "default": { - "text": "", - "require": false } }, "editor": { @@ -39,13 +36,7 @@ "string", "null" ] - }, - "id": { - "type": "string" } - }, - "default": { - "type": null } }, "binding": { @@ -87,9 +78,6 @@ "style": "" } }, - "size": { - "type": "object" - }, "markRow": { "type": "number", "default": 0 @@ -122,7 +110,11 @@ }, "required": [ "id", - "type" + "type", + "colspan", + "rowspan", + "align", + "valign" ], "events": { "onExpandClick": "扩展按钮点击事件", diff --git a/packages/ui-vue/components/table/src/schema/table.schema.json b/packages/ui-vue/components/table/src/schema/table.schema.json index b6fa750e862cfbf33970bb9bff75a47b32c802db..12f0dfc937dc9f0319db3cce886d7701a0dfc100 100644 --- a/packages/ui-vue/components/table/src/schema/table.schema.json +++ b/packages/ui-vue/components/table/src/schema/table.schema.json @@ -32,42 +32,38 @@ "type": "object", "properties": { "width": { - "type": "number" + "type": "number", + "default": 1 }, "enableColor": { - "type": "boolean" + "type": "boolean", + "default": false }, "color": { - "type": "string" + "type": "string", + "default": "#eaecf3" } - }, - "default": { - "width": 1, - "enableColor": false, - "color": "#eaecf3" } }, "font": { "type": "object", "properties": { "size": { - "type": "number" + "type": "number", + "default": 13 }, "enableColor": { - "type": "boolean" + "type": "boolean", + "default": false }, "color": { - "type": "string" + "type": "string", + "default": "#2d2f33" }, "family": { - "type": "string" + "type": "string", + "default": "sans-serif" } - }, - "default": { - "size": 13, - "enableColor": false, - "color": "#2d2f33", - "family": "sans-serif" } }, "rows": { diff --git a/packages/ui-vue/components/table/src/table.props.ts b/packages/ui-vue/components/table/src/table.props.ts index 0bc0f6fdac89a4af75202a327b34ebeda1f93423..cf8c7eb28795c8a45b26bb74cefd865d1ff8dec8 100644 --- a/packages/ui-vue/components/table/src/table.props.ts +++ b/packages/ui-vue/components/table/src/table.props.ts @@ -3,8 +3,9 @@ import { createPropsResolver, getPropsResolverGenerator } from '@farris/ui-vue/c import { schemaMapper } from './schema/schema-mapper'; import tableSchema from './schema/table.schema.json'; import tableCellSchema from './schema/table-td.schema.json'; +import tableRowSchema from './schema/table-row.schema.json'; import { schemaResolver } from './schema/schema-resolver'; -import { TableCellEditor, TableCellStaticText, TableRow } from './composition/types'; +import { TableCell, TableCellEditor, TableCellStaticText, TableRow } from './composition/types'; export const tableProps = { @@ -25,7 +26,6 @@ export type TablePropsType = ExtractPropTypes; export const propsResolver = createPropsResolver(tableProps, tableSchema, schemaMapper, schemaResolver); export const propsResolverGenerator = getPropsResolverGenerator(tableProps, tableSchema, schemaMapper, schemaResolver); - export const tableCellProps = { id: { type: String, default: '' }, type: { type: String, default: '' }, @@ -52,3 +52,14 @@ export const tableCellProps = { export type TableCellProps = ExtractPropTypes; export const TableCellPropsResolver = createPropsResolver(tableCellProps, tableCellSchema, schemaMapper, schemaResolver); + + +export const tableRowProps = { + id: { type: String, default: '' }, + type: { type: String, default: '' }, + columns: { type: Array as PropType, default: () => [] } +} as Record; + + +export type TableRowProps = ExtractPropTypes; +export const TableRowPropsResolver = createPropsResolver(tableRowProps, tableRowSchema, schemaMapper, schemaResolver);