diff --git a/package.json b/package.json index 3369ab02aee2a426325e38cf0826cae5538a3aee..80c88b1565504f11bccfc70fc03c29e9562ce815 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "fs-extra": "^11.2.0", "happy-dom": "^14.12.0", "highlight.js": "^11.9.0", - "husky": "^8.0.0", + "husky": "^9.0.0", "inquirer": "^9.1.1", "intersection-observer": "^0.12.2", "jest": "^29.0.0", diff --git a/packages/designer/public/assets/monaco-editor.config.json b/packages/designer/public/assets/monaco-editor.config.json index dde50999239004911e6aeef730f300c77e210b60..1eb1ac541b0bff178a8d0ad443183028d7e46c14 100644 --- a/packages/designer/public/assets/monaco-editor.config.json +++ b/packages/designer/public/assets/monaco-editor.config.json @@ -1,3 +1,3 @@ { "vsPath": "/platform/common/web/monaco/vs" -} \ No newline at end of file +} diff --git a/packages/designer/public/assets/rtc/property-rule.json b/packages/designer/public/assets/rtc/property-rule.json new file mode 100644 index 0000000000000000000000000000000000000000..9b7ec226647621e09d95ca543d4a43ac28c3d3f2 --- /dev/null +++ b/packages/designer/public/assets/rtc/property-rule.json @@ -0,0 +1,383 @@ +{ + "form-group": [ + "id", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "label", + "binding", + "responseLayout" + ], + "input-group": [ + "type", + "readonly", + "required", + "placeholder", + "maxLength" + ], + "number-spinner": [ + "type", + "readonly", + "required", + "placeholder", + "textAlign", + "max", + "min", + "step", + "precision" + ], + "textarea": [ + "type", + "readonly", + "required", + "placeholder", + "resizable" + ], + "date-picker": [ + "type", + "readonly", + "required", + "placeholder", + "maxDate", + "minDate", + "showTime", + "displayFormat" + ], + "time-picker": [ + "type", + "readonly", + "required", + "placeholder", + "editable", + "format", + "showHeader", + "use12Hours", + "hourStep", + "minuteStep", + "secondStep" + ], + "lookup": [ + "type", + "readonly", + "required", + "enableTitle", + "dataSource", + "displayType", + "textField", + "mappingFields", + "enableToSelect", + "multiSelect", + "filterConditions", + "showSelections", + "displayType", + "dialog.title", + "dialog.width", + "dialog.height", + "dialog.navigatorWidth", + "dialog.draggable", + "dialog.resizeable", + "dialog.showMaxButton", + "events.clear", + "events.dictPicking", + "events.beforeSelectData", + "events.dictPicked", + "events.beforeLoadData" + ], + "check-box": [ + "type", + "readonly", + "required", + "type" + ], + "check-group": [ + "type", + "readonly", + "required", + "data", + "direction", + "textField", + "valueField" + ], + "combo-list": [ + "type", + "readonly", + "required", + "data", + "textField", + "valueField", + "maxLength" + ], + "radio-group": [ + "type", + "readonly", + "required", + "data", + "textField", + "valueField", + "direction" + ], + "switch": [ + "type", + "readonly", + "required", + "square", + "onLabel", + "offLabel", + "onBackground", + "offBackground", + "size" + ], + "page-header": [ + "id", + "type", + "appearance", + "appearance.style", + "appearance.class", + "icon", + "title", + "visible" + ], + "data-grid": [ + "id", + "type", + "dataSource", + "columns", + "showStripe", + "showBorder", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "rowNumber.enable", + "rowNumber.width", + "rowNumber.heading", + "visible", + "onSelectionChange" + ], + "data-grid-column": [ + "id", + "visible", + "title", + "resizable", + "halign", + "align", + "valign", + "hAlign" + ], + "tree-grid": [ + "id", + "type", + "dataSource", + "columns", + "fit", + "appearance", + "appearance.style", + "appearance.class", + "showStripe", + "showBorder", + "striped", + "onSelectionChange" + ], + "tree-grid-column": [ + "id", + "visible", + "title", + "resizable", + "halign", + "align", + "valign", + "hAlign" + ], + "response-toolbar-item": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "icon", + "onClick", + "tipsEnable", + "tipsText", + "text", + "disabled" + ], + "response-toolbar": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class" + ], + "component": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "name", + "onInit", + "onAfterViewInit" + ], + "content-container": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class" + ], + "external-container": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "externalComponent", + "onCommunication" + ], + "fieldset": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "title" + ], + "response-form": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "labelAutoOverflow", + "unifiedLayout" + ], + "html-template": [ + "id", + "type", + "html" + ], + "list-nav": [ + "id", + "type", + "appearance", + "appearance.style", + "appearance.class", + "size.width", + "size.height", + "visible" + ], + "section": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "showHeader", + "fill", + "mainTitle", + "subTitle", + "expandStatus", + "enableAccordion", + "contentClass" + ], + "section-toolbar-item": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "icon", + "onClick", + "text", + "disabled" + ], + "splitter": [ + "id", + "visible", + "type", + "appearance", + "appearance.style", + "appearance.class" + ], + "tabs": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "titleWidth", + "fill", + "autoTitleWidth", + "activeId" + ], + "tab-page": [ + "id", + "type", + "show", + "appearance", + "appearance.style", + "appearance.class", + "title", + "disabled", + "customTitleClass", + "tabWidth", + "toolbarPosition" + ], + "tab-toolbar-item": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "icon", + "onClick", + "text", + "disabled" + ], + "uploader": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class" + ], + "query-solution": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "isControlInline", + "presetQuerySolutionName", + "filterText", + "expanded", + "fields", + "presetFields", + "onQuery" + ], + "filter-bar": [ + "id", + "type", + "visible", + "appearance", + "appearance.style", + "appearance.class", + "fields", + "resetText", + "onQuery" + ] +} \ No newline at end of file diff --git a/packages/designer/public/assets/template-rules/common.json b/packages/designer/public/assets/template-rules/common.json index 66d8bf5e1b79a9228bfb8b2c75077ee1d2459744..ce6bf7c6710fd46ca30b98419b4bff1ca75296ae 100644 --- a/packages/designer/public/assets/template-rules/common.json +++ b/packages/designer/public/assets/template-rules/common.json @@ -407,15 +407,7 @@ "description": "分栏面板导航区域(左侧)", "canMove": false, "canDelete": false, - "canAccept": { - "invalidContext": [ - { - "parent": { - "type": "splitter" - } - } - ] - } + "canAccept": true }, "f-page-content-main": { "description": "分栏面板主区域(右侧)", diff --git a/packages/designer/src/components/components/entity-tree-view/components/create-new-entity.component.tsx b/packages/designer/src/components/components/entity-tree-view/components/create-new-entity.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2f0cb13059c0b4d180193e7ee42e7b3c2f232222 --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/components/create-new-entity.component.tsx @@ -0,0 +1,113 @@ +import { FNotifyService } from '@farris/ui-vue/components'; +import axios from 'axios'; +import { defineComponent, SetupContext } from 'vue'; +import { CreateNewEntityProps, createNewEntityProps } from './entity-tree-view.props'; +import { resolvePresetFields } from '../composition/preset-entity-fields'; +import { IdService } from '../../view-model-designer/method-manager/service/id.service'; + +/** + * 新建子实体 + */ +export default defineComponent({ + name: 'FCreateNewEntity', + props: createNewEntityProps, + emits: ['cancel', 'submit'] as (string[] & ThisType) | undefined, + setup(props: CreateNewEntityProps, context: SetupContext) { + const notifyService: any = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + + const entityInfo = { id: '', code: '', name: '' }; + function onCancel() { + context.emit('cancel'); + } + + function checkValidation() { + if (!entityInfo.code) { + notifyService.warning('请填写实体编号!'); + return; + } + if (!entityInfo.name) { + notifyService.warning('请填写实体名称!'); + return; + } + if (props.existedEntityCodes) { + const lowerEntityCodes = props.existedEntityCodes.map(code => code.toLowerCase()); + if (lowerEntityCodes.includes(entityInfo.code.toLowerCase())) { + notifyService.warning('编号已存在,请重新输入。'); + return; + } + } + + return true; + } + function getValidEntityLabel() { + const voId = props.useFormSchema.getSchemas().id; + const formBasicInfo = props.useFormSchema.getFormMetadataBasicInfo(); + const dimension1 = formBasicInfo.dimension1 || ''; + const dimension2 = formBasicInfo.dimension2 || ''; + const url = `/api/runtime/bcc/v1.0/template/newTableLabel?voId=${voId}&tableCode=${entityInfo.code}&dim1=${dimension1}&dim2=${dimension2}`; + return axios.get(url); + } + function onSubmit() { + if (!checkValidation()) { + return; + } + getValidEntityLabel().then(result => { + if (!result?.data) { + notifyService.warning('编号已存在,请重新输入。'); + return; + } + Object.assign(entityInfo, { + id: new IdService().generate(), + label: result.data, + type: { + name: entityInfo.code, + primary: 'id', + fields: resolvePresetFields(), + entities: [], + displayName: entityInfo.name + } + }); + + context.emit('submit', entityInfo); + }, () => { + notifyService.console.error('获取子实体Label属性失败'); + }); + + } + return () => { + return
+
+
+
+ +
+ +
+
+
+ +
+
+ +
+ +
+
+
+ +
+ +
; + }; + + + } +}); diff --git a/packages/designer/src/components/components/entity-tree-view/components/create-new-field.component.tsx b/packages/designer/src/components/components/entity-tree-view/components/create-new-field.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b264bbac1dd25449e0c3228c57e06f9ed0ccecd2 --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/components/create-new-field.component.tsx @@ -0,0 +1,185 @@ +import { FLoadingService, FNotifyService } from '@farris/ui-vue'; +import { defineComponent, inject, ref, SetupContext, computed, onMounted } from 'vue'; +import { ExtendFieldEntity, FieldTypeEnums } from '../composition/extend-field'; +import { CreateNewFieldProps, createNewFieldProps } from './entity-tree-view.props'; +import { FComboList, FNumberSpinner, FSwitch, FSchemaSelectorEditor, LookupSchemaRepositoryToken, FComboTree, VisualData } from '@farris/ui-vue/components'; +import { useNewFieldVerification } from '../composition/use-new-field-verification'; +import { useNewFieldUtil } from '../composition/use-new-field-util'; + +/** + * 新建字段 + */ +export default defineComponent({ + name: 'FCreateNewEntityField', + props: createNewFieldProps, + emits: ['cancel', 'submit'] as (any[] & ThisType) | undefined, + setup(props: CreateNewFieldProps, context: SetupContext) { + const notifyService: any = new FNotifyService(); + notifyService.globalConfig = { position: 'top-center' }; + const loadingService: any = inject('FLoadingService'); + + /** 新增字段实体 */ + const extendField = ref(new ExtendFieldEntity()); + const { isFieldNameExisted, checkFieldNameExisted, checkFieldCodeRegValid, + checkFieldCodeValid, fieldLabelMessage, isFieldLabelValid, checkFieldValidation } = useNewFieldVerification(props, extendField, notifyService); + const { onChangeFieldType, fieldObjectTypes, renderEnumValuesEditor, isLengthReadonly, isPrecisionReadonly, maxLength, maxPrecision, + resolveFieldInfo, helpMetadataName, onSubmitHelpMetadata, onHelpMetadataSelected, helpSchemaTreeData, relatedHelpFieldIds, + onHelpRelatedFieldsChanged, relatedFieldsTreeData, helpFieldId, onHelpBindingFieldsChanged } = useNewFieldUtil(props, extendField); + + + /** 字段标签行样式 */ + const fieldLabelSpanClass = computed(() => { + return { + 'farris-feedback': true, + 'f-state-valid': isFieldLabelValid.value, + 'f-state-invalid': !isFieldLabelValid.value, + 'position-relative': true, + }; + }); + + onMounted(() => { + + }); + function onCancel() { + context.emit('cancel'); + } + + function onSubmit() { + const loadingInstance = loadingService.show(); + if (!checkFieldValidation()) { + loadingInstance.value.close(); + return; + } + + checkFieldCodeValid().then(result => { + if (result) { + const newFieldInfo = resolveFieldInfo(); + context.emit('submit', newFieldInfo); + } + loadingInstance.value.close(); + + }, () => { + loadingInstance.value.close(); + }); + + } + + function renderEditor(title: string, editor: any, hideLabel = false) { + return
+
+ +
+ {editor} +
+
+
; + } + + /** 渲染帮助元数据的选择器 */ + function renderHelpMetadataSelector() { + const viewOptions = [{ id: 'total', title: '全部', type: 'List', dataSource: 'Total' }]; + const repositoryToken = LookupSchemaRepositoryToken; + const editorParams = { formBasicInfo: props.useFormSchema.getFormMetadataBasicInfo() }; + return + ; + } + + /** 设置帮助关联字段下拉树表格的行禁用 */ + const helpRelateTreeCustomRowStatus = (visualData: VisualData) => { + if (!visualData.raw.selectable) { + visualData.disabled = true; + } + return visualData; + }; + + /** 渲染帮助关联字段的选择器 */ + function renderHelpRelateSelector() { + return ; + } + + /** 渲染帮助绑定字段的选择器 */ + function renderHelpFieldSelector() { + return ; + } + + return () => { + return
+
+ {renderEditor('字段类型', + + )} + {renderEditor('字段名称', + <> + + {extendField.value.name && isFieldNameExisted.value && +
+ 名称已存在,请重新输入 +
} + )} + {renderEditor('字段编号', + + )} + {renderEditor('字段标签', +
+ {fieldLabelMessage.value} +
, + true + )} + + {(extendField.value.type === 'String' || extendField.value.type === 'Integer') && + renderEditor('对象类型', + + + ) + } + {extendField.value.objectType === 'Enum' && renderEditor('枚举数据', renderEnumValuesEditor())} + + {extendField.value.objectType !== 'Association' ? <> + {renderEditor('字段长度', + + + )} + {extendField.value.type === 'Decimal' && renderEditor('字段精度', + + + )} + {renderEditor('是否必填', + + )} + {renderEditor('是否只读', + + )} + : <> + {renderEditor('选择帮助', renderHelpMetadataSelector())} + {renderEditor('关联字段', renderHelpRelateSelector())} + {renderEditor('帮助绑定字段', renderHelpFieldSelector())} + + } + +
+ +
; + }; + } +}); diff --git a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx index 797537b2798204e7d4cb6d3477d05d2675fd4d45..84cb1663c33db8a5f7479607d06c5064c2d8f727 100644 --- a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx +++ b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.component.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { defineComponent, inject, ref, SetupContext, watch, nextTick } from 'vue'; +import { defineComponent, inject, ref, SetupContext, watch, nextTick, onMounted, Ref } from 'vue'; import { FButton } from '@farris/ui-vue/components'; import { FSearchBox } from "@farris/ui-vue/components"; import { FTreeView } from '@farris/ui-vue/components'; @@ -26,6 +26,9 @@ import '../composition/entity-tree-view.css'; import './entity-tree-view.scss'; import { RowOptions, VisualData } from '@farris/ui-vue/components'; import { FLoadingService } from '@farris/ui-vue/components'; +import { DesignerMode, UseDesignerContext } from '../../../../components/types/designer-context'; +import { useOpenNewEntity } from '../composition/use-new-entity'; +import { useOpenNewField } from '../composition/use-new-field-modal'; export default defineComponent({ name: 'FEntityTreeView', @@ -35,13 +38,18 @@ export default defineComponent({ const entityTreeRef = ref(); const dragularCompostion = ref(props.dragula); const useFormSchema: any = inject('useFormSchema'); - const { treeViewData, resolveEntityTreeData, assignExpandState, setTreeDraggable, appendTreeToDragulaContainer } = UseEntityTreeData(useFormSchema); const schemaService = inject('schemaService') as UseSchemaService; + const { treeViewData, resolveEntityTreeData, assignExpandState, setTreeDraggable, appendTreeToDragulaContainer, + existedEntityCodes, resolveRtcEntityTreeData, serializedTreeData } = UseEntityTreeData(useFormSchema, schemaService); const designViewModelUtils = inject('designViewModelUtils') as UseDesignViewModel; const controlCreatorUtils = inject('controlCreatorUtils') as UseControlCreator; const useUpdateEntitySchemaComposition = useUpdateEntitySchema(schemaService, useFormSchema, designViewModelUtils, controlCreatorUtils, context); const loadingService: FLoadingService | any = inject('FLoadingService'); + // 获取当前设计器运行环境 + const designerContext = inject('designerContext') as UseDesignerContext; + const designerMode = designerContext.designerMode as DesignerMode; + /** 原始实体数据 */ const entityData = ref(props.data.module?.entity); const columns = ref([{ field: 'name', title: '', dataType: 'string' }]); @@ -51,6 +59,8 @@ export default defineComponent({ unfold: 'f-icon f-icon-file-folder-open text-primary mr-1', leafnodes: 'f-icon f-icon-preview mr-1' }; + /** 当前新增加的实体编号集合,表单保存后清空集合。 */ + const newEntityCodeList: Ref = ref([]); /** 获取树表绑定数据 */ function getTreeViewData() { @@ -59,8 +69,12 @@ export default defineComponent({ } const oldTreeViewData = cloneDeep(treeViewData.value); treeViewData.value = []; + serializedTreeData.value = []; const mainEntity = entityData.value[0].entities[0]; - resolveEntityTreeData(mainEntity, 0, null); + existedEntityCodes.value = []; + treeViewData.value.push(resolveEntityTreeData(mainEntity, 0, null)); + + resolveRtcEntityTreeData(); assignExpandState(treeViewData.value, oldTreeViewData); } @@ -120,28 +134,49 @@ export default defineComponent({ setTreeDraggable(); }); } + + + onMounted(() => { + newEntityCodeList.value = []; + }); + const { openNewEntityModal } = useOpenNewEntity(useFormSchema, existedEntityCodes, refreshEntityTree, newEntityCodeList); + const { openNewFieldModal } = useOpenNewField(useFormSchema, newEntityCodeList, refreshEntityTree, treeViewData); + function renderHeader() { - return
- {/* */} -
- {/* - */} - -
-
; + if (designerMode !== DesignerMode.PC_RTC) { + return
+
+ +
+
; + } } return () => { return
- - {{ header: renderHeader }} + {{ + header: renderHeader, + cellTemplate: ({ cell, row }) => { + const rowData = row.raw; + return <> + {rowData.name} + {designerMode === DesignerMode.PC_RTC && row.raw.nodeType === 'entity' &&
+ openNewFieldModal(event, row.raw)}> + {!row.raw.parent && } +
+ } + ; + }, + }} +
-
; + ; }; } }); diff --git a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.props.ts b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.props.ts index 20d9236e70e5d88ac33c2f9d13ef6a4b749c23cf..1e321420472237a217c99461fec7d976680590fc 100644 --- a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.props.ts +++ b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.props.ts @@ -24,3 +24,24 @@ export const entityTreeProps = { } as Record; export type EntityTreeProps = ExtractPropTypes; + + +export const createNewEntityProps = { + useFormSchema: { type: Object }, + /** 当前已存在的实体编号 */ + existedEntityCodes: { type: Array } +} as Record; +export type CreateNewEntityProps = ExtractPropTypes; + + +export const createNewFieldProps = { + useFormSchema: { type: Object }, + /** 当前实体 */ + entityCode: { type: String }, + /** 当前实体中已有的字段 */ + existedAllFields: { type: Object }, + /** 当前实体是否为新建的子实体 */ + isNewEntity: { type: Boolean } +} as Record; +export type CreateNewFieldProps = ExtractPropTypes; + diff --git a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss index 0e161e53b83bb73bac5bda56483be0a26ebd05dc..58519e45e31b85e224ba9b5f41a3e955cb774bc6 100644 --- a/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss +++ b/packages/designer/src/components/components/entity-tree-view/components/entity-tree-view.scss @@ -1,17 +1,16 @@ .designer-schema-tree { .designer-schema-tree-header { - // display: flex; display: inline-block; position: absolute; right: 6px; top: 4px; + } - .toolbar-action { - color: rgb(199, 205, 220); - background: #0000; - height: 100%; - width: 26px; - padding: 0 !important; - } + .toolbar-action { + color: rgb(199, 205, 220); + background: #0000; + height: 100%; + width: 26px; + padding: 0 !important; } } \ No newline at end of file diff --git a/packages/designer/src/components/components/entity-tree-view/composition/extend-field.ts b/packages/designer/src/components/components/entity-tree-view/composition/extend-field.ts new file mode 100644 index 0000000000000000000000000000000000000000..c87ab5677a1b235fe8e220a7d9e6d41448dbfc65 --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/composition/extend-field.ts @@ -0,0 +1,146 @@ +import { IdService } from "../../view-model-designer/method-manager/service/id.service"; + +export enum ElementObjectType { + /** + * 未设置 + */ + None = "None", + /** + * 关联 + */ + Association = "Association", + /** + * 枚举 + */ + Enum = "Enum", + /** + * 动态属性 + */ + DynamicProp = "DynamicProp" +} +/** + * 字段数据类型 + */ +export enum ElementDataType { + /** + * 文本 + */ + String = "String", + /** + * 备注 + */ + Text = "Text", + /** + * 整数 + */ + Integer = "Integer", + /** + * 浮点数 + */ + Decimal = "Decimal", + /** + * 布尔型 + */ + Boolean = "Boolean", + /** + * 日期型 + */ + Date = "Date", + /** + * 日期时间型 + */ + DateTime = "DateTime", + /** + * 二进制 + */ + Binary = "Binary" +} +/** + * 枚举类型 + */ +export class EnumData { + public value: string = ''; + public name: string = ''; +} +export class ExtendFieldEntity { + // id + id: string = new IdService().generate(); + + // 字段编号 + code = ''; + + // 字段名称 + name = ''; + + label = ''; + + // 字段类型 + type = ElementDataType.String; + + // 是否只读 + readonly = false; + + // 是否必填 + require = false; + + // 关联 枚举类型 + objectType: ElementObjectType = ElementObjectType.None; + + // 字段长度 文本36 浮点18 其他0 + length = 36; + + // 字段精度 整数:0 浮点:2 + precision = 0; + + // 是否支持多语 + multiLanguage = false; + + // 枚举值 + enumValues?: EnumData[]; + + // 默认值 + defaultValue: any; + +} + +/** + * 字段类型 + */ +export const FieldTypeEnums = [ + { + value: ElementDataType.String, text: '文本' + }, + { + value: ElementDataType.Text, text: '备注' + }, + { + value: ElementDataType.Integer, text: '整数' + }, + { + value: ElementDataType.Decimal, text: '浮点数字' + }, + { + value: ElementDataType.Boolean, text: '布尔型' + }, + { + value: ElementDataType.Date, text: '日期' + }, + { + value: ElementDataType.DateTime, text: '日期时间' + } +]; + +/** + * 字段对象类型 + */ +export const FieldObjectTypeEnums = [ + { + value: ElementObjectType.None, text: '无' + }, + { + value: ElementObjectType.Enum, text: '枚举' + }, + { + value: ElementObjectType.Association, text: '关联' + } +]; diff --git a/packages/designer/src/components/components/entity-tree-view/composition/preset-entity-fields.ts b/packages/designer/src/components/components/entity-tree-view/composition/preset-entity-fields.ts new file mode 100644 index 0000000000000000000000000000000000000000..2cb209c120cf731f0f196f47efa26a28f001cacd --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/composition/preset-entity-fields.ts @@ -0,0 +1,56 @@ +import { IdService } from "../../view-model-designer/method-manager/service/id.service"; + +export function resolvePresetFields() { + const idService = new IdService(); + const idID = idService.generate(); + const parentIDID = idService.generate(); + + return [{ + $type: 'SimpleField', + id: idID, + originalId: idID, + code: 'ID', + name: 'ID', + label: 'id', + bindingField: 'id', + defaultValue: '', + require: true, + readonly: false, + type: { + $type: 'StringType', + name: 'String', + displayName: '字符串', + length: 36 + }, + editor: { + $type: 'TextBox' + }, + path: 'ID', + bindingPath: 'id', + multiLanguage: false + }, + { + $type: 'SimpleField', + id: parentIDID, + originalId: parentIDID, + code: 'ParentID', + name: 'ParentID', + label: 'parentID', + bindingField: 'parentID', + defaultValue: '', + require: true, + readonly: false, + type: { + $type: 'StringType', + name: 'String', + displayName: '字符串', + length: 36 + }, + editor: { + $type: 'TextBox' + }, + path: 'ParentID', + bindingPath: 'parentID', + multiLanguage: false + }]; +} diff --git a/packages/designer/src/components/components/entity-tree-view/composition/use-entity-tree-data.ts b/packages/designer/src/components/components/entity-tree-view/composition/use-entity-tree-data.ts index ef66b45f4d3c911b6b60ae6e5e65502579697f6a..b3b9a4294050f174949dfed80a7cb1de2cb17939 100644 --- a/packages/designer/src/components/components/entity-tree-view/composition/use-entity-tree-data.ts +++ b/packages/designer/src/components/components/entity-tree-view/composition/use-entity-tree-data.ts @@ -1,10 +1,17 @@ -import { FormSchemaEntity, FormSchemaEntityField, FormSchemaEntityField$Type, UseFormSchema } from "../../../types"; +import { FormSchemaEntity, FormSchemaEntityField, FormSchemaEntityField$Type, UseFormSchema, UseSchemaService } from "../../../types"; import { ref } from 'vue'; +import { DesignerMode } from "../../../types/designer-context"; +import { cloneDeep } from 'lodash-es'; -export function UseEntityTreeData(useFormSchema: UseFormSchema) { +export function UseEntityTreeData(useFormSchema: UseFormSchema, schemaService: UseSchemaService) { /** 树表绑定数据 */ const treeViewData: any = ref([]); + /** 平铺展示的树节点 */ + const serializedTreeData: any = ref([]); + + /** 当前实体编号集合 */ + const existedEntityCodes: any = ref([]); function getViewModelFieldsByEntity(entityPath: string): Map { const fieldsMap = new Map(); @@ -36,29 +43,31 @@ export function UseEntityTreeData(useFormSchema: UseFormSchema) { /** * 将实体内的字段组装为树结构 */ - function resolveFieldNodesInEntity(fields: FormSchemaEntityField[], layer: number, parentNode: any, treeData: any[] = [], occupiedFieldsMap: Map) { + function resolveFieldNodesInEntity(fields: FormSchemaEntityField[], parentNode: any, occupiedFieldsMap: Map) { + const treeData: any = []; fields.forEach(field => { const fieldTreeData = { data: field, id: field.id, - name: field.name, - layer, parent: parentNode && parentNode.id, - hasChildren: false, isOccupied: occupiedFieldsMap?.has(field.id), - collapse: false, - draggable: true + collapse: true, + draggable: true, + children: [] }; treeData.push(fieldTreeData); + serializedTreeData.value.push(fieldTreeData); + // 关联表字段 / UDT字段 if (field.type && field.type.fields && field.type.fields.length > 0) { - fieldTreeData.hasChildren = true; - fieldTreeData.collapse = true; + fieldTreeData.collapse = false; fieldTreeData.draggable = false; - resolveFieldNodesInEntity(field.type.fields, layer + 1, field, treeData, occupiedFieldsMap); + fieldTreeData.children = resolveFieldNodesInEntity(field.type.fields, field, occupiedFieldsMap); } }); + + return treeData; } /** @@ -66,43 +75,61 @@ export function UseEntityTreeData(useFormSchema: UseFormSchema) { */ function resolveEntityTreeData(entity: FormSchemaEntity, layer: number, parentNode: any, entityPath: string = '/') { const occupiedFieldsMap = getViewModelFieldsByEntity(entityPath); - const entityTreeData = { + const entityTreeData: any = { data: entity, id: entity.id, - name: entity.name, nodeType: 'entity', - layer, parent: parentNode && parentNode.id, - hasChildren: true, + children: [], entityPath, collapse: false, draggable: true }; - treeViewData.value.push(entityTreeData); + serializedTreeData.value.push(entityTreeData); + existedEntityCodes.value.push(entity.code); if (entity.type && entity.type.fields && entity.type.fields.length > 0) { - resolveFieldNodesInEntity(entity.type.fields, layer + 1, entity, treeViewData.value, occupiedFieldsMap); + entityTreeData.children = resolveFieldNodesInEntity(entity.type.fields, entity, occupiedFieldsMap); } if (entity.type.entities && entity.type.entities.length > 0) { - const childentityTreeData = { - id: `childEntity_${entity.id}`, - name: '子表', - layer: layer + 1, - parent: entity.id, - hasChildren: true, - collapse: false, - draggable: false - }; - treeViewData.value.push(childentityTreeData); - + const childrenTreeData: any = []; entity.type.entities.forEach((childEntity: any) => { const childEntityPath = `${entityPath === '/' ? '' : entityPath}/${childEntity.label}`; - resolveEntityTreeData(childEntity, layer + 2, childentityTreeData, childEntityPath); + const childTreeData = resolveEntityTreeData(childEntity, layer + 2, { id: entity.id }, childEntityPath); + if (childTreeData) { + childrenTreeData.push(childTreeData); + } }); + + entityTreeData.children.push({ + id: `childEntity_${entity.id}`, + data: { id: `childEntity_${entity.id}`, name: '子表' }, + parent: entity.id, + nodeType: 'childEntity', + collapse: false, + draggable: false, + children: childrenTreeData + }); + } + return entityTreeData; + } + /** + * 合并运行时定制中来自be或vo的字段 + */ + function resolveRtcEntityTreeData() { + + if (useFormSchema.designerMode === DesignerMode.PC_RTC) { + schemaService.rtcAddedTreeNodes.value = {}; + schemaService.rtcSerializedAddedTreeNodes.value = []; + schemaService.assembleRtcSchemaTree(treeViewData.value); + if (schemaService.rtcSerializedAddedTreeNodes.value?.length) { + serializedTreeData.value = serializedTreeData.value.concat(cloneDeep(schemaService.rtcSerializedAddedTreeNodes.value)); + } } } + /** * 刷新实体树时保留上次的树节点展开状态 * @param currentTreeData 新的treeData @@ -147,7 +174,7 @@ export function UseEntityTreeData(useFormSchema: UseFormSchema) { return; } const nodeId = idClass.replace('id=', ''); - const treeNode = treeViewData.value.find(nodeData => nodeData.id === nodeId); + const treeNode = serializedTreeData.value.find(nodeData => nodeData.data?.id === nodeId); // 简单字段节点 if (treeNode?.data?.$type === FormSchemaEntityField$Type.SimpleField) { @@ -186,5 +213,10 @@ export function UseEntityTreeData(useFormSchema: UseFormSchema) { } } - return { resolveEntityTreeData, assignExpandState, setTreeDraggable, treeViewData, appendTreeToDragulaContainer }; + return { + resolveEntityTreeData, assignExpandState, setTreeDraggable, treeViewData, appendTreeToDragulaContainer, + existedEntityCodes, + resolveRtcEntityTreeData, + serializedTreeData + }; } diff --git a/packages/designer/src/components/components/entity-tree-view/composition/use-new-entity.tsx b/packages/designer/src/components/components/entity-tree-view/composition/use-new-entity.tsx new file mode 100644 index 0000000000000000000000000000000000000000..71c664a1555489546e2e22e9ce19ce24f434d223 --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/composition/use-new-entity.tsx @@ -0,0 +1,78 @@ +import { FModalService, F_MODAL_SERVICE_TOKEN } from '@farris/ui-vue/components'; +import { UseFormSchema } from "../../../types"; +import { inject, Ref, ref } from 'vue'; +import CreateNewEntityComponent from '../components/create-new-entity.component'; + +export function useOpenNewEntity( + useFormSchema: UseFormSchema, + existedEntityCodes: Ref, + refreshEntityTree: any, + newEntityCodeList: Ref) { + + const modalService: FModalService | null = inject(F_MODAL_SERVICE_TOKEN, null); + const modalInstance = ref(); + + /** + * 关闭窗口 + */ + function onCancel() { + if (modalInstance.value.close) { + modalInstance.value.close(); + } + } + /** + * 确定新增子表 + */ + function onSubmit(newEntityInfo: any) { + existedEntityCodes.value.push(newEntityInfo.code); + // 修改schema + const mainEntity = useFormSchema.getSchemaEntities()[0]; + if (mainEntity?.type?.entities) { + mainEntity.type.entities.push(newEntityInfo); + } + // 刷新实体树 + if (refreshEntityTree) { + refreshEntityTree(); + } + // 记录新增表的编号,以便于后续新增字段时做校验 + newEntityCodeList.value.push(newEntityInfo.code); + + // 关闭窗口 + if (modalInstance.value.close) { + modalInstance.value.close(); + } + } + function renderNewEntityComponent() { + + return () => (<> + ); + } + + + function openNewEntityModal(event: MouseEvent) { + event.stopPropagation(); + event.preventDefault(); + if (!modalService) { + return; + } + const modalEditorRef = modalService.open({ + title: '新增子实体', + width: 500, + height: 200, + fitContent: false, + showButtons: false, + render: renderNewEntityComponent(), + enableEsc: false, + draggable: true + }); + + modalInstance.value = modalEditorRef?.modalRef?.value; + } + + + return { openNewEntityModal }; +} diff --git a/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-modal.tsx b/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-modal.tsx new file mode 100644 index 0000000000000000000000000000000000000000..081ad162de55c471c34c42993331ea3a99ca13d0 --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-modal.tsx @@ -0,0 +1,80 @@ +import { FModalService, F_MODAL_SERVICE_TOKEN } from '@farris/ui-vue/components'; +import { FormSchemaEntity, FormSchemaEntityField, UseFormSchema } from "../../../types"; +import { inject, Ref, ref } from 'vue'; +import CreateNewFieldComponent from '../components/create-new-field.component'; + +export function useOpenNewField( + useFormSchema: UseFormSchema, + newEntityCodeList: Ref, + refreshEntityTree: any, + treeViewData: Ref) { + + const modalService: FModalService | null = inject(F_MODAL_SERVICE_TOKEN, null); + const modalInstance = ref(); + + const currentTreeNode = ref(); + /** + * 关闭窗口 + */ + function onCancel() { + if (modalInstance.value.close) { + modalInstance.value.close(); + } + } + /** + * 确定新增子表 + */ + function onSubmit(newSchemaField: FormSchemaEntityField) { + // 修改schema + if (currentTreeNode.value?.data?.type?.fields) { + currentTreeNode.value.data.type.fields.push(newSchemaField); + } + + // 刷新实体树 + if (refreshEntityTree) { + refreshEntityTree(); + } + + if (modalInstance.value.close) { + modalInstance.value.close(); + } + } + function renderNewFieldComponent(treeNode: any) { + const entityCode = treeNode?.data?.code; + const isNewEntity = newEntityCodeList.value.includes(entityCode); + const existedAllFields = treeViewData.value.filter(node => node.parent === treeNode?.data?.id && node.data).map(node => node.data); + return () => (<> + ); + } + + + function openNewFieldModal(event: MouseEvent, treeNode: any) { + event.stopPropagation(); + event.preventDefault(); + if (!modalService) { + return; + } + currentTreeNode.value = treeNode; + const modalEditorRef = modalService.open({ + title: '新增字段', + width: 800, + height: 500, + fitContent: false, + showButtons: false, + render: renderNewFieldComponent(treeNode), + enableEsc: false, + draggable: true + }); + + modalInstance.value = modalEditorRef?.modalRef?.value; + } + + + return { openNewFieldModal }; +} diff --git a/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-util.tsx b/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-util.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5c1cd455665c013bf8dafb9daca3c417912a1b3b --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-util.tsx @@ -0,0 +1,724 @@ +import { FormSchemaEntityField, FormSchemaEntityField$Type, FormSchemaEntityFieldEditor, FormSchemaEntityFieldType$Type, UseFormSchema } from "../../../types"; +import { Ref, ref } from 'vue'; +import { CreateNewEntityProps, CreateNewFieldProps } from '../components/entity-tree-view.props'; +import { FItemCollectionEditor } from '@farris/ui-vue/components'; +import { ElementDataType, ElementObjectType, ExtendFieldEntity, FieldObjectTypeEnums } from './extend-field'; +import { cloneDeep } from 'lodash-es'; +import { MetadataService } from "../../../../components/composition/metadata.service"; +import axios from "axios"; +import { IdService } from "../../view-model-designer/method-manager/service/id.service"; + +export function useNewFieldUtil(props: CreateNewFieldProps, extendField: Ref) { + + // 长度字段是否只读 + const isLengthReadonly = ref(false); + const maxLength = ref(2000); + + // 精度字段是否只读 + const isPrecisionReadonly = ref(true); + const maxPrecision = ref(8); + + /** 字段对象类型枚举 */ + const fieldObjectTypes = ref(cloneDeep(FieldObjectTypeEnums)); + /** 帮助元数据 */ + const helpMetadata = ref(); + const helpMetadataName = ref(); + /** 选中的关联字段id集合 */ + const relatedHelpFieldIds = ref(); + /** 选中的关联字段集合 */ + const relatedHelpFields = ref(); + /** 帮助元数据主表字段的树结构集合,用于选择帮助关联字段 */ + const helpSchemaTreeData = ref(); + /** 帮助元数据主表实体节点 */ + const helpSchemaEntity = ref(); + /** 帮助关联字段的树结构集合,用于选择帮助绑定字段 */ + const relatedFieldsTreeData = ref([]); + /** 帮助绑定字段 */ + const helpField = ref(); + /** 帮助绑定字段id */ + const helpFieldId = ref(); + /** 帮助元数据中schema主对象(新),重新调用接口获取的。因为帮助元数据的schema字段缺失editor、type等属性,所以重新调用接口生成一遍schema */ + const newHelpSchemaEntityFields: Ref = ref(); + /** 转为表单字段后的帮助控件绑定字段 */ + const helpSchemaField = ref(); + /** 帮助映射 */ + const helpMapFields: any = {}; + + /** + * 切换字段类型后,联动变更字段相关属性 + */ + function onChangeFieldType() { + switch (extendField.value.type) { + case ElementDataType.String: { + isLengthReadonly.value = false; + isPrecisionReadonly.value = true; + extendField.value.length = 36; + maxLength.value = 2000; + extendField.value.precision = 0; + fieldObjectTypes.value = FieldObjectTypeEnums; + + break; + } + case ElementDataType.Decimal: { + isLengthReadonly.value = false; + isPrecisionReadonly.value = false; + extendField.value.length = 18; + maxLength.value = 30; + + extendField.value.precision = 2; + extendField.value.multiLanguage = false; + break; + } + case ElementDataType.Text: { + isLengthReadonly.value = true; + isPrecisionReadonly.value = true; + extendField.value.length = 0; + extendField.value.precision = 0; + break; + } + case ElementDataType.Integer: { + isLengthReadonly.value = true; + isPrecisionReadonly.value = true; + extendField.value.length = 0; + extendField.value.precision = 0; + extendField.value.multiLanguage = false; + + fieldObjectTypes.value = FieldObjectTypeEnums.filter(type => [ElementObjectType.None, ElementObjectType.Enum].includes(type.value)); + break; + } + default: { + isLengthReadonly.value = true; + isPrecisionReadonly.value = true; + extendField.value.length = 0; + extendField.value.precision = 0; + extendField.value.multiLanguage = false; + } + } + extendField.value.objectType = ElementObjectType.None; + } + /** + * 修改枚举数据 + */ + function onChangeEnumValues(newValue: any) { + extendField.value.enumValues = newValue || []; + } + /** + * 枚举编辑器 + */ + function renderEnumValuesEditor() { + const requiredFields = ['value', 'name']; + const columns = [ + { field: 'value', title: '值', dataType: 'string' }, + { field: 'name', title: '名称', dataType: 'string' } + ]; + return + ; + } + /** + * 获取默认的字段编辑器 + * @param fieldType 字段类型, + * @param multiLanguage 是否多语 + */ + function getDefaultEditorByType(fieldType: FormSchemaEntityFieldType$Type, multiLanguage = false): FormSchemaEntityFieldEditor { + // if (multiLanguage) { + // return { + // $type: DgControl.LanguageTextBox.type + // }; + // } + + switch (fieldType) { + case FormSchemaEntityFieldType$Type.TextType: { + return { + $type: 'MultiTextBox' + }; + } + case FormSchemaEntityFieldType$Type.NumericType: { + return { + $type: 'NumericBox' + }; + } + case FormSchemaEntityFieldType$Type.DateType: case FormSchemaEntityFieldType$Type.DateTimeType: { + return { + $type: 'DateBox', + format: "'yyyy-MM-dd'" + }; + } + case FormSchemaEntityFieldType$Type.BooleanType: { + return { + $type: 'CheckBox' + }; + } + case FormSchemaEntityFieldType$Type.EnumType: { + return { + $type: 'EnumField' + }; + } + default: { + return { + $type: 'TextBox' + }; + } + } + } + + /** + * 扩展字段类型对象映射到shema类型对象 + * @param field 扩展字段 + */ + function mapExtendFieldType2SchemaType(field: ExtendFieldEntity) { + const fieldType = field.type; + switch (field.type) { + case ElementDataType.String: { + if (field.objectType === ElementObjectType.Enum) { + return { + $type: FormSchemaEntityFieldType$Type.EnumType, + name: field.objectType, + displayName: '枚举', + valueType: { + $type: FormSchemaEntityFieldType$Type.StringType, + name: fieldType, + length: field.length || 36, + displayName: '字符串' + }, + enumValues: field.enumValues + }; + } else { + return { + $type: FormSchemaEntityFieldType$Type.StringType, + name: fieldType, + displayName: '字符串', + length: field.length || 36 + }; + } + + } + case ElementDataType.Text: { + return { + $type: FormSchemaEntityFieldType$Type.TextType, + name: fieldType, + displayName: '文本', + length: 0 + }; + } + case ElementDataType.Integer: case ElementDataType.Decimal: { + if (field.objectType === ElementObjectType.Enum) { + return { + $type: FormSchemaEntityFieldType$Type.EnumType, + name: field.objectType, + displayName: '枚举', + valueType: { + $type: FormSchemaEntityFieldType$Type.NumericType, + name: 'Number', + displayName: '数字', + length: field.length || 0, + precision: field.precision || 0, + elementType: field.type // 区分整数和浮点数 + }, + enumValues: field.enumValues + }; + } else { + return { + $type: FormSchemaEntityFieldType$Type.NumericType, + name: 'Number', + displayName: '数字', + length: field.length || 0, + precision: field.precision || 0, + elementType: field.type // 区分整数和浮点数 + }; + } + + } + case ElementDataType.Boolean: { + return { + $type: FormSchemaEntityFieldType$Type.BooleanType, + name: fieldType, + displayName: '布尔' + }; + } + case ElementDataType.Date: { + return { + $type: FormSchemaEntityFieldType$Type.DateType, + name: 'Date', + displayName: '日期', + elementType: field.type // 区分日期和日期时间类型 + }; + } + case ElementDataType.DateTime: { + + return { + $type: FormSchemaEntityFieldType$Type.DateTimeType, + name: 'DateTime', + displayName: '日期时间', + elementType: field.type // 区分日期和日期时间类型 + }; + } + } + } + + /** + * 组装简单字段的schema字段结构 + */ + function mapExtendFieldToSchemaField(objectType?: string) { + objectType = objectType || extendField.value.objectType; + const schemaField: any = {}; + + Object.assign(schemaField, { + id: extendField.value.id, + originalId: extendField.value.id, + code: extendField.value.code, + name: extendField.value.name, + label: extendField.value.label, + bindingField: extendField.value.label, + bindingPath: extendField.value.label, + path: extendField.value.label + }); + + // 简单字段的类型、编辑器、必填、只读、多语属性 + if (objectType === ElementObjectType.None || objectType === ElementObjectType.Enum) { + schemaField.type = mapExtendFieldType2SchemaType(extendField.value); + schemaField.editor = getDefaultEditorByType(schemaField.type.$type, extendField.value.multiLanguage); + + Object.assign(schemaField, { + $type: FormSchemaEntityField$Type.SimpleField, + readonly: extendField.value.readonly, + require: extendField.value.require, + multiLanguage: extendField.value.multiLanguage || false, + // defaultValue: defaultValueCmp && defaultValueCmp.getFinalDefaultValue() + }); + } else { + schemaField.$type = FormSchemaEntityField$Type.ComplexField; + } + + return schemaField; + } + + /** + * 补充帮助元数据schema字段缺失的属性 + * @param selectedField + */ + function getMergeNewSchemaField(selectedField: FormSchemaEntityField, targetFields?: FormSchemaEntityField[]) { + if (!targetFields) { + targetFields = newHelpSchemaEntityFields.value || []; + } + const targetField = targetFields.find(field => field.originalId === selectedField.originalId); + if (targetField) { + selectedField.require = targetField.require; + selectedField.editor = targetField.editor; + selectedField.multiLanguage = targetField.multiLanguage; + selectedField.bindingPath = targetField.bindingPath; + selectedField.readonly = targetField.readonly; + + // 若包含udt带出字段,则补充udt字段信息 + if (targetField.type?.fields?.length && selectedField.type?.fields?.length) { + const { fields, ...basicTypeInfo } = targetField.type; + Object.assign(selectedField.type, basicTypeInfo); + + selectedField.type.fields.map(selectedChildField => { + selectedChildField = getMergeNewSchemaField(selectedChildField, targetField.type.fields || []); + }); + + } else { + selectedField.type = targetField.type; + } + + } + + return selectedField; + } + /** + * 获取UDT明细字段所属的根字段节点 + */ + function getUDTParentField() { + const relatedRootFields = [] as FormSchemaEntityField[]; + const helpSchemaEntityFields = helpSchemaEntity.value.type.fields; + + // 根据帮助schema字段中是否有editor属性来判断是否需要合并新的帮助schema字段 + const needMergeNewSchemaField = helpSchemaEntityFields[0].editor ? false : true; + + relatedHelpFields.value.forEach(selectedField => { + // 能从第一层的字段列表中找到,则认为是简单字段。否则是关联带出或者udt字段 + let rootField = helpSchemaEntityFields.find(field => field.bindingField === selectedField.bindingField); + if (rootField) { + const schemaField = needMergeNewSchemaField ? getMergeNewSchemaField(selectedField) : selectedField; + relatedRootFields.push(schemaField); + return; + } + + // 因为选择关联字段的下拉帮助中做了限制:只支持一层嵌套,所以此处只需要在帮助实体的第一层字段中查询根节点 + rootField = helpSchemaEntityFields.find(helpSchemaField => { + if (helpSchemaField.type && helpSchemaField.type.fields) { + const leafField = helpSchemaField.type.fields.find(field => field.id === selectedField.id); + if (leafField) { + return true; + } + } + return false; + }); + if (rootField && !relatedRootFields.map(field => field.id).includes(rootField.id)) { + const schemaField = needMergeNewSchemaField ? getMergeNewSchemaField(rootField) : rootField; + relatedRootFields.push(schemaField); + } + + }); + + // 排除未选择的UDT明细字段--因为接口返回的帮助schema里明细节点的id可能会跟帮助元数据里明细节点的id匹配不上,所以这里用originalId + const relatedFieldOriginalIds = relatedHelpFields.value.map(f => f.originalId); + const relatedFieldIds = relatedHelpFields.value.map(f => f.id); + relatedRootFields.forEach(rootField => { + if (rootField.$type === 'SimpleField') { + return; + } + if (rootField.type.fields) { + rootField.type.fields = rootField.type.fields.filter(field => relatedFieldIds.includes(field.id) || relatedFieldOriginalIds.includes(field.originalId)); + } + }); + return relatedRootFields; + } + /** + * 获取关联字段自身字段 + */ + function getAssociationSelfField() { + const id = new IdService().generate(); + const assoSelfField = mapExtendFieldToSchemaField(ElementObjectType.None); + Object.assign(assoSelfField, { + id, + originalId: id, + path: assoSelfField.path + '.' + assoSelfField.label, + bindingPath: assoSelfField.bindingPath + '.' + assoSelfField.label, + require: false + }); + return assoSelfField; + + } + /** + * 映射简单字段schema + * @param field 帮助schema field + * @param parentLabel 字段所属父级label,即当前新增的字段 + */ + function setAssociationSimpleFieldToSchemaField(field: FormSchemaEntityField, parentLabel: string) { + // 记录帮助绑定字段 + if (field.id === helpFieldId.value) { + helpSchemaField.value = field; + } + + // 记录帮助上字段的label,用于映射字段 + const originHelpFieldLabel = field.label; + + const newLabel = parentLabel + '_' + field.code; + Object.assign(field, { + id: new IdService().generate(), + label: newLabel, + path: parentLabel + '.' + newLabel, + bindingPath: parentLabel + '.' + newLabel, + bindingField: parentLabel + '_' + newLabel, + require: false + }); + + delete field['parentPath']; + + // 映射 + helpMapFields[originHelpFieldLabel] = field.bindingPath; + + } + + /** + * 映射UDT字段 + * @param field 帮助UDT schema字段 + * @param parentLabel 字段所属父级label,即当前新增的字段 + */ + function setAssociationUdtFieldToSchemaField(field: FormSchemaEntityField, parentLabel: string) { + const newLabel = parentLabel + '_' + field.code; + const newId = new IdService().generate(); + Object.assign(field, { + id: newId, + originalId: newId, + label: newLabel, + path: parentLabel + '.' + newLabel, + bindingPath: parentLabel + '.' + newLabel, + bindingField: parentLabel + '_' + newLabel + }); + + + // 实体名称: 编号+ 自身字段的ID前四位(首字符大写) + field.type.name = field.type.name + field.id.charAt(0).toUpperCase() + field.id.substr(1, 3); + + // 映射UDT明细字段 + field.type?.fields?.forEach(leafField => { + if (leafField.id === helpFieldId.value) { + helpSchemaField.value = leafField; + } + + // 记录帮助上字段的label,用于映射字段 + const originHelpLeafFieldBindingPath = leafField.bindingPath; + + const newLeafId = new IdService().generate(); + + Object.assign(leafField, { + id: newLeafId, + // originalId: newLeafId, + // label: newLabel, + path: field.path + '.' + leafField.code, + bindingPath: field.bindingPath + '.' + leafField.label, + bindingField: field.bindingField + '_' + leafField.code, + require: false + }); + + // 映射 + if (originHelpLeafFieldBindingPath) { + helpMapFields[originHelpLeafFieldBindingPath] = leafField.bindingPath; + } + }); + + } + /** + * 组装关联字段的schema结构 + */ + function mapAssociationFieldToSchemaField() { + const relatedRootFields = getUDTParentField(); + + const newField = mapExtendFieldToSchemaField(); + if (!helpSchemaEntity.value) { + return; + } + newField.type = { + $type: FormSchemaEntityFieldType$Type.EntityType, + name: helpSchemaEntity.value.code, + primary: extendField.value.label, + fields: [], + entities: [], + displayName: helpSchemaEntity.value.name, + extendProperty: { + beId: helpMetadata.value.dataSource.sourceId, + voId: helpMetadata.value.dataSource.voSourceId + } + }; + + // 关联字段自身 + const assoSelfField = getAssociationSelfField(); + newField.type.fields.push(assoSelfField); + + // 实体名称: 编号+ 自身字段的ID前四位(首字符大写) + newField.type.name = helpSchemaEntity.value.code + assoSelfField.id.charAt(0).toUpperCase() + assoSelfField.id.substr(1, 3); + + // 修改关联字段属性 + const parentLabel = extendField.value.label; + relatedRootFields.forEach(field => { + if (field.$type === 'SimpleField') { + setAssociationSimpleFieldToSchemaField(field, parentLabel); + } else { + setAssociationUdtFieldToSchemaField(field, parentLabel); + } + newField.type.fields.push(field); + + + }); + + // ID映射 + if (helpMapFields.id) { + helpMapFields.id = helpMapFields.id + ',' + newField.label + '.' + newField.label; + } else { + helpMapFields.id = newField.label + '.' + newField.label; + } + + // this.schemaService.localizeSchemaFields([newField]); + return newField; + } + /** + * 组装帮助编辑信息 + */ + function assembleSchemaHelpEditor() { + return { + editor: { + $type: 'lookup', + dataSource: { + uri: `lookup.${props.entityCode}_${helpSchemaField.value.bindingField}`, + displayName: helpMetadata.value.name, + idField: helpMetadata.value.idField, + type: 'ViewObject' + }, + textField: helpMetadata.value.textField, + displayType: helpMetadata.value.displayType, + helpId: helpMetadata.value.id, + mappingFields: JSON.stringify(helpMapFields) + } + }; + } + function resolveFieldInfo() { + // 新字段的schema节点 + let newSchemaField; + + if (extendField.value.objectType === ElementObjectType.Association) { + // 复杂类型:关联字段 + newSchemaField = mapAssociationFieldToSchemaField(); + + // 关联帮助的schema增量记录到schema里 + const schemaIncrement = assembleSchemaHelpEditor(); + Object.assign(helpSchemaField.value, schemaIncrement); + + } else { + // 简单类型、枚举类型的字段 + newSchemaField = mapExtendFieldToSchemaField(); + + } + + return newSchemaField; + } + /** + * 选择帮助元数据后事件 + */ + function onSubmitHelpMetadata(dataSourceSchema: any) { + if (dataSourceSchema) { + const formBasicInfo = props.useFormSchema.getFormMetadataBasicInfo(); + // 获取数据源详细配置信息 + return new MetadataService().getPickMetadata(formBasicInfo.relativePath, dataSourceSchema[0].data) + .then((res: any) => { + const metadata = JSON.parse(res?.metadata.content); + return metadata; + }); + } + } + + + /** + * 判断字段是否可以勾选 + * @param layer 字段在schema中的层级 + * @param field schema field + * @param children 子级 + */ + function checkHelpFieldSelectable(layer: number, field: FormSchemaEntityField, children: any[]) { + if (layer > 1) { + return false; + } + // 简单字段 + if (field.$type === 'SimpleField') { + return true; + } + + // 非简单字段 目前只支持单值UDT和多值UDT(只有一层嵌套),不支持关联和关联UDT + if (field.$type === 'ComplexField' && (field.type.$type !== 'ObjectType' || (field.type?.fields && field.type.fields.length > 1))) { + children.forEach(c => c.selectable = false); + } + return false; + } + function assembleHelpFieldsToTreeData(fields: FormSchemaEntityField[], layer = 0) { + const treeData: any = []; + fields.forEach(element => { + + let children = []; + if (element.type && element.type.fields && element.type.fields.length > 0) { + children = assembleHelpFieldsToTreeData(element.type.fields, layer + 1); + + } + treeData.push({ + data: element, + children, + expanded: true, + selectable: checkHelpFieldSelectable(layer, element, children) + }); + }); + return treeData; + } + /** + * 获取帮助元数据的schema结构 + * 背景:在帮助设计器中点击保存按钮时,后端会对元数据内容进行精简:①删除字段的editor属性,②删除字段type属性下的长度、精度、类型等属性。 + * 在运行时定制设计器中扩展关联字段时,若选择了这种精简过的帮助,便会无法获取字段的类型、编辑器等等信息,所以扩展字段时需要重新调用一个接口,返回完整的帮助元数据。 + */ + function getRealHelpMetadataSchema() { + const url = '/api/runtime/bcc/v1.0/template/gethelpschema'; + const body = { + voId: helpMetadata.value.dataSource.voSourceId, + scene: '', + isRuntime: true + }; + axios.post(url, body, { + headers: { + "content-type": "application/json" + } + }).then((result: any) => { + if (result?.data?.entities) { + newHelpSchemaEntityFields.value = result.data.entities[0].type.fields; + } + }); + } + /** + * 获取帮助元数据后事件 + */ + function onHelpMetadataSelected(helpMetadataData: any) { + if (helpMetadataData?.length) { + helpMetadata.value = helpMetadataData[0].metadataContent; + + helpSchemaEntity.value = helpMetadata.value.schema.main.entities[0]; + const mainFields = helpSchemaEntity.value.type.fields; + helpSchemaTreeData.value = assembleHelpFieldsToTreeData(mainFields); + helpMetadataName.value = helpMetadata.value.name; + + relatedHelpFields.value = []; + relatedHelpFieldIds.value = ''; + helpFieldId.value = ''; + helpField.value = null; + relatedFieldsTreeData.value = []; + + // 调用接口获取帮助中最新的schema数据 + getRealHelpMetadataSchema(); + } + } + + /** + * 选关联字段 + */ + function onHelpRelatedFieldsChanged(selections: any[]) { + const rawSelections = selections?.map(selection => selection.data); + if (rawSelections && rawSelections.length > 0) { + relatedFieldsTreeData.value = assembleHelpFieldsToTreeData(rawSelections); + } else { + relatedFieldsTreeData.value = []; + } + relatedHelpFields.value = rawSelections; + if (!rawSelections.find(selection => selection.id === helpFieldId.value)) { + helpFieldId.value = ''; + helpField.value = null; + } + } + + /** + * 选帮助绑定字段 + */ + function onHelpBindingFieldsChanged(selections: any[]) { + if (selections && selections.length > 0) { + helpField.value = selections[0]; + helpFieldId.value = helpField.value.id; + } else { + helpField.value = null; + helpFieldId.value = ''; + } + } + return { + renderEnumValuesEditor, + isLengthReadonly, + isPrecisionReadonly, + maxLength, + maxPrecision, + resolveFieldInfo, + fieldObjectTypes, + onChangeFieldType, + helpMetadata, + onHelpMetadataSelected, + onSubmitHelpMetadata, + relatedHelpFieldIds, + helpSchemaTreeData, + helpMetadataName, + onHelpRelatedFieldsChanged, + relatedFieldsTreeData, + helpFieldId, + onHelpBindingFieldsChanged + }; +} diff --git a/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-verification.ts b/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-verification.ts new file mode 100644 index 0000000000000000000000000000000000000000..03ff73457df9c931412405a902ffb93ba6c22247 --- /dev/null +++ b/packages/designer/src/components/components/entity-tree-view/composition/use-new-field-verification.ts @@ -0,0 +1,191 @@ +import axios from "axios"; +import { ref, Ref } from "vue"; +import { CreateNewFieldProps } from "../components/entity-tree-view.props"; +import { ElementDataType, ElementObjectType, ExtendFieldEntity } from "./extend-field"; + +export function useNewFieldVerification(props: CreateNewFieldProps, extendField: Ref, notifyService: any) { + + /** 字段名称是否已存在 */ + const isFieldNameExisted = ref(false); + /** 字段标签是否有效 */ + const isFieldLabelValid = ref(true); + /** 字段标签提示信息 */ + const fieldLabelMessage = ref('存储标签:'); + + + /** + * 校验名称是否重复 + */ + function checkFieldNameExisted() { + const names = props.existedAllFields.map(field => field.name); + isFieldNameExisted.value = names.includes(extendField.value.name); + } + + /** + * 校验字段编号:前端 + */ + function checkFieldCodeRegValid() { + if (!extendField.value.code) { + isFieldLabelValid.value = true; + fieldLabelMessage.value = '存储标签:'; + extendField.value.label = ''; + return true; + } + // 1、校验特殊字符 + const reg = /^[a-zA-Z][a-zA-Z0-9]*$/; + if (!reg.test(extendField.value.code)) { + isFieldLabelValid.value = false; + fieldLabelMessage.value = '只允许输入数字、英文字母,且首字母只能为英文字母。'; + extendField.value.label = ''; + + return false; + } + + // 2、校验code是否重复 + const codes = props.existedAllFields.map(field => { + let lowerCode = field.code.toLowerCase(); + if (lowerCode.includes('ext_') && lowerCode.includes('_lv9')) { + lowerCode = lowerCode.replace('ext_', '').replace('_lv9', ''); + } + return lowerCode; + }); + if (codes.includes(extendField.value.code.toLowerCase())) { + isFieldLabelValid.value = false; + let msg = '编号XXX已存在,请重新输入。'; + msg = msg.replace('XXX', extendField.value.code); + fieldLabelMessage.value = msg; + extendField.value.label = ''; + + return false; + } + isFieldLabelValid.value = true; + fieldLabelMessage.value = '存储标签:'; + return true; + } + + /** + * 校验字段编号:后端 + */ + function checkFieldCodeValid(): Promise { + + if (!extendField.value.code) { + return Promise.resolve(true); + } + if (!checkFieldCodeRegValid()) { + return Promise.resolve(true); + } + + // 3、后台校验:若所属实体为新创建的表,则不进行后台校验 + if (props.isNewEntity) { + isFieldLabelValid.value = true; + + // label拼接前后缀 + extendField.value.label = 'ext_' + extendField.value.code + '_Lv9'; + const labelMsg = '存储标签:'; + fieldLabelMessage.value = labelMsg + extendField.value.label; + + return Promise.resolve(true); + } + + const checkLabelValidURL = '/api/runtime/bcc/v1.0/template/newFieldLabel'; + const voId = props.useFormSchema.getSchemas().id; + + return new Promise((resolve, reject) => { + axios.get(`${checkLabelValidURL}/${voId}/${props.entityCode}/${extendField.value.code}`).then((result: any) => { + const data = result?.data; + if (!data) { + resolve(false); + return; + } + if (data.valid) { + + isFieldLabelValid.value = true; + const labelMsg = '存储标签:'; + fieldLabelMessage.value = labelMsg + data.label; + extendField.value.label = data.label; + resolve(true); + return; + } else { + isFieldLabelValid.value = false; + fieldLabelMessage.value = data.msg; + extendField.value.label = ''; + resolve(false); + return; + + } + }, () => { + isFieldLabelValid.value = false; + fieldLabelMessage.value = '校验字段编号失败。'; + resolve(false); + return; + }); + + }); + + } + + + function checkFieldValidation() { + if (!isFieldLabelValid.value) { + return false; + } + if (!extendField.value.type) { + notifyService.warning('字段类型不能为空'); + return false; + } + if (!extendField.value.name) { + notifyService.warning('字段名称不能为空'); + return false; + } + if (!extendField.value.code) { + notifyService.warning('字段编号不能为空'); + return false; + } + if (!extendField.value.objectType) { + notifyService.warning('对象类型不能为空'); + return false; + } + if (extendField.value.length === null) { + notifyService.warning('字段长度不能为空'); + return false; + } + if (extendField.value.precision === null) { + notifyService.warning('字段精度不能为空'); + return false; + } + // if (!checkDefaultValueValid()) { + // return false; + // } + + // if (extendField.value.type === ElementDataType.String && extendField.value.objectType === ElementObjectType.Association) { + // if (!helpMetadata) { + // notifyService.warning('请选择帮助!'); + // return false; + // } + // if (relatedFieldsTreeData.length === 0) { + // notifyService.warning('请选择关联字段!'); + // return false; + // } + // if (!helpField) { + // notifyService.warning('请选择帮助绑定字段!'); + // return false; + // } + // } + + if (extendField.value.objectType === ElementObjectType.Enum && + (!extendField.value.enumValues || !extendField.value.enumValues.length)) { + notifyService.warning('请填写枚举数据!'); + return false; + } + return true; + } + return { + isFieldNameExisted, + checkFieldNameExisted, + checkFieldCodeRegValid, + checkFieldCodeValid, + fieldLabelMessage, + isFieldLabelValid, + checkFieldValidation + }; +} 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 a4db47a2477b2d8f38d50ad4b41d983de3ab7e30..3d34615e25327b68aa6fe08ead2f414463d898e8 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 @@ -26,7 +26,7 @@ export default defineComponent({ const entityTreeRef = ref(); const monacoEditorRef = ref(); const customClassEditorRef = ref(); - const { toolboxItems, componentsToRegister, designerMode} = designerContext; + const { toolboxItems, componentsToRegister, designerMode } = designerContext; function onCanvasInitialized(dragula: any) { dragulaCompostion.value = dragula; } @@ -42,7 +42,7 @@ export default defineComponent({ const { width } = designerCanvasElementRef.getBoundingClientRect(); if (externalComponentPanelWidth.value !== width) { externalComponentPanelWidth.value = width; - } + } }); schemaService.load(componentSchema.value); provide('SchemaService', schemaService); @@ -262,7 +262,7 @@ export default defineComponent({ components={componentsToRegister} canvasMode={designerMode} > - {/* */} diff --git a/packages/designer/src/components/components/form-settings/form-settings.component.tsx b/packages/designer/src/components/components/form-settings/form-settings.component.tsx index 3a96be236fe72a0bd2fcadf162216dbd82d23e63..13b3288aa0ef4a4572ca1a182f05c4d80a0697f2 100644 --- a/packages/designer/src/components/components/form-settings/form-settings.component.tsx +++ b/packages/designer/src/components/components/form-settings/form-settings.component.tsx @@ -1,8 +1,7 @@ import { SetupContext, defineComponent, inject, ref } from "vue"; import { formSettingsDesignerProps, FormSettingsDesignerProps } from "./form-settings.props"; import { UseFormSchema } from "../../types"; -import { FMessageBoxService } from "@farris/ui-vue/components"; -import { FNotifyService } from "@farris/ui-vue/components"; +import { FCheckbox } from "@farris/ui-vue/components"; import './form-settings.scss'; @@ -12,144 +11,28 @@ export default defineComponent({ emits: [], setup(props: FormSettingsDesignerProps) { const useFormSchema = inject('useFormSchema') as UseFormSchema; - const formSchema = useFormSchema.getFormSchema(); - const options = ref(formSchema?.options || {}); - const notifyService: any = new FNotifyService(); - const messageService: any = new FMessageBoxService(); - const radioEnumData = [ - { value: 'valid', name: '仅合法变更' }, - { value: 'entire', name: '全部变更' } - ]; + const formBasicInfo = useFormSchema.getFormMetadataBasicInfo(); + const extendable = ref(formBasicInfo?.extendable || false); - // const rootViewModel: any = formSchema.module.viewmodels.find(v => !v.parent); - - if (notifyService) { - notifyService.globalConfig = { position: 'top-center', timeout: 3000, showCloseButton: true }; + function onClickExtendable(checked: boolean) { + formBasicInfo.extendable = extendable.value; } - - /** - * 修改卡片组件内输入控件的静态文本属性 - */ - function changeInputTextArea(componentSchema: any) { - - // TODO: 筛选输入类控件 - if (componentSchema.type === 'form-group') { - componentSchema.isTextArea = options.value.enableTextArea; - return; - } - componentSchema.contents && (componentSchema.contents as any[]) - .forEach((content: any) => changeInputTextArea(content)); - } - - /** - * 刷新静态文本 - */ - function refreshInputTextArea() { - if (!messageService || !messageService.question) { - return; - } - messageService.question('输入类控件将启用静态文本属性,确定刷新?', undefined, () => { - useFormSchema.getFormSchema().module.components.filter((component: any) => - component.componentType.startsWith('form').forEach((formComponent: any) => changeInputTextArea(formComponent))); - notifyService.success('刷新成功'); - - }); - } - return () => { - // return ( - //
- //
- //
- //
- //

静态文本

- //
- //
- // 启用静态文本后输入类控件在只读状态下仅展示文本信息。 - //
- //
- // - //
- // - //
- // - //
- //
- //
- //
- //
- //
- //

复用会话

- //
- //
- // 在组合表单的使用场景中开启该设置后,多个表单可以共用一个会话。 - //
- //
- // - //
- // - //
- //
- //
- //
- //
- //
- //
- //

数据类型转换

- //
- //
- // 启用数据类型转换后,表单变量和VO变量会被转换为对应的数据类型。 - //
- //
- // - //
- // - //
- //
- //
- //
- //
- //
- //
- //

变更集提交策略

- //
- //
- // 变更提交策略是指表单数据发生变化时前端往后端提交变更集的策略。 - // 仅合法变更策略是指仅提交校验通过的变更项,适用于大部分场景。全部变更策略是指提交所有数据变化到后端,适用于暂存场景。 - //
- //
- // - //
- //
- //
- //
- //
- //
- //

服务器端变更检查

- //
- //
- // 菜单或应用关闭前及取消变更时调用后端接口确认后端缓存中的数据是否已经保存并提示用户。 - // 该特性依赖HasChanges接口,请确认已在Api接口文档中添加。 - //
- //
- // - //
- // - //
- //
- //
- //
- //
- - // ); + return ( +
+
+
+

扩展配置

+
+
+ 允许在运行时定制扩展 + 开启此选项后,可以在运行时定制扩展表单中进行扩展 (比如添加字段、子表等) 。 +
+ +
+
+ + ); }; } diff --git a/packages/designer/src/components/components/form-settings/form-settings.scss b/packages/designer/src/components/components/form-settings/form-settings.scss index 9d39cc6c6f69ad8b1ac0045622f510029b7c7763..43c91fafc77daef189771f21c5c01ded77960dfc 100644 --- a/packages/designer/src/components/components/form-settings/form-settings.scss +++ b/packages/designer/src/components/components/form-settings/form-settings.scss @@ -1,58 +1,47 @@ -.f-designer-option-panel { - box-shadow: 0 0 10px 0 #eceff4; - border-radius: 5px; - background: #fff; - padding: 8px 14px; - width: 70%; - margin: 14px auto; - overflow: auto; - - .f-section-header { - - margin: 0 0 4px; - - - } - - .text-muted { - color: #969ba5 !important; - } - - .badge { - padding: .25rem .5rem; - } - - .col-form-label { - justify-content: start !important; - width: auto; - display: inline-block; - } - - .badge { - padding: .25rem .5rem; +.f-designer-settings { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + background-color: #fff; + padding: 20px; + + .f-designer-option-panel { + width: 80%; + + .panel-title { + color: #000; + display: inline-flex; + align-items: center; + line-height: 1.375rem; + width: 100%; + background: #F7F8FA; + padding: 4px 10px; + border-radius: 4px; + + .menu-item-icon { + margin-right: 5px; + color: #5B89FE; + } + + .title-text { + font-size: 12px; + line-height: 17px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + margin-bottom: 0; + margin-right: 10px; + } + } + + .panel-main { + padding: 20px 40px; + + .form-text { + font-size: 90%; + color: #969ba5 !important; + } + } } - - small { - font-size: 90%; - } - - .mr-4 { - display: inline-block; - margin: 4px 24px 3px 10px; - } - - .custom-control-label { - display: inline-block; - - } - - .custom-control.custom-radio { - margin: 8px 8px 6px 1px; - display: inline-block !important; - } - - .form-group { - margin: 4px 1px 3px 1px; - } - } \ No newline at end of file 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 dac02857dc2426799527f972e65eec2239884842..9f12b16aecab9e7c986cf54fcb1419b57017b53b 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 @@ -102,21 +102,26 @@ export function useWebCommandSelector() { const { relativePath } = formMetaBasicInfo; const supportedControllers = getAllSupportedControllers(); - new MetadataService().GetMetadataListByType(relativePath, '.webcmd').then((response: any) => { + new MetadataService().getMetadataListByType(relativePath, '.webcmd').then((response: any) => { + const allCommandsMetadata: any[] = response.data; - const commandsMetadataInThePage = allCommandsMetadata.filter((commandMetadata: any) => { - const hasExtendProperty = !!commandMetadata.extendProperty; - const extendPropertyObject = hasExtendProperty ? JSON.parse(commandMetadata.extendProperty) : {} as Record; - const beloneToThePage = extendPropertyObject.FormCode === formMetaBasicInfo.code; - return beloneToThePage; - }).reduce((result: Map, commandMetadataInThePage: any) => { - result.set(commandMetadataInThePage.id, { - id: commandMetadataInThePage.id, - path: commandMetadataInThePage.relativePath, - name: commandMetadataInThePage.fileName - }); - return result; - }, new Map); + let commandsMetadataInThePage = new Map; + if (allCommandsMetadata?.length) { + commandsMetadataInThePage = allCommandsMetadata.filter((commandMetadata: any) => { + const hasExtendProperty = !!commandMetadata.extendProperty; + const extendPropertyObject = hasExtendProperty ? JSON.parse(commandMetadata.extendProperty) : {} as Record; + const beloneToThePage = extendPropertyObject.FormCode === formMetaBasicInfo.code; + return beloneToThePage; + }).reduce((result: Map, commandMetadataInThePage: any) => { + result.set(commandMetadataInThePage.id, { + id: commandMetadataInThePage.id, + path: commandMetadataInThePage.relativePath, + name: commandMetadataInThePage.fileName + }); + return result; + }, new Map); + } + const allCommandInfoReferencedInThePage = webCmdInfos.reduce((result: Map, commandInfo: FormWebCmd) => { result.set(commandInfo.id, commandInfo); @@ -124,7 +129,7 @@ export function useWebCommandSelector() { }, commandsMetadataInThePage); const requestCommandsMetadata = Array.from(allCommandInfoReferencedInThePage.values()) - .map((commandInfo: FormWebCmd) => new MetadataService().queryMetadataById(relativePath, commandInfo.id) + .map((commandInfo: FormWebCmd) => new MetadataService().getRefMetadata(relativePath, commandInfo.id) .catch(() => { console.log(`获取元数据${commandInfo.name}失败,请检查。`); }) ); diff --git a/packages/designer/src/components/components/view-model-designer/method-manager/composition/build-method.ts b/packages/designer/src/components/components/view-model-designer/method-manager/composition/build-method.ts index 504e05e41c46f4c3297cc0eb7a196e3aa9b95853..778d8dc625776d2e745304f30aa8881d0efcd7a3 100644 --- a/packages/designer/src/components/components/view-model-designer/method-manager/composition/build-method.ts +++ b/packages/designer/src/components/components/view-model-designer/method-manager/composition/build-method.ts @@ -7,6 +7,7 @@ import { IdService } from "../service/id.service"; import { MetadataService } from "../../../../composition/metadata.service"; import { cloneDeep } from 'lodash-es'; import { FMessageBoxService } from '@farris/ui-vue/components'; +import { DesignerMode } from '../../../../types/designer-context'; export class MethodBuilder { @@ -106,7 +107,7 @@ export class MethodBuilder { const relativePath = metadataInfo ? metadataInfo.relativePath : ''; const requestCommandsMetadata = webCmdInfos.map((commandInfo: FormWebCmd) => { - return new MetadataService().queryMetadataById(relativePath, commandInfo.id).catch(error => { + return new MetadataService().getRefMetadata(relativePath, commandInfo.id).catch(error => { this.messageService.warning(`获取元数据${commandInfo.name}失败,请检查。`, ''); }); }); @@ -219,7 +220,9 @@ export class MethodBuilder { const command = new Command(selectedCommand, controller.Id, controller); command.id = new IdService().generate(); command.isNewGenerated = false; - + if (this.useFormSchema.designerMode === DesignerMode.PC_RTC) { + command.isRtcCommand = true; + } this.recursiveUniqueId(command.children); // 处理code、name diff --git a/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-list.ts b/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-list.ts index 44633387a58c372a735684f96a477689d48a3ed4..469ccafb5a8c04405597a41cf37fbcd92fffe8e0 100644 --- a/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-list.ts +++ b/packages/designer/src/components/components/view-model-designer/method-manager/composition/use-view-model-list.ts @@ -71,7 +71,7 @@ export function useViewModelNavigation() { if (pageViewModel) { sortedViewModels.push(pageViewModel); } - }) + }); const components = formSchema.module.components.filter(component => component.componentType !== ComponentType.Frame); componentIdList.forEach(componentId => { diff --git a/packages/designer/src/components/components/view-model-designer/method-manager/entity/command.ts b/packages/designer/src/components/components/view-model-designer/method-manager/entity/command.ts index 5ed682d126c3d0eb5e410a7f40b9167f39ea3ae6..b7bca57b77ca8b46a4aaef5ac322201daf7a796f 100644 --- a/packages/designer/src/components/components/view-model-designer/method-manager/entity/command.ts +++ b/packages/designer/src/components/components/view-model-designer/method-manager/entity/command.ts @@ -37,7 +37,7 @@ export class Command implements ITreeNode { root?: ITreeNode; /** 是否为运行时定制添加的命令 */ - isRTCmd?: boolean; + isRtcCommand?: boolean; /** 命令的参数是否需要刷新--用于构件中删除命令参数的场景 */ needRefreshParam = false; @@ -157,7 +157,7 @@ export class Command implements ITreeNode { cmpId: this.cmpId, shortcut: this.shortcut ? JSON.parse(JSON.stringify(this.shortcut)) : {}, extensions, - isRTCmd: this.isRTCmd, + isRtcCommand: this.isRtcCommand, isInvalid: this.isInValid }; if (this.isNewGenerated !== undefined) { diff --git a/packages/designer/src/components/components/view-model-designer/method-manager/method-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/method-manager/method-manager.component.tsx index d37bb0f6d54c1ee661e3cc20a1cc90d28526f1f2..03af6c0f919ec062ba2ab03d34e20b0757aaaa92 100644 --- a/packages/designer/src/components/components/view-model-designer/method-manager/method-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/method-manager/method-manager.component.tsx @@ -8,6 +8,7 @@ import { WebCommand, WebCommandMetadata } from "./entity/web-command"; import FMethodEditor from '../../../components/view-model-designer/method-manager/components/method-editor/method-editor.component'; import FMethodList from '../../../components/view-model-designer/method-manager/components/method-list/method-list.component'; import FMethodSelector from '../../../components/view-model-designer/method-manager/components/method-selector/method-selector.component'; +import { DesignerMode } from "../../../types/designer-context"; import './method-manager.scss'; @@ -121,6 +122,10 @@ export default defineComponent({ notifyService.warning({ message: '请先选择方法' }); return; } + if (useFormSchema.designerMode === DesignerMode.PC_RTC && !methodListRef.value.selectedTreeNode.data?.isRtcCommand) { + notifyService.warning({ message: '不允许移除基础表单的方法' }); + return; + } messageBoxService.question('确定移除方法?', '', () => { const { nextCommandId, commandsTreeData: newCommandsTreeData } = methodBuilderComposition.removeCommand(methodListRef.value.selectedTreeNode, activeViewModel.value); commandsTreeData.value = newCommandsTreeData; @@ -143,6 +148,10 @@ export default defineComponent({ notifyService.warning({ message: '方法已失效,不支持重命名' }); return; } + if (useFormSchema.designerMode === DesignerMode.PC_RTC && !methodListRef.value.selectedTreeNode.data?.isRtcCommand) { + notifyService.warning({ message: '不允许重命名基础表单的方法' }); + return; + } methodEditorVisible.value = true; } /** diff --git a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx index ea342f4f2e8ebd23e73b42ee8bff24ae04026534..95aac794dd0b1723d055f7c2608118f92ec1cd9a 100644 --- a/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx +++ b/packages/designer/src/components/components/view-model-designer/variable-manager/variable-manager.component.tsx @@ -3,9 +3,10 @@ import { FDataGrid, FLoadingService } from "@farris/ui-vue/components"; import { variableManagerProps, VariableManagerProps } from "./variable-manager.props"; import './variable-manager.scss'; import { useVariableData } from "./composition/use-variable-data"; -import { FormVariable } from "../../../../components/types"; +import { FormVariable, UseFormSchema } from "../../../../components/types"; import { useVariableDataGridOptions } from "./composition/use-variable-datagrid-options"; import { useVariableDefaultValue } from "./composition/use-variable-default-value"; +import { DesignerMode } from "../../../../components/types/designer-context"; export default defineComponent({ name: 'FVariableManager', @@ -13,7 +14,7 @@ export default defineComponent({ emits: [] as (string[] & ThisType) | undefined, setup(props: VariableManagerProps, context: SetupContext) { const loadingService: FLoadingService | any = inject('FLoadingService'); - + const useFormSchemaComposition: any = inject('useFormSchema') as UseFormSchema; /** 表格实例 */ const gridComponentInstance = ref(); /** 列配置 */ @@ -122,10 +123,11 @@ export default defineComponent({
-
-
- 刷新 -
+ {DesignerMode.PC_RTC !== useFormSchemaComposition.designerMode && +
+
+ 刷新 +
}
{ - return metadataService.GetRefMetadata(metadataInfo.relativePath || '', webcmdInfo.id).then((response) => { + return metadataService.getRefMetadata(metadataInfo.relativePath || '', webcmdInfo.id).then((response) => { webcmdInfo.code = webcmdInfo.code ? webcmdInfo.code : response.data.code; webcmdInfo.nameSpace = webcmdInfo.nameSpace ? webcmdInfo.nameSpace : response.data.nameSpace; return response.data; @@ -156,8 +156,13 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS function loadCommandsInCurrentPath(): Promise { const commandsInfos = formSchemaService.getCommands(); const metadataInfo = formSchemaService.getFormMetadataBasicInfo(); + if (!metadataInfo.relativePath) { + return new Promise((resolve, reject) => { + resolve(null); + }); + } return new Promise((resolve, reject) => { - metadataService.GetMetadataList(metadataInfo.relativePath, '.webcmd').then((response: AxiosResponse) => { + metadataService.getMetadataList(metadataInfo.relativePath, '.webcmd').then((response: AxiosResponse) => { if (!response.data) { resolve(null); return; @@ -585,7 +590,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS handlerName: commandItem.handlerName, cmpId: commandItem.cmpId, isNewGenerated: commandItem.isNewGenerated || false, - isRTCmd: commandItem['isRTCmd'], + isRtcCommand: commandItem['isRtcCommand'], isInvalid: commandItem.isInvalid || false, params: cloneDeep(commandItem.params), controllerId: '', @@ -673,7 +678,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS params: cloneDeep(allBoundEvents[i].params), cmpId: allBoundEvents[i].cmpId, isNewGenerated: allBoundEvents[i].isNewGenerated || false, - isRTCmd: allBoundEvents[i]['isRTCmd'], + isRtcCommand: allBoundEvents[i]['isRtcCommand'], isInvalid: allBoundEvents[i].isInvalid || false, }, controller: { @@ -779,7 +784,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS isNewGenerated: undefined, showTargetComponent: false, targetComponent: cmpId, - isRTCmd: undefined, + isRtcCommand: undefined, }; let recordController = { controllerName: { @@ -886,7 +891,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS recordCommand.name = viewModelcommand.name; recordCommand.id = viewModelcommand.id; recordCommand.targetComponent = cmpId; - recordCommand['isRTCmd'] = viewModelcommand['isRTCmd']; + recordCommand.isRtcCommand = viewModelcommand.isRtcCommand; return recordCommand; } /** 1-b.生成已绑定的事件列表 */ @@ -938,7 +943,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS isInvalid: false, isNewGenerated: undefined, targetComponent: undefined, - isRTCmd: undefined, + isRtcCommand: undefined, }; const vmId = paths !== undefined ? paths[1] : viewModelId; const cmdLabel = paths !== undefined ? paths[2] : propCmdLabel; @@ -959,7 +964,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS newCommand.handlerName = mapItem.command.handlerName; newCommand.cmpId = cloneDeep(mapItem.controller.id); newCommand.shortcut = mapItem.command.shortcut; - newCommand.isRTCmd = mapItem.command['isRTCmd']; + newCommand.isRtcCommand = mapItem.command['isRtcCommand']; newCommand.isNewGenerated = mapItem.command.isNewGenerated || false; newCommand.isInvalid = mapItem.command.isInvalid || false; newCommand.extensions = mapItem.command.extensions; @@ -1017,7 +1022,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS handlerName: '', showTargetComponent: false, isNewGenerated: undefined, - isRTCmd: undefined, + isRtcCommand: undefined, isInvaild: false, cmpId: '', componentLists: [], @@ -1051,7 +1056,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS controllerListItem.property = cloneDeep(mapItem.command.params); controllerListItem.cmpId = mapItem.controller.id; controllerListItem.isNewGenerated = mapItem.isNewGenerated || false; - controllerListItem.isRTCmd = mapItem['isRTCmd']; + controllerListItem.isRtcCommand = mapItem['isRtcCommand']; controllerListItem.isInvaild = mapItem.inInvalid || false; if (mapItem.targetComponent.id) { controllerListItem.targetComponent = mapItem.targetComponent.id; @@ -1289,7 +1294,7 @@ export function useFormCommandService(formSchemaService: UseFormSchema, useFormS componentLists: [], shortcut: {}, // true:表明为新增项,可以编辑 - isRTCmd: commandsItem['isRTCmd'], + isRtcCommand: commandsItem['isRtcCommand'], isNewGenerated: commandsItem['isNewGenerated'] || false, extensions: [], isInvalid: false, 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 12ddccfd2658d8917708b73d9bc14d26cd4d0b72..11804ce264ef466175a5941ae1256dc7f2d41c92 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,8 +1,9 @@ import { getSchemaByType } from "@farris/ui-vue/components"; -import { FormBindingType, FormSchemaEntityField, FormSchemaEntityFieldTypeName, UseControlCreator } from "../../types"; +import { omit } from "lodash-es"; +import { FormBindingType, FormSchemaEntityField, FormSchemaEntityFieldTypeName, UseControlCreator, UseSchemaService } from "../../types"; import { FormMetadataConverter } from "../form-metadata-converter"; -export function usePCControlCreator(): UseControlCreator { +export function usePCControlCreator(schemaService: UseSchemaService): UseControlCreator { /** * 配置输入控件属性 * @param field schema字段 @@ -72,6 +73,13 @@ export function usePCControlCreator(): UseControlCreator { } } + // 帮助类型 + if (formEditor.type === 'lookup' && field.editor?.$type === 'lookup') { + const editorOptions = omit(field.editor, '$type'); + Object.assign(formEditor, editorOptions); + } + + schemaService.addRtcFieldsToSchemaEntity(field); return formGroupMetadata; } @@ -219,6 +227,7 @@ export function usePCControlCreator(): UseControlCreator { const fieldEditor = setFormFieldProperty(field, realEditor, '', 'Grid'); metadata.editor = fieldEditor.editor; } + schemaService.addRtcFieldsToSchemaEntity(field); return metadata; } diff --git a/packages/designer/src/components/composition/designer-context/use-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-designer-context.ts index a71ba23d89250b741d8aa3695543038fac56824b..25b397cbbb1ca9e00955209159eada41def58954 100644 --- a/packages/designer/src/components/composition/designer-context/use-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-designer-context.ts @@ -1,23 +1,43 @@ import { DesignerMode, UseDesignerContext } from "../../types/designer-context"; -import { MetadataService } from "../metadata.service"; +import { useLocation } from "../use-location"; import { useMobileDesignerContext } from "./use-mobile-designer-context"; import { usePCDesignerContext } from "./use-pc-designer-context"; +import { usePCRtcDesignerContext } from "./use-pc-rtc-designer-context"; /** * 设计器上下文 * @returns */ export function useDesignerContext(): UseDesignerContext { + /** + * 判断的当前设计器运行环境 + */ function getDesignerMode(): DesignerMode { - const metadataService = new MetadataService(); - const metadataPath = metadataService.getMetadataPath(); + const { getHrefParam, getUrlParam } = useLocation(); + const metadataPath = getUrlParam('id') || ''; + const designerEnvType = getHrefParam('envType'); + + if (designerEnvType === 'runtimeCustom') { + return DesignerMode.PC_RTC; + } if (metadataPath && metadataPath.includes('.mfrm')) { return DesignerMode.Mobile; } + return DesignerMode.PC; } const designerMode = getDesignerMode(); - return designerMode === DesignerMode.Mobile ? useMobileDesignerContext() : usePCDesignerContext(); -} \ No newline at end of file + switch (designerMode) { + case DesignerMode.PC: { + return usePCDesignerContext(); + } + case DesignerMode.Mobile: { + return useMobileDesignerContext(); + } + case DesignerMode.PC_RTC: { + return usePCRtcDesignerContext(); + } + } +} diff --git a/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts index 037667831498e295c368072fc155fcf4be10c9ef..f5ba536315dc0a0d123592a8dde7a9ba0f37a6fb 100644 --- a/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-mobile-designer-context.ts @@ -10,9 +10,11 @@ import { import { useMobileControlCreator } from "../control-creator/use-mobile-control-creator"; import { FormComponent, UseFormSchema } from "../../../components/types"; import ControllCategories from '../schema-repository/controller/mobile-categories'; +import axios from 'axios'; +import { useFormMetadata } from "../form-metadata.service"; export function useMobileDesignerContext(): UseDesignerContext { - + /** 设计器模式 */ const designerMode: DesignerMode = DesignerMode.Mobile; @@ -22,8 +24,8 @@ export function useMobileDesignerContext(): UseDesignerContext { /** 要注册的UI组件 */ const componentsToRegister: any[] = [ Component, PageContainer, PageHeaderContainer, PageBodyContainer, PageFooterContainer, - ContentContainer, Card, FloatContainer,Textarea,DatePicker,DateTimePicker,Lookup, - Navbar, ListView,Picker,NumberInput,Switch,CheckboxGroup,RadioGroup, + ContentContainer, Card, FloatContainer, Textarea, DatePicker, DateTimePicker, Lookup, + Navbar, ListView, Picker, NumberInput, Switch, CheckboxGroup, RadioGroup, Form, FormItem, InputGroup, Button, ButtonGroup, ]; @@ -34,15 +36,18 @@ export function useMobileDesignerContext(): UseDesignerContext { const controllCategories: any = ControllCategories; - + /** 控件创建服务 */ const useControlCreator = useMobileControlCreator; + /** 表单元数据服务 */ + const useFormMetadataService = useFormMetadata; + /** * 获取所有的页面组件 * @returns */ - function getPageComponents(useFormSchema:UseFormSchema):FormComponent[]{ + function getPageComponents(useFormSchema: UseFormSchema): FormComponent[] { const predicateFunction = (component: any) => component.componentType && component.componentType.toLowerCase() === 'page'; const pageComponents = useFormSchema.getComponetsByPredicate(predicateFunction); return pageComponents; @@ -55,6 +60,7 @@ export function useMobileDesignerContext(): UseDesignerContext { supportedControllers, controllCategories, useControlCreator, - getPageComponents - } -} \ No newline at end of file + getPageComponents, + useFormMetadataService + }; +} diff --git a/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts index 282da41d9103fa5f7543d20baf07d7fcd2a01c1b..8ea9ba76b44db5f1b05e0ae14479f521fe45f1f6 100644 --- a/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts +++ b/packages/designer/src/components/composition/designer-context/use-pc-designer-context.ts @@ -4,6 +4,7 @@ import { usePCControlCreator } from "../control-creator/use-pc-control-creator.s import SupportedControllers from '../../composition/command/supported-controllers/pc-supported-controller.json'; import { FormComponent, UseFormSchema } from "../../../components/types"; import ControllCategories from '../schema-repository/controller/pc-categories'; +import { useFormMetadata } from "../form-metadata.service"; export function usePCDesignerContext(): UseDesignerContext { @@ -18,13 +19,16 @@ export function usePCDesignerContext(): UseDesignerContext { /** 支持的控制器 */ const supportedControllers: any = SupportedControllers; - + /** 控制器分类 */ const controllCategories: any = ControllCategories; /** 控件创建服务 */ const useControlCreator = usePCControlCreator; + /** 表单元数据服务 */ + const useFormMetadataService = useFormMetadata; + /** * 获取所有的页面组件 * @returns @@ -45,6 +49,7 @@ export function usePCDesignerContext(): UseDesignerContext { supportedControllers, controllCategories, useControlCreator, - getPageComponents - } -} \ No newline at end of file + getPageComponents, + useFormMetadataService + }; +} diff --git a/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts b/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts new file mode 100644 index 0000000000000000000000000000000000000000..c059227de34545dea084f43135c81eaa3e6ab843 --- /dev/null +++ b/packages/designer/src/components/composition/designer-context/use-pc-rtc-designer-context.ts @@ -0,0 +1,207 @@ +import { DesignerMode, UseDesignerContext } from "../../types/designer-context"; +import ToolboxItems from '../../types/toolbox/pc-toolbox.json'; +import { usePCControlCreator } from "../control-creator/use-pc-control-creator.service"; +import SupportedControllers from '../../composition/command/supported-controllers/pc-supported-controller.json'; +import { FormComponent, UseFormSchema } from "../../../components/types"; +import ControllCategories from '../schema-repository/controller/pc-categories'; +import { useRtcFormMetadata } from "../form-metadata-rtc.service"; +import axios from "axios"; +import { ElementPropertyConfig } from "@farris/ui-vue/components/property-panel"; +import { FNotifyService } from "@farris/ui-vue/components"; + +export function usePCRtcDesignerContext(): UseDesignerContext { + + /** 设计器模式 */ + const designerMode: DesignerMode = DesignerMode.PC_RTC; + + /** 工具箱的数据 */ + const toolboxItems: any[] = ToolboxItems; + + /** 要注册的UI组件 */ + const componentsToRegister: any = null; + + /** 支持的控制器 */ + const supportedControllers: any = SupportedControllers; + + /** 控制器分类 */ + const controllCategories: any = ControllCategories; + + /** 控件创建服务 */ + const useControlCreator = usePCControlCreator; + + /** 表单元数据服务 */ + const useFormMetadataService = useRtcFormMetadata; + + /** 控件属性过滤映射 */ + let controlPropertyRule: any = {}; + + const notifyService = new FNotifyService(); + + /** 运行时定制中新增控件的属性标识 */ + const identifyForNewControl = 'isRtcControl'; + + /** 运行时定制中新增方法的属性标识 */ + const identifyForNewCommand = 'isRtcCommand'; + /** + * 获取所有的页面组件 + * @returns + */ + function getPageComponents(useFormSchema: UseFormSchema): FormComponent[] { + const pageComponents: FormComponent[] = []; + const pageComponent = useFormSchema.getComponentById('root-component'); + if (pageComponent) { + pageComponents.push(pageComponent); + } + return pageComponents; + } + + /** + * 获取运行时定制控件属性默认控制规则 + */ + function getPropertyFilterRule() { + + return axios.get('assets/rtc/property-rule.json?version=' + new Date().getTime()).then(response => { + controlPropertyRule = response?.data || {}; + }); + + } + + /** + * 如果分类下没有属性或者所有属性都隐藏,则不展示分类 + */ + function checkIsHideCategory(cat: ElementPropertyConfig) { + if (cat.hide) { + return; + } + + cat.hide = !cat.properties.length; + + const visibleProp = cat.properties.find(p => p.visible !== false); + if (!visibleProp) { + cat.hide = true; + } + } + function filterCommandProperty(category: ElementPropertyConfig, allowedPropertyIds: string[]) { + if (allowedPropertyIds && category.properties) { + category.properties.forEach((eventInfo) => { + const { initialData } = eventInfo.editor; + // 已绑定事件 + initialData.boundEventsList = initialData.boundEventsList.filter((item) => { + return allowedPropertyIds.includes(item.boundEvents.label); + }); + // 事件列表 + initialData.events = initialData.events.filter((item) => { + return allowedPropertyIds.includes(item.label); + }); + + // 动态事件 + const switchEvents = initialData.getEventList(); + switchEvents.events = switchEvents.events.filter((item) => { + return allowedPropertyIds.includes(item.label); + }); + initialData.getEventList = () => { + return switchEvents; + }; + + category.hide = initialData.events.length === 0; + }); + } + } + /** + * 根据配置文件过滤属性 + */ + function filterPropertyEntity(propertyConfig: ElementPropertyConfig[], propertyData: any): ElementPropertyConfig[] { + if (propertyData?.type === 'Module') { + return propertyConfig; + } + if (!propertyConfig?.length || !propertyData || !controlPropertyRule[propertyData.type]?.length) { + return []; + } + let allowedPropertyIds = controlPropertyRule[propertyData.type]; + if (['form-group', 'data-grid-column'].includes(propertyData.type) && propertyData.editor) { + const editorPropertyIds = controlPropertyRule[propertyData.editor.type]; + if (editorPropertyIds?.length) { + allowedPropertyIds = allowedPropertyIds.concat(editorPropertyIds.map(propertyId => + propertyId.includes('events') ? propertyId.replace('events.', '') : `editor.${propertyId}`)); + } + + } + propertyConfig.forEach(category => { + if (!category.properties?.length) { + return; + } + + // 表达式属性都展示,不屏蔽 + if (category.categoryId === 'expressions') { + return; + } + // 过滤事件类属性 + if (category.categoryId.includes("eventsEditor")) { + filterCommandProperty(category, allowedPropertyIds); + return; + } + + // 分类使用级联特性,属性ID要拼接父ID + const categoryPrefix = category.parentPropertyID ? `${category.parentPropertyID}.` : ''; + category.properties = category.properties.filter(property => { + let propertyPrefix = property.parentPropertyID ? `${property.parentPropertyID}.` : ''; + + if (['class', 'style'].includes(property.propertyID) && !property.parentPropertyID && category.categoryId.toLocaleLowerCase() === 'appearance') { + propertyPrefix = 'appearance.'; + } + const propertyPath = `${categoryPrefix}${propertyPrefix}${property.propertyID}`; + + return allowedPropertyIds.includes(propertyPath); + }); + + checkIsHideCategory(category); + }); + propertyConfig = propertyConfig.filter(category => category.properties.length); + return propertyConfig; + } + /** + * 校验是否支持删除控件 + */ + function checkCanDeleteControl(propertyData: any, needNotify = true) { + if (!propertyData[identifyForNewControl]) { + if (needNotify) { + notifyService.warning({ position: 'top-center', message: '不允许删除基础表单的控件' }); + } + return false; + } + + return true; + } + /** + * 为控件增加定制标识 + */ + function appendIdentifyForNewControl(propertyData: any) { + if (propertyData) { + propertyData[identifyForNewControl] = true; + } + } + /** + * 为方法增加定制标识 + */ + function appendIdentifyForNewCommand(command: any) { + if (command) { + command[identifyForNewCommand] = true; + } + } + return { + designerMode, + toolboxItems, + componentsToRegister, + supportedControllers, + controllCategories, + useControlCreator, + getPageComponents, + useFormMetadataService, + getPropertyFilterRule, + filterPropertyEntity, + checkCanDeleteControl, + identifyForNewControl, + appendIdentifyForNewControl, + appendIdentifyForNewCommand + }; +} diff --git a/packages/designer/src/components/composition/events-editor-utils.ts b/packages/designer/src/components/composition/events-editor-utils.ts index d9ca3e13922ba076bff876d97f061a2cac014afb..c9a95b50adf31a881900eb1c10f1ff27fba62171 100644 --- a/packages/designer/src/components/composition/events-editor-utils.ts +++ b/packages/designer/src/components/composition/events-editor-utils.ts @@ -168,7 +168,7 @@ export function useEventsEditorUtils(commandService: UseFormCommandService, form handlerName: boundEventItem.command.handlerName, params: cloneDeep(boundEventItem.command.property), isNewGenerated: boundEventItem.command.isNewGenerated || false, - // isRTCmd: boundEventItem.command['isRTCmd'], + // isRtcCommand: boundEventItem.command['isRtcCommand'], isInvalid: boundEventItem.command.isInvalid || false, }, controller: { diff --git a/packages/designer/src/components/composition/form-metadata-converter.ts b/packages/designer/src/components/composition/form-metadata-converter.ts index aa8f734896c7e8c1cf829f0924fb2a4fb8aa2d2f..88aa146c702b5c507b6d3ecec293b173702bd510 100644 --- a/packages/designer/src/components/composition/form-metadata-converter.ts +++ b/packages/designer/src/components/composition/form-metadata-converter.ts @@ -1,21 +1,8 @@ /** - * 将现有表单元数据转换成vue设计器要求的结构 + * 将表单schema字段中的editor类型转为vue控件类型 */ export class FormMetadataConverter { - private componentTypeMapper: Record = { - Tab: 'tabs', - ToolBar: 'response-toolbar', - QueryScheme: 'query-solution', - Form: 'response-form', - Header: 'page-header', - GridField: 'data-grid-column', - TreeGridField: 'data-grid-column', - TabToolbarItem: 'tab-toolbar-item', - TabPage: 'tab-page', - ResponseToolbarItem: 'response-toolbar-item' - }; - private formGroupMapper: Record = { EnumField: 'combo-list', LookupEdit: 'input-group', @@ -36,81 +23,4 @@ export class FormMetadataConverter { public getRealEditorType(type: string) { return this.formGroupMapper[type || 'TextBox'] || type; } - public convertDesignerMetadata(formSchema: any) { - this.convertEntity(formSchema); - this.convertComponents(formSchema.module.components); - } - - /** - * 转换控件类型 - * @param component - * @returns - */ - private convertComponentType(component: any) { - const originalComponentType = component.type; - - // 输入类控件 - if (this.formGroupMapper[originalComponentType]) { - component.type = 'form-group'; - component.label = component.title; - component.editor = { - type: this.formGroupMapper[originalComponentType] - }; - - const properties = Object.keys(component); - - // 如果属性不是id等属性,则将其移到editor对象中 - for (const prop of properties) { - if (!["id", "type", "editor", "label", "appearance", "style", "binding", "visible", "path"].includes(prop)) { - component.editor[prop] = component[prop]; - // 删除原对象上的该属性 - delete component[prop]; - } - } - } - - // 类型转换 - if (this.componentTypeMapper[originalComponentType]) { - component.type = this.componentTypeMapper[component.type]; - return; - } - // 统一处理:将camel-case 转为kebab-case - component.type = component.type.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - } - - /** - * 转换子组件的componentType值 - */ - private convertChildComponentType(component: any) { - if (component && component.type === 'component' && component.componentType) { - component.componentType = component.componentType.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - } - } - - private convertComponents(components: any[]) { - components.forEach((component: any) => { - this.convertComponentType(component); - this.convertChildComponentType(component); - if (component.contents && component.contents.length) { - this.convertComponents(component.contents); - } - if (component.type === 'tab-page' && component.toolbar) { - this.convertComponentType(component.toolbar); - if (component.toolbar.contents && component.toolbar.contents.length) { - this.convertComponents(component.toolbar.contents); - } - } - - }); - } - - /** - * 转换实体节点 - */ - private convertEntity(domMetadata: any) { - if (domMetadata.module.schemas) { - domMetadata.module.entity = domMetadata.module.schemas; - } - } - } diff --git a/packages/designer/src/components/composition/form-metadata-rtc.service.ts b/packages/designer/src/components/composition/form-metadata-rtc.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..107b3d62439895ded6b0399039831f6c18b0edcd --- /dev/null +++ b/packages/designer/src/components/composition/form-metadata-rtc.service.ts @@ -0,0 +1,104 @@ +import axios from 'axios'; +import { DesignerProps } from '../designer.props'; +import { FormMetadaDataDom, UseFormSchema, UseFormMetadata, FormMetaDataModule, UseSchemaService } from '../types'; +import { useLocation } from './use-location'; +import { useFormMetadata } from './form-metadata.service'; +import { cloneDeep } from 'lodash-es'; +import { RuntimeSchemaDiffService } from './runtime/runtime-schema-diff.service'; +import { RuntimeComponentDiffService } from './runtime/runtime-component-diff.service'; + +export function useRtcFormMetadata( + props: DesignerProps, + useFormSchemaComposition: UseFormSchema, + schemaService: UseSchemaService): UseFormMetadata { + + /** 初始的表单元数据,用于在保存表单时做前后元数据内容的对比。 */ + let previousMetadataContent; + + /** 运行时定制,元数据查询、保存url */ + const rtcMetadataUrl = '/api/runtime/bcc/v1.0/template'; + + /** 获取表单元数据 */ + function queryMetadata(): Promise { + const { getHrefParam } = useLocation(); + + const dimension1 = getHrefParam('dim1'); + const dimension2 = getHrefParam('dim2'); + const metadataId = getHrefParam('metadataId'); + + return new Promise((resolve, reject) => { + + axios.get(`${rtcMetadataUrl}/${metadataId}`).then((response: any) => { + if (response?.data?.fieldTree && response?.data?.formContent) { + const { fieldTree, formContent } = response.data; + const formSchema = formContent.Contents; + + const formMetadataBasicInfo = { + id: formContent.Id, + code: formContent.Code, + name: formContent.Name, + resourceMetadataId: response.data.resourceMetadataId, + dimension1, + dimension2, + relativePath: '' + }; + useFormSchemaComposition.setFormMetadataBasicInfo(formMetadataBasicInfo); + useFormSchemaComposition.setFormSchema(formSchema); + + previousMetadataContent = { + Id: formContent.Id, + Contents: cloneDeep(formSchema) + }; + schemaService.rtcSchemaFields.value = fieldTree; + + resolve(formSchema); + } + }); + }); + + } + function saveFormMetadata() { + const currentFormSchema = useFormSchemaComposition.getFormSchema(); + const currentFormModule = useFormSchemaComposition.getModule(); + const schemaDiffService = new RuntimeSchemaDiffService(schemaService); + const componentsDiffService = new RuntimeComponentDiffService(); + const { addedFields, modifiedFields } = schemaDiffService.getChanges(previousMetadataContent.Contents.module, currentFormModule); + const { newLookupConfigs, deletedLookupConfigs, modifiedLookupConfigs } = componentsDiffService.getLookupConfigsChanges(previousMetadataContent.Contents.module.components, currentFormModule.components); + const voChanges = { + added: addedFields, + modified: modifiedFields, + newLookupConfigs, + deletedLookupConfigs, + modifiedLookupConfigs, + }; + const currentMetadataContent = { + Id: previousMetadataContent.Id, + Contents: JSON.stringify(currentFormSchema) + }; + const body = { + voChanges, + content: currentMetadataContent, + voId: currentFormModule.entity[0].id, + formId: previousMetadataContent.Id, + eapiId: currentFormModule.entity[0].eapiId, + }; + return new Promise((resolve, reject) => { + axios.put(`${rtcMetadataUrl}/`, body).then(() => { + previousMetadataContent.Contents = cloneDeep(currentFormSchema); + resolve(null); + }, (error) => { + reject(error); + }); + }); + + } + /** + * 获取拖拽控制规则:合并公共规则和模板的特定规则 + */ + function queryFormTemplateRule(formModule: FormMetaDataModule): Promise { + return useFormMetadata(props, useFormSchemaComposition).queryFormTemplateRule(formModule); + } + + return { queryMetadata, saveFormMetadata, queryFormTemplateRule }; + +} diff --git a/packages/designer/src/components/composition/form-metadata.service.ts b/packages/designer/src/components/composition/form-metadata.service.ts index 49fd467c3985cf46a06e047fe416046502df5aba..12fe8d3a7dfbe380ee2df039e1c97a2f74869464 100644 --- a/packages/designer/src/components/composition/form-metadata.service.ts +++ b/packages/designer/src/components/composition/form-metadata.service.ts @@ -1,11 +1,10 @@ import axios from 'axios'; import { mergeWith, omit } from 'lodash-es'; import { DesignerProps } from '../designer.props'; -import { FormMetadataConverter } from './form-metadata-converter'; import { FormMetadaDataDom, MetadataDto, MetadataPathToken, UseFormSchema, UseFormMetadata, FormMetaDataModule } from '../types'; import { inject } from 'vue'; import { MetadataService } from './metadata.service'; -import {FNotifyService} from '@farris/ui-vue/components'; +import { FNotifyService } from '@farris/ui-vue/components'; export function useFormMetadata(props: DesignerProps, useFormSchemaComposition: UseFormSchema): UseFormMetadata { @@ -43,10 +42,6 @@ export function useFormMetadata(props: DesignerProps, useFormSchemaComposition: axios.get(url).then((response) => { const formSchema = JSON.parse(response.data.content).Contents; - - if (!response.data.properties || response.data.properties.framework !== 'Vue') { - new FormMetadataConverter().convertDesignerMetadata(formSchema); - } const formMetadataBasicInfo = omit(response.data, 'content') as MetadataDto; useFormSchemaComposition.setFormMetadataBasicInfo(formMetadataBasicInfo); @@ -79,6 +74,7 @@ export function useFormMetadata(props: DesignerProps, useFormSchemaComposition: ExtendProperty: formMetadataBasicInfo.extendProperty, NameLanguage: formMetadataBasicInfo.nameLanguage ? formMetadataBasicInfo.nameLanguage : null, Properties: formMetadataBasicInfo.properties, + Extendable: formMetadataBasicInfo.extendable, content: JSON.stringify(metadataContent) }; diff --git a/packages/designer/src/components/composition/metadata.service.ts b/packages/designer/src/components/composition/metadata.service.ts index 5ece93469a76e0068d6742021b5469f001bf6a5f..b0b65c860fa9e74c60d99130ca15343f0c8cde30 100644 --- a/packages/designer/src/components/composition/metadata.service.ts +++ b/packages/designer/src/components/composition/metadata.service.ts @@ -1,8 +1,12 @@ import axios from 'axios'; +import { DesignerMode } from '../types/designer-context'; +import { useDesignerContext } from './designer-context/use-designer-context'; import { useLocation } from './use-location'; export class MetadataService { + private designerMode = useDesignerContext().designerMode; + /** 低代码获取元数据url */ private metadataBasePath = '/api/dev/main/v1.0/metadatas'; /** @@ -10,6 +14,10 @@ export class MetadataService { */ private metadataServicePath = '/api/dev/main/v1.0/mdservice'; + /** 运行时定制获取元数据url */ + private rtcMetadataBasePath = '/api/runtime/lcm/v1.0/rt-metadatas'; + + public getMetadataPath() { const { getUrlParam } = useLocation(); let metadataPath = getUrlParam('id') || ''; @@ -23,25 +31,20 @@ export class MetadataService { return metadataPath; } - /** - * 根据元数据Id查询元数据 - * @param relativePath 相对路径 - * @param metadataId 元数据id - * @returns - */ - public queryMetadataById(relativePath: string, metadataId: string): Promise { - const url = this.metadataBasePath + '/relied?metadataPath=' + relativePath + '&metadataID=' + metadataId; - return axios.get(url); - } - /** * 根据元数据类型查询元数据 * @param relativePath * @param metadataType * @returns */ - public GetMetadataListByType(relativePath: string, metadataType: string): Promise { - const url = this.metadataBasePath + '?path=' + relativePath + '&metadataTypeList=' + metadataType; + public getMetadataListByType(relativePath: string, metadataType: string): Promise { + let url; + if (this.designerMode === DesignerMode.PC_RTC) { + url = `${this.rtcMetadataBasePath}?metadataTypes=${metadataType}`; + } else { + url = `${this.metadataBasePath}?path=${relativePath}&metadataTypeList=${metadataType}`; + } + // const url = this.metadataBasePath + '?path=' + relativePath + '&metadataTypeList=' + metadataType; return axios.get(url); } @@ -52,9 +55,13 @@ export class MetadataService { * @param {?} sessionId * @return {?} */ - public GetRefMetadata(path, metadataId): Promise { - // gsp.cache.get('sessionId'); - const url = this.metadataBasePath + '/relied?metadataPath=' + path + '&metadataID=' + metadataId; + public getRefMetadata(relativePath: string, metadataId: string): Promise { + let url; + if (this.designerMode === DesignerMode.PC_RTC) { + url = `${this.rtcMetadataBasePath}/${metadataId}`; + } else { + url = `${this.metadataBasePath}/relied?metadataPath=${relativePath}&metadataID=${metadataId}`; + } return axios.get(url); } @@ -64,8 +71,7 @@ export class MetadataService { * @param {?} typeName * @return {?} */ - public GetMetadataList(spacePath, typeName) { - // var headers = new HttpHeaders().set('SessionId', this.sessionId); + public getMetadataList(spacePath, typeName) { const url = this.metadataServicePath + '?path=' + spacePath + '&metadataTypeList=' + typeName; return axios.get(url); }; @@ -93,28 +99,47 @@ export class MetadataService { * @param pageSize * @returns */ - public getAllMetadataList(relativePath: string, metaddataType: string, pageSize = 1000) { - const url = `${this.metadataServicePath}/unionmdlist?pageIndex=1&pageSize=${pageSize}` + - '&path=' + relativePath + '&metadataTypeList=' + metaddataType; + public getAllMetadataList(relativePath: string, metadataType: string, pageSize = 1000) { + let url = `${this.metadataServicePath}/unionmdlist?path=${relativePath}&`; - return axios.get(url).then((res: any) => { + if (this.designerMode === DesignerMode.PC_RTC) { + url = `${this.rtcMetadataBasePath}/rtmetadatalist?`; + } + return axios.get(`${url}pageIndex=1&pageSize=${pageSize}&metadataTypeList=${metadataType}`).then((res: any) => { const totalNum = res.data['page']['total'] || 0; if (pageSize !== totalNum && totalNum > 1000) { - return this.getAllMetadataList(relativePath, metaddataType, totalNum); + return this.getAllMetadataList(relativePath, metadataType, totalNum); } return res; }); } public getPickMetadata(relativePath: string, data: any) { - const url = this.metadataServicePath + '/pickMetadata?currentPath=' + relativePath; - return axios.post(url, data).then((res: any) => { - return res.data; - }); + if (this.designerMode === DesignerMode.PC_RTC) { + const url = `${this.rtcMetadataBasePath}/${data?.id}`; + return axios.get(url, data).then((res: any) => { + return { metadata: res.data }; + }); + } else { + const url = this.metadataServicePath + '/pickMetadata?currentPath=' + relativePath; + return axios.post(url, data).then((res: any) => { + return res.data; + }); + } } - public saveMetadata(metadataDto: any) { - return axios.put(this.metadataBasePath, metadataDto); + public saveMetadata(metadataDto: any, formBasicInfo?: any) { + if (this.designerMode === DesignerMode.PC_RTC) { + const { dimension1, dimension2 } = formBasicInfo; + return axios.post(this.rtcMetadataBasePath, { + metadataDto, + firstDimension: dimension1, + secondDimension: dimension2 + }); + } else { + return axios.put(this.metadataBasePath, metadataDto); + } + } public validateRepeatName(path: string, fileName: string) { diff --git a/packages/designer/src/components/composition/runtime/runtime-component-diff.service.ts b/packages/designer/src/components/composition/runtime/runtime-component-diff.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..2bc32d8e4fa8ab5d41610f859fb55487d3dc1cbb --- /dev/null +++ b/packages/designer/src/components/composition/runtime/runtime-component-diff.service.ts @@ -0,0 +1,122 @@ + +/** + * 运行时定制:帮助控件对比服务 + */ +class LookupDiffService { + + private lookupConfigs = new Map(); + + public getLookupConfigs() { + return this.lookupConfigs; + } + + public findLookupConfigs(components: any[]) { + if (components && components.length) { + components.forEach(component => { + if ((component.type === 'query-solution' || component.type === 'filter-bar') && component.fields) { + this.findLookupConfigInFilter(component.fields); + } + if (component?.editor?.type === 'lookup') { + this.findLookupConfigInCard(component.editor); + } + if (component.type === 'data-grid' && component.columns) { + this.findLookupConfigInGrid(component.columns); + } + this.findLookupConfigs(component['contents']); + }); + + } + } + + /** + * 提取列表中的帮助 + */ + private findLookupConfigInGrid(columns: any[]) { + columns.forEach(column => { + if (column.editor?.type === 'lookup') { + this.findLookupConfigInCard(column.editor); + } + }); + } + + /** + * 提取卡片中的帮助 + */ + private findLookupConfigInCard(componentEditor: any) { + const lookupId = componentEditor['helpId']; + if (componentEditor.dataSource?.uri) { + const uri = componentEditor.dataSource.uri.replace('.', '/'); + if (!this.lookupConfigs.has(uri)) { + this.lookupConfigs.set(uri, { uri, lookupId }); + } + } + } + + /** + * 提取筛选条和筛选方案中的帮助配置 + */ + private findLookupConfigInFilter(fieldConfigs: any[]) { + let uri: string, lookupId: string, conditions: any; + fieldConfigs.forEach(field => { + const { controlType } = field; + if (controlType && ['lookup', 'combo-lookup'].includes(controlType) && field.editor) { + uri = field.editor.uri.replace('.', '/'); + lookupId = field.editor.helpId; + if (!this.lookupConfigs.has(uri)) { + this.lookupConfigs.set(uri, { uri, lookupId }); + } + } + }); + } +} + +/** + * 运行时定制:控件元数据差异对比服务 + */ +export class RuntimeComponentDiffService { + + public getLookupConfigsChanges(previous: any[], current: any[]): any { + + const currentLookupDiff = new LookupDiffService(); + currentLookupDiff.findLookupConfigs(current); + const currentLookupConfigs = currentLookupDiff.getLookupConfigs(); + + const previousLookupDiff = new LookupDiffService(); + previousLookupDiff.findLookupConfigs(previous); + const previousLookupConfigs = previousLookupDiff.getLookupConfigs(); + + const newLookupConfigs: any = []; + currentLookupConfigs.forEach((value, key) => { + if (!previousLookupConfigs.has(key)) { + newLookupConfigs.push(value); + } + }); + const deletedLookupConfigs: any = []; + previousLookupConfigs.forEach((value, key) => { + if (!currentLookupConfigs.has(key)) { + deletedLookupConfigs.push(value['uri']); + } + }); + const modifiedLookupConfigs = this.findModifiedLookup(currentLookupConfigs, previousLookupConfigs); + return { + newLookupConfigs: newLookupConfigs, + deletedLookupConfigs: deletedLookupConfigs, + modifiedLookupConfigs: modifiedLookupConfigs + }; + } + + private findModifiedLookup(current: Map, previous: Map): any[] { + const modifiedLookupConfigs: any = []; + let currentFilter: string, previousFilter: string; + current.forEach((value, key, map) => { + if (previous.has(key)) { + currentFilter = value['conditions']; + previousFilter = previous.get(key)['conditions']; + if (currentFilter !== previousFilter || value['lookupId'] !== previous.get(key)['lookupId']) { + modifiedLookupConfigs.push(value); + } + } + }); + return modifiedLookupConfigs; + } +} diff --git a/packages/designer/src/components/composition/runtime/runtime-schema-diff.service.ts b/packages/designer/src/components/composition/runtime/runtime-schema-diff.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..3697479d54718cc66f4eea0e5ae65e0cb095a082 --- /dev/null +++ b/packages/designer/src/components/composition/runtime/runtime-schema-diff.service.ts @@ -0,0 +1,253 @@ +import { RuntimeSchemaService } from './runtime-schema.service'; +import { FormMetaDataModule, FormSchemaEntity, FormSchemaEntityField, UseSchemaService } from '../../types'; + +/** + * 运行时定制:表单实体差异对比服务 + */ +export class RuntimeSchemaDiffService { + // 新添加的字段、子表 + addedTreeData: any[] = []; + // 平铺的变更集合 + changeList = []; + // 变更集合 + changeContrast = {}; + // 当前正在处理的entity + currentSchemaEntity: FormSchemaEntity | undefined; + // 需同步VO的changes + changedMap = new Map(); + + + constructor(private schemaService: UseSchemaService) { } + private initParams() { + this.addedTreeData = []; + this.changeList = []; + this.changeContrast = {}; + this.currentSchemaEntity = undefined; + this.changedMap = new Map(); + } + /* + * modified: Map + * addedMap: TreeNode[]: [{data: {id,name,code,label,primary?}, children: [字段信息 ...]} ... ] + */ + public getChanges(previous: FormMetaDataModule, current: FormMetaDataModule): any { + this.initParams(); + this.recursiveNewSchema(previous.entity[0].entities, current.entity[0].entities); + this.setAddedTreeData(); + this.findEnumChanges(previous.viewmodels, current.viewmodels); + return { addedFields: this.addedTreeData, modifiedFields: this.changeMapToObj(this.changedMap) }; + } + /* + * 获取新增字段/子表(内含字段) + * @param oldSchemaEntities + * @param newSchemaEntities + * @param parentEntityId 暂时未用 + */ + private recursiveNewSchema(oldSchemaEntities: FormSchemaEntity[], newSchemaEntities: FormSchemaEntity[], parentEntityId: string = '') { + if (!oldSchemaEntities || !newSchemaEntities || newSchemaEntities.length === 0) { + return; + } + newSchemaEntities.forEach(entity => { + const oldEntity = oldSchemaEntities.find(e => e.id === entity.id); + if (!oldEntity) { // 新增表 + const children = entity.type.fields.map(field => { + return { data: field, selectable: true }; + }); + this.addedTreeData.push({ data: entity, selectable: true, children, expanded: true }); + return; + } + const added = this.recursiveField(entity.type.fields, oldEntity.type.fields, entity.id, entity.id); + + const { type, ...basicEntity } = entity; + if (added.length > 0) { + this.addedTreeData.push({ data: basicEntity, selectable: false, children: added, expanded: true }); + } + if (entity.type.entities && entity.type.entities.length > 0) { + const oldChildEntities = oldEntity?.type?.entities || []; + this.recursiveNewSchema(oldChildEntities, entity.type.entities, entity.id); + } + }); + } + + private recursiveField(newFields: FormSchemaEntityField[], oldFields: FormSchemaEntityField[], parentId: string, entityId: string) { + const added: any = []; + newFields.forEach(newField => { + if (!oldFields) { + added.push({ data: newField, selectable: true }); + return; + } + const oldField = oldFields.find(f => f.id === newField.id); + if (!oldField) { + added.push({ data: newField, selectable: true }); + return; + } + // 比较默认值是否变化 + this.checkDefaultValueDiff(oldField, newField, entityId); + + // 字段类型相同,并且有下级字段:遍历下级字段 + if (oldField.type.name === newField.type.name && newField.type.fields) { + const childAddedFields = this.recursiveField(newField.type.fields, oldField.type.fields || [], newField.id, entityId); + if (childAddedFields.length > 0) { + added.push({ data: newField, selectable: false, children: childAddedFields, expanded: true }); + } + } + }); + return added; + } + + /** + * 对比schema字段默认值 + * @param oldField 旧字段 + * @param newField 新字段 + * @param entityId 字段所属实体id + */ + private checkDefaultValueDiff(oldField: FormSchemaEntityField, newField: FormSchemaEntityField, entityId: string) { + + // 默认值存在表达式对象的场景,故转换成字段串后再比较 + let oldDefaultValue = oldField.defaultValue; + oldDefaultValue = oldDefaultValue && typeof (oldDefaultValue) === 'object' ? JSON.stringify(oldDefaultValue) : oldDefaultValue; + + let newDefaultValue = newField.defaultValue; + newDefaultValue = newDefaultValue && typeof (newDefaultValue) === 'object' ? JSON.stringify(newDefaultValue) : newDefaultValue; + + if (oldDefaultValue !== newDefaultValue) { + this.setChangeMap(entityId, { + id: newField.id, + propCode: 'defaultValue', + preValue: oldField.defaultValue, + curValue: newField.defaultValue + }); + } + } + private setAddedTreeData() { + const addedTmp = this.addedTreeData.map(treeData => { + // 寻找完整实体树对应表里的全部字段 + const elements = this.schemaService.getRtcSchemaFieldsByEntity(treeData.data.id); + // 找到对应的表 + if (elements) { + const children = treeData.children.map(addedField => { + // 判断新增字段是否已经在VO,BE上存在 + const addedEle: any = Object.values(elements).find((ele: any) => ele.code === addedField.data.code); + // 如果存在, 把来源类型(Be,Vo)和源字段信息返回 + if (addedEle) { + delete addedEle.schemaField; + addedField['sourceType'] = addedEle.type; + addedField['source'] = addedEle; + } + return addedField; + }); + treeData.children = children; + } + // 如果没有找到对应表,证明是新增子表,直接返回 + return treeData; + }); + this.addedTreeData = addedTmp; + } + + private findEnumChanges(previous: any[], current: any[]) { + + let vmId: string; + for (const currentVm of current) { + // 如果无字段,略过 + if (!currentVm.fields || currentVm.fields.length === 0) { + continue; + } + + vmId = currentVm.id; + const previousVm = previous.find(item => item.id === vmId); + for (const field of currentVm.fields) { + // 不是扩展字段,略过 + if (!field.fieldName.startsWith("ext_") || !field.fieldName.endsWith("_Lv9")) { + continue; + } + // 如果不是枚举字段,略过 + if (!this.isEnumField(field.id, vmId)) { + continue; + } + const cur_type = field.fieldSchema.type; + // 如果没有修改枚举值,略过 + if (!cur_type || !cur_type.enumValues) { + continue; + } + let pre_field = { + fieldSchema: { + type: { + enumValues: [] + } + } + }; + + if (previousVm) { + const index = previousVm.fields.findIndex(item => item.id === field.id); + if (index > -1) { + pre_field = previousVm.fields[index]; + } + } + + const pre_type = pre_field.fieldSchema.type; + + const pre_enumValue_string = pre_type ? JSON.stringify(pre_type.enumValues) : undefined; + const cur_enumValue_string = JSON.stringify(cur_type.enumValues); + // 如果枚举值没有变化,略过 + if (pre_enumValue_string === cur_enumValue_string) { + continue; + } + + const tableInfo = this.schemaService.getTableInfoByViewModelId(vmId); + const isAddedInSchema = tableInfo && this.isAddedInSchema(tableInfo.id, field.id); + // 如果已经在schema中添加过,不需要添加到modify + if (isAddedInSchema || !tableInfo) { + continue; + } + + this.setChangeMap(tableInfo.id, { + id: field.id, + propCode: 'enumValue', + preValue: pre_type ? pre_type.enumValues : null, + curValue: cur_type.enumValues + }); + } + } + } + /** + * 由于查找schema新增内容在前,查找viewModel变换在后 + * 调用时 this.addedTreeData 已经记录了新增信息 + * 新增过的内容,不需要放在modify内容中 + */ + private isAddedInSchema(tableId: string, fieldId: string): boolean { + if (this.addedTreeData.length === 0) { + return false; + } + const tableIndex = this.addedTreeData.findIndex(table => tableId === table.data.id) + if (tableIndex < 0) { + return false; + } + + const fieldIndex = this.addedTreeData[tableIndex].children.findIndex(field => field.data.id === fieldId); + return fieldIndex > -1; + } + + private setChangeMap(tableId: string, changeItem: any) { + if (this.changedMap.has(tableId)) { + this.changedMap.get(tableId).push(changeItem); + } else { + this.changedMap.set(tableId, [changeItem]); + } + } + + private changeMapToObj(map: Map) { + const obj = {}; + map.forEach((value, key) => { + obj[key] = value; + }); + return obj; + } + + private isEnumField(id: string, vmId: string) { + const fieldInfo = this.schemaService.getFieldByIDAndVMID(id, vmId); + if (fieldInfo?.schemaField && 'EnumType' === fieldInfo.schemaField.type.$type) { + return true; + } else { + return false; + } + } +} diff --git a/packages/designer/src/components/composition/schema-repository/controller/controller-selector.service.ts b/packages/designer/src/components/composition/schema-repository/controller/controller-selector.service.ts index ccdcaedefbd1b8dee1ad26b02c1adb3ba40c4609..4932f15e9fefe8884e22372d2999389432dae996 100644 --- a/packages/designer/src/components/composition/schema-repository/controller/controller-selector.service.ts +++ b/packages/designer/src/components/composition/schema-repository/controller/controller-selector.service.ts @@ -10,7 +10,7 @@ export class ControllerSelectorSchemaService { public getNavigationData = (searchingText: string, pagination: SchemaRepositoryPagination): SchemaCategory[] => { return this.designerContext.controllCategories; - } + }; public getRecentlyData(searchingText: string, pagination: SchemaRepositoryPagination): SchemaItem[] { return []; @@ -48,7 +48,13 @@ export class ControllerSelectorSchemaService { public getSchemaData = async (searchingText: string, pagination: SchemaRepositoryPagination, editorParams): Promise => { const { relativePath } = editorParams.formBasicInfo; const allMetadataRes = await this.metadataService?.getAllMetadataList(relativePath, this.metadataType); - const items = allMetadataRes.data.metadataIndexItems ? allMetadataRes.data.metadataIndexItems : allMetadataRes.data; + let items = allMetadataRes.data; + if (items.metadataIndexItems) { + items = items.metadataIndexItems; + } + if (items.list) { + items = items.list.map(item => item.metadata); + } return this.metadata2SchemaItem(items, 'all'); }; } diff --git a/packages/designer/src/components/composition/schema-repository/form/form-selector.service.ts b/packages/designer/src/components/composition/schema-repository/form/form-selector.service.ts index f8548a5817b584f4116a644bdf2e590b7a93c73a..2ff87a1116d442dc2f62863e0759edb95b3ff886 100644 --- a/packages/designer/src/components/composition/schema-repository/form/form-selector.service.ts +++ b/packages/designer/src/components/composition/schema-repository/form/form-selector.service.ts @@ -36,7 +36,13 @@ export class FormSelectorSchemaService { public getSchemaData = async (searchingText: string, pagination: SchemaRepositoryPagination, editorParams): Promise => { const { relativePath } = editorParams.formBasicInfo; const allMetadataRes = await this.metadataService?.getAllMetadataList(relativePath, this.metadataType); - const items = allMetadataRes.data.metadataIndexItems ? allMetadataRes.data.metadataIndexItems : allMetadataRes.data; + let items = allMetadataRes.data; + if (items.metadataIndexItems) { + items = items.metadataIndexItems; + } + if (items.list) { + items = items.list.map(item => item.metadata); + } return this.metadata2SchemaItem(items, 'all'); }; } diff --git a/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts b/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts index 1d1d96faff5e4dd54d23a8205d72aaa360a4f452..467851f1916273c2d1daa50b4e2ae7a9effb9cc6 100644 --- a/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts +++ b/packages/designer/src/components/composition/schema-repository/lookup/lookup-field-selector.service.ts @@ -48,17 +48,15 @@ export class LookupFieldSelectorService { getData(editorParams: any) { const { propertyData, formBasicInfo } = editorParams; const metadataPath = formBasicInfo?.relativePath; - if (!metadataPath) { - return; - } - return this.metadataService && this.metadataService.GetRefMetadata(metadataPath, propertyData?.helpId).then((res) => { + + return this.metadataService && this.metadataService.getRefMetadata(metadataPath, propertyData?.helpId).then((res) => { const metadata = JSON.parse(res.data.content); return metadata && metadata.schema && metadata.schema.main && this.buildTreeData(metadata.schema.main); }); } private async getMetadata(id: string) { - return await this.metadataService.queryMetadataById('', id).then(res => res.data); + return await this.metadataService.getRefMetadata('', id).then(res => res.data); } async getLookupConditions(editorParams: any) { @@ -165,12 +163,12 @@ export class LookupFieldSelectorService { Type: voMetadata.type, BizobjectID: voMetadata.bizobjectID, ExtendProperty: voMetadata.extendProperty, - Extendabl: voMetadata.extendable, + Extendable: voMetadata.extendable, NameLanguage: !voMetadata.nameLanguage ? null : voMetadata.nameLanguage, Properties: voMetadata.properties, }; - return this.metadataService.saveMetadata(content); + return this.metadataService.saveMetadata(content, formBasicInfo); }); } diff --git a/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts b/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts index 6ae7030dc6259e3df61c70ec89770d1a89bdd4b0..66a64d3c5d6799b9add670a1843f9b8acd083906 100644 --- a/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts +++ b/packages/designer/src/components/composition/schema-repository/lookup/lookup-schema.service.ts @@ -43,9 +43,15 @@ export class LookupSchemaService { }; getSchemaData = async (searchingText: string, pagination: SchemaRepositoryPagination, editorParams): Promise => { - const {relativePath} = editorParams.formBasicInfo; + const { relativePath } = editorParams.formBasicInfo; const allMetadataRes = await this.metadataService?.getAllMetadataList(relativePath, this.metadataType); - const items = allMetadataRes.data.metadataIndexItems ? allMetadataRes.data.metadataIndexItems: allMetadataRes.data; + let items = allMetadataRes.data; + if (items.metadataIndexItems) { + items = items.metadataIndexItems; + } + if (items.list) { + items = items.list.map(item => item.metadata); + } return this.metadata2SchemaItem(items, 'all'); }; } diff --git a/packages/designer/src/components/composition/schema.service.ts b/packages/designer/src/components/composition/schema.service.ts index 17c50fb2c34639a2f65f09d0a887f3691b5bca93..de0dc8a34488ada20160204a4e7dccaa24faffad 100644 --- a/packages/designer/src/components/composition/schema.service.ts +++ b/packages/designer/src/components/composition/schema.service.ts @@ -1,6 +1,10 @@ import axios from "axios"; +import { Ref, ref } from "vue"; import { FormSchema, FormSchemaEntity, FormSchemaEntityField, FormSchemaEntityField$Type, FormSchemaEntityFieldType$Type, FormSchemaEntityFieldTypeName, UseFormMetadata, UseFormSchema, UseSchemaService } from "../types"; +import { DesignerMode } from "../types/designer-context"; import { MetadataService } from "./metadata.service"; +import { cloneDeep } from 'lodash-es'; + /** * 操作表单DOM Schema的工具类 */ @@ -12,6 +16,16 @@ export function useSchemaService( /** 表单更新schema产生的变更记录,用于控件同步自身属性。页面重刷结束后,依赖实体树组件将此属性重置为null */ let entityChangeset: any; + /** 运行时定制:打开表单时存储完整的字段信息 */ + const rtcSchemaFields: Ref = ref(); + + // 运行时定制:{实体ID:实体中新增的字段树节点集合} + const rtcAddedTreeNodes: Ref = ref({}); + + // 运行时定制:平铺所有新增字段树节点(平铺关联带出字段) + const rtcSerializedAddedTreeNodes: Ref = ref([]); + + function getSchemaEntities(): FormSchemaEntity[] { const schema = useFormSchema.getSchemas(); return schema?.entities || []; @@ -340,60 +354,18 @@ export function useSchemaService( if (!fields) { return; } - return getFieldInfoByID(fields, '', id); - } - - /** - * 根据字段path和ViewModelId获取字段信息(包括关联表字段) - * 返回对象 {实体,是否关联字段,关联字段的dataField} - * @param path 字段标识 - * @param viewModelId 视图模型标识 - */ - function getFieldByPathAndVMID(path: string, viewModelId: string): { - schemaField: FormSchemaEntityField, isRefElement: boolean, refElementLabelPath: string - } | undefined { - const entities = getSchemaEntities(); - if (!entities || entities.length === 0) { - return; - } - const vm = useFormSchema.getViewModelById(viewModelId); - const fields = getTableFieldsByBindTo(entities, vm?.bindTo || ''); - if (!fields) { - return; - } - return getFieldInfoByPath(fields, '', path); - } - - function getTableLabelByVMID(viewModelId: string) { - const entities = getSchemaEntities(); - if (!entities || entities.length === 0) { - return; - } - const vm = useFormSchema.getViewModelById(viewModelId); - return _getTableLabelByUri(entities, vm?.bindTo || ''); - } - - /** - * 定位分级码字段(返回第一个类型为HierarchyType的字段) - * @param viewModelId 视图模型标识 - */ - function getTreeGridUdtField(viewModelId: string) { - const entities = getSchemaEntities(); - if (!entities || entities.length === 0) { - return; + const fieldInfo = getFieldInfoByID(fields, '', id); + if (fieldInfo?.schemaField) { + return fieldInfo; } - const vm = useFormSchema.getViewModelById(viewModelId); - const fields = getTableFieldsByBindTo(entities, vm?.bindTo || ''); - if (!fields) { - return ''; - } - for (const element of fields) { - if (element.type && element.type.$type === 'HierarchyType') { - return element.label; + // 若是运行时定制环境,从be或vo字段中查找 + if (useFormSchema.designerMode === DesignerMode.PC_RTC) { + const rtcFieldNode = rtcSerializedAddedTreeNodes.value?.find(node => node.data?.id === id); + if (rtcFieldNode) { + return { schemaField: rtcFieldNode.data, isRefElement: false, refElementLabelPath: '' }; } } - return ''; } /** @@ -419,45 +391,6 @@ export function useSchemaService( return udtFields; } - /** - * schema字段集合组装成树 - * @param fields schema字段集合 - */ - function assembleFields2Tree(fields: FormSchemaEntityField[], expandRelateNode = true, displayedFieldsMap: Map | null = null, label = '') { - const treeData = [] as any; - fields.forEach(element => { - // 零代码:不展示id等属性 - // if (formBasicService && formBasicService.envType === DesignerEnvType.noCode && - // ['id', "version", "processInstance", "parentID"].includes(element.bindingField)) { - // return; - // } - // 补充bindingPath属性 - if (!element.bindingPath) { - element.bindingPath = (label ? label + '.' : '') + element.label; - } - - // 处理字段类型的国际化 - // element.type.displayName = EntityFieldTypeDisplayNamei18n[element.type.name] || element.type.displayName; - - // 关联表字段 / UDT字段 - let children = []; - if (element.type && element.type.fields && element.type.fields.length > 0) { - children = assembleFields2Tree(element.type.fields, true, displayedFieldsMap, element.bindingPath); - } - - treeData.push({ - data: element, - children, - expanded: expandRelateNode, - selectable: children.length > 0 ? false : true, - isUsed: displayedFieldsMap && displayedFieldsMap.has(element.id), - tips: element.name + '[' + element.id + ']' - }); - - }); - return treeData; - } - /** * 国际化:schema字段类型 * @param fields 实体下的字段集合 @@ -502,7 +435,7 @@ export function useSchemaService( */ function convertViewObjectToEntitySchema(viewObjectId: string, sessionId: string) { // 1、schema.id 查询VO实体 - return metadataService.GetRefMetadata('', viewObjectId).then(result => { + return metadataService.getRefMetadata('', viewObjectId).then(result => { if (result && result.data && result.data.content) { const viewObjectMetadataContent = JSON.parse(result.data.content); // 2、将VO实体转为schema @@ -535,35 +468,13 @@ export function useSchemaService( return getTableFieldsByBindTo(entities, vm.bindTo); } - function getPrimaryField(viewModelId: string): string { + function getPrimaryField(): string { const entities = getSchemaEntities(); if (!entities || entities.length === 0) { return ''; - - } - return entities[0].type.primary; - } - - /** - * 根据实体获取VM id,之前用于实体树的拖拽 - * @param entity 实体 - */ - function getViewModelIdByEntity(entity: FormSchemaEntity): string { - if (!entity) { - return ''; } - const viewModels = useFormSchema.getViewModels(); - const entities = getSchemaEntities(); - const mappingViewModel = viewModels.find(viewModel => { - if (viewModel.id === 'root-viewmodel') { - return false; // root viewmodel 不对应任何SchemaEntity - } - const info = _getTableBasicInfoByUri(entities, viewModel.bindTo); - return info.id === entity.id; - }); - // 找到对应的viewmodel返回id,找不到返回undefined。 - return mappingViewModel && mappingViewModel.id || ''; + return entities[0].type.primary; } /** @@ -596,98 +507,148 @@ export function useSchemaService( } /** - * 字段名称映射更改 + * 运行时定制场景:获取某实体下来源于be或vo的字段(不在当前表单entity内的字段) */ - function fieldsDisplayNameUpdate(entity: FormSchemaEntityField[]) { - entity.forEach((item) => { - if (item.$type === FormSchemaEntityField$Type.SimpleField) { - switch (item.type.$type) { - case FormSchemaEntityFieldType$Type.NumericType: - if (item.type.precision === 0) { - item.type.displayName = '整数'; - } - if (item?.type?.precision && item?.type?.precision > 0) { - item.type.displayName = '浮点数字'; - } - break; - case FormSchemaEntityFieldType$Type.StringType: - item.type.displayName = '文本'; - break; - case FormSchemaEntityFieldType$Type.TextType: - item.type.displayName = '备注'; - break; + function getRtcSchemaFieldsByEntity(targetEntityId: string, rtSchemaNode?: any) { + if (!rtSchemaNode) { + rtSchemaNode = rtcSchemaFields.value.mainNode; + } + if (rtSchemaNode?.id === targetEntityId) { + return rtSchemaNode.elements; + } + if (rtSchemaNode?.childNodes) { - default: - break; + if (rtSchemaNode.childNodes[targetEntityId]) { + return rtSchemaNode.childNodes[targetEntityId].elements; + } + const childEntityIds = Object.keys(rtSchemaNode.childNodes); + if (childEntityIds && childEntityIds.length) { + for (const id of childEntityIds) { + const childElements = getRtcSchemaFieldsByEntity(targetEntityId, rtSchemaNode.childNodes[id]); + if (childElements) { + return childElements; + } } + } + } + } + /** + * schema字段集合组装成树 + * @param fields schema字段集合 + */ + function assembleRtcFieldsToTree(fields: FormSchemaEntityField[], rtRelateParentSchemaField: any, entityId: string) { + const treeData: any = []; + fields.forEach(element => { + // 关联表字段 / UDT字段 + let children = []; + if (element.type && element.type.fields && element.type.fields.length > 0) { + children = assembleRtcFieldsToTree(element.type.fields, rtRelateParentSchemaField, entityId); } + const node = { + data: element, + children, + draggable: children.length === 0, + // 关联带出字段:记录父节点,用于添加schema节点 + rtRelateParentSchemaField: rtRelateParentSchemaField, + entityId + }; + treeData.push(node); + + rtcSerializedAddedTreeNodes.value.push(node); }); + return treeData; } - /** - * 删除schema实体 - * @param entityId 实体id + * 运行时定制场景:合并来源于be和vo字段,返回完整的实体树结构 */ - function deleteSchemaEntityById(entityId: string) { - - const schemaEntities = getSchemaEntities(); - if (!schemaEntities || schemaEntities.length < 1 || !schemaEntities[0]) { + function assembleRtcSchemaTree(treeNodes: any[],) { + if (!treeNodes || treeNodes.length === 0) { return; } - const mainEntity = schemaEntities[0]; - const queue = [mainEntity]; - while (queue.length) { - const current = queue.shift(); + for (const treeNode of treeNodes) { + if (treeNode.nodeType !== 'entity' && treeNode.nodeType !== 'childEntity') { + continue; + } + const schemaEntity = treeNode.data; + if (schemaEntity?.type) { + const currentSchemaFieldIds = schemaEntity.type.fields.map(field => field.id); + const rtcSchemaFields = getRtcSchemaFieldsByEntity(schemaEntity.id); + if (rtcSchemaFields) { + Object.keys(rtcSchemaFields).forEach(rtId => { + const rtElement = rtcSchemaFields[rtId]; + if (!rtElement.schemaField || currentSchemaFieldIds.includes(rtElement.schemaField.id)) { + return; + } + // 新字段为关联字段 + let childNodes = []; + if (rtElement.schemaField.$type === 'ComplexField' && rtElement.schemaField.type) { + childNodes = assembleRtcFieldsToTree(rtElement.schemaField.type.fields, rtElement.schemaField, schemaEntity.id); + } + // 新字段追加到树表:放在子表节点前面 + const newFieldTreeNode = { + data: rtElement.schemaField, + children: childNodes, + draggable: childNodes.length === 0, + rtFieldSourceType: rtElement.type, + rtFieldTag: rtElement.tag, + entityId: schemaEntity.id + }; + rtcSerializedAddedTreeNodes.value.push(newFieldTreeNode); + + const childEntityIndex = treeNode.children.findIndex(c => c.nodeType === 'childEntity'); + if (childEntityIndex > 0) { + treeNode.children.splice(childEntityIndex, 0, cloneDeep(newFieldTreeNode)); + } else { + treeNode.children.push(cloneDeep(newFieldTreeNode)); + } + if (!rtcAddedTreeNodes.value[schemaEntity.id]) { + rtcAddedTreeNodes.value[schemaEntity.id] = []; + } + rtcAddedTreeNodes.value[schemaEntity.id].push(newFieldTreeNode); - if (current?.type.entities && current.type.entities.length) { - if (current.type.entities.some(entity => entity.id === entityId)) { - current.type.entities = current.type.entities.filter(entity => entity.id !== entityId); - return; + }); } - queue.push(...current.type.entities); } + if (treeNode.children && treeNode.children.length > 0) { + assembleRtcSchemaTree(treeNode.children); + } } - } - /** - * 根据字段id获取所属schema实体和字段 - * @param fieldId 字段id + * 运行时定制:当表单使用be或vo的字段创建控件时,便将这个字段添加到表单实体中 */ - function getFieldBelongedEntity(fieldId: string): { - entity: FormSchemaEntity, schemaField: FormSchemaEntityField, isRefElement: boolean - } | null { - const schemaEntities = getSchemaEntities(); - if (!schemaEntities || schemaEntities.length < 1 || !schemaEntities[0]) { - return null; - } - const mainEntity = schemaEntities[0]; - let queue = [mainEntity]; - while (queue.length) { - const current = queue.shift(); - if (current?.type.fields && current?.type.fields.length) { - - const fieldInfo = getFieldInfoByID(current.type.fields, '', fieldId); - if (fieldInfo) { - return { - entity: current, - schemaField: fieldInfo.schemaField, - isRefElement: fieldInfo.isRefElement - }; + function addRtcFieldsToSchemaEntity(schemaField: FormSchemaEntityField) { + if (useFormSchema.designerMode === DesignerMode.PC_RTC && rtcSerializedAddedTreeNodes.value.length) { + const rtcFieldNode = rtcSerializedAddedTreeNodes.value.find(node => node.data.id === schemaField.id); + if (rtcFieldNode) { + const { entityId } = rtcFieldNode; + const addedField = rtcFieldNode.rtRelateParentSchemaField ? rtcFieldNode.rtRelateParentSchemaField : rtcFieldNode.data; + const entities = getSchemaEntities(); + const entity = getEntityNodeById(entities, entityId); + if (entity?.type?.fields && !entity.type.fields.find(field => field.id === addedField.id)) { + entity.type.fields.push(addedField); } } - if (current?.type.entities && current.type.entities.length) { - queue = queue.concat(current.type.entities); - } } - return null; } return { - convertViewObjectToEntitySchema, getFieldByIDAndVMID, getFieldsByViewModelId, getTableInfoByViewModelId, getFieldByID, entityChangeset, - getSchemaEntities, getPrimaryField + convertViewObjectToEntitySchema, + getFieldByIDAndVMID, + getFieldsByViewModelId, + getTableInfoByViewModelId, + getFieldByID, + entityChangeset, + getSchemaEntities, + getPrimaryField, + getRtcSchemaFieldsByEntity, + assembleRtcSchemaTree, + rtcAddedTreeNodes, + rtcSchemaFields, + rtcSerializedAddedTreeNodes, + addRtcFieldsToSchemaEntity }; } diff --git a/packages/designer/src/components/composition/use-events-editor.ts b/packages/designer/src/components/composition/use-events-editor.ts index 7740e02d654e24c04371e555f860344a3a8e7c5a..1e172a598899cc167d8be843b2b175663fe6cb40 100644 --- a/packages/designer/src/components/composition/use-events-editor.ts +++ b/packages/designer/src/components/composition/use-events-editor.ts @@ -174,7 +174,7 @@ export function useEventsEditor(commandService: UseFormCommandService, useFormSc controllerListItem.cmpId = mapItem.controller.id; controllerListItem.isNewGenerated = mapItem.controller.isNewGenerated || false; controllerListItem.isInvalid = mapItem.command.isInvalid || false; - controllerListItem['isRTCmd'] = mapItem.command['isRTCmd']; + controllerListItem['isRtcCommand'] = mapItem.command['isRtcCommand']; controllerListItem.targetComponent = mapItem.targetComponent['id'] ? mapItem.targetComponent['id'] : undefined; savedViewModelItem.controllerList.push(cloneDeep(controllerListItem)); } @@ -192,7 +192,7 @@ export function useEventsEditor(commandService: UseFormCommandService, useFormSc controllerListItem.property = cloneDeep(commandsItem.params); controllerListItem.cmpId = commandsItem.id; controllerListItem.isNewGenerated = commandsItem.isNewGenerated || false; - controllerListItem['isRTCmd'] = commandsItem.command['isRTCmd']; + controllerListItem['isRtcCommand'] = commandsItem.command['isRtcCommand']; controllerListItem.isInvalid = commandsItem.isInvalid || false; controllerListItem.targetComponent = commandsItem['targetComponent'] ? commandsItem['targetComponent'] : undefined; savedViewModelItem.controllerList.push(cloneDeep(controllerListItem)); @@ -260,7 +260,7 @@ export function useEventsEditor(commandService: UseFormCommandService, useFormSc handlerName: commandItem.handlerName, params: cloneDeep(commandItem.property), isNewGenerated: commandItem.isNewGenerated || false, - isRTCmd: commandItem['isRTCmd'], + isRtcCommand: commandItem['isRtcCommand'], isInvalid: commandItem.isInvalid || false, }, controller: { @@ -334,7 +334,7 @@ export function useEventsEditor(commandService: UseFormCommandService, useFormSc componentLists: [], targetComponent: undefined, isNewGenerated: undefined, - isRTCmd: undefined, + isRtcCommand: undefined, isInvalid: false, property: [] }; @@ -354,7 +354,7 @@ export function useEventsEditor(commandService: UseFormCommandService, useFormSc controllerListItem.property = cloneDeep(mapItem.command.params); controllerListItem.cmpId = mapItem.controller.id; controllerListItem.isNewGenerated = mapItem.controller.isNewGenerated || false; - controllerListItem.isRTCmd = mapItem.command['isRTCmd']; + controllerListItem.isRtcCommand = mapItem.command['isRtcCommand']; controllerListItem.isInvalid = mapItem.command.isInvalid || false; controllerListItem.targetComponent = mapItem.targetComponent['id'] ? mapItem.targetComponent['id'] : undefined; savedViewModelItem.controllerList.push(cloneDeep(controllerListItem)); @@ -374,7 +374,7 @@ export function useEventsEditor(commandService: UseFormCommandService, useFormSc controllerListItem.property = cloneDeep(commandsItem.params); controllerListItem.cmpId = commandsItem.id; controllerListItem.isNewGenerated = commandsItem.isNewGenerated || false; - controllerListItem.isRTCmd = commandsItem.isRTCmd; + controllerListItem.isRtcCommand = commandsItem.isRtcCommand; controllerListItem.isInvalid = commandsItem.isInvalid || false; controllerListItem.targetComponent = commandsItem['targetComponent'] || targetComponent ? commandsItem['targetComponent'] || targetComponent : undefined; savedViewModelItem.controllerList.push(cloneDeep(controllerListItem)); diff --git a/packages/designer/src/components/composition/use-form-schema.ts b/packages/designer/src/components/composition/use-form-schema.ts index 813ad7f0ad9e0be513bcb6cd5e61d96a991f7c9b..cd75efa33d45f730bab374e49252aa8ea3fcd935 100644 --- a/packages/designer/src/components/composition/use-form-schema.ts +++ b/packages/designer/src/components/composition/use-form-schema.ts @@ -4,9 +4,10 @@ import { NodeType, Node } from "../types/events-editor"; import { inject } from "vue"; import { LookupSchemaRepositoryToken } from "@farris/ui-vue/components"; import { LookupSchemaService } from "./schema-repository/lookup/lookup-schema.service"; +import { DesignerMode } from "../types/designer-context"; export function useFormSchema(): UseFormSchema { - const lookupSchemaService = inject(LookupSchemaRepositoryToken); + const designerMode = DesignerMode.PC; const ROOT_VIEW_MODEL_ID = 'root-viewmodel'; /** 表单元数据外层信息 */ @@ -1288,6 +1289,7 @@ export function useFormSchema(): UseFormSchema { getSchemaEntities, externalFormSchema, getComponetsByPredicate, - getDefaultValueByFiledAndType + getDefaultValueByFiledAndType, + designerMode }; } diff --git a/packages/designer/src/components/composition/use-form-statemachine.ts b/packages/designer/src/components/composition/use-form-statemachine.ts index 796e23ea67236359fc9608680936f3cfebe8314c..5a25e4ca4e2a6bec1586174eaeaa284405823ca5 100644 --- a/packages/designer/src/components/composition/use-form-statemachine.ts +++ b/packages/designer/src/components/composition/use-form-statemachine.ts @@ -46,7 +46,7 @@ export default function (useFormSchemaComposition: UseFormSchema): UseFormStateM stateMachines.forEach(stateMachine => { const { uri: stateMachineID, id: stateMachineCode } = stateMachine; const { relativePath } = formBasicInfo; - metadataService.queryMetadataById(relativePath, stateMachineID).then(result => { + metadataService.getRefMetadata(relativePath, stateMachineID).then(result => { if (result?.data?.content) { stateMachineMetadata = JSON.parse(result.data.content); } diff --git a/packages/designer/src/components/composition/use-location.ts b/packages/designer/src/components/composition/use-location.ts index 159c2b908982a0b0cfe0c0506f305f1de44f5019..6597fffc270858272cd2dbff8b53571efb1efec1 100644 --- a/packages/designer/src/components/composition/use-location.ts +++ b/packages/designer/src/components/composition/use-location.ts @@ -1,10 +1,24 @@ export function useLocation() { function getUrlParam(key: string) { const URL = new URLSearchParams(location.search); - return decodeURI(URL.get(key)|| ''); + return decodeURI(URL.get(key) || ''); } + /** + * 获取url参数 + * @param variable 参数编号 + */ + function getHrefParam(key: string) { + + const queryParam = window.location.href.substring(window.location.href.indexOf('?') + 1); + const queryVars = queryParam.split('&'); + for (const queryVar of queryVars) { + const pair = queryVar.split('='); + if (pair[0] === key) { return pair[1]; } + } + } return { - getUrlParam + getUrlParam, + getHrefParam }; } diff --git a/packages/designer/src/components/designer.component.tsx b/packages/designer/src/components/designer.component.tsx index c6dfa7abd5d3302b65201a8e3415fbe4b2a8e429..5a89cc85c62baa974cfa49fd02830e0ecb3f9cab 100644 --- a/packages/designer/src/components/designer.component.tsx +++ b/packages/designer/src/components/designer.component.tsx @@ -6,7 +6,7 @@ import { FormMetadaDataDom, MetadataPathToken } from "./types"; import { FNotifyService, FLoadingService, FResponseToolbar } from '@farris/ui-vue/components'; import FDesigner from '../components/components/form-designer/form-designer.component'; import FViewModelDesigner from '../components/components/view-model-designer/view-model-designer.component'; - +import FFormSettings from './components/form-settings/form-settings.component'; import './designer.scss'; import { useFormCommandService } from "./composition/command.service"; import { useEventsEditor } from "./composition/use-events-editor"; @@ -45,6 +45,7 @@ export default defineComponent({ // 注册 formSchema服务 const useFormSchemaComposition = useFormSchema(); provide('useFormSchema', useFormSchemaComposition); + useFormSchemaComposition.designerMode = designerContext.designerMode; const commandBuilderService = useCommandBuilderService(useFormSchemaComposition); const useFormStateMachineComposition = useFormStateMachine(useFormSchemaComposition); provide('useFormStateMachine', useFormStateMachineComposition); @@ -65,11 +66,12 @@ export default defineComponent({ // metadatFullPath const metadataPath: string = inject(MetadataPathToken, ''); // 控件创建服务 - const controlCreatorService = designerContext.useControlCreator(); + const controlCreatorService = designerContext.useControlCreator(schemaService); provide('controlCreatorUtils', controlCreatorService); provide('formMetadataConverter', new FormMetadataConverter()); const { eventBetweenDesignerAndCodeView } = commandBuilderService; - const useFormMetadataComposition = useFormMetadata(props, useFormSchemaComposition); + const { useFormMetadataService } = designerContext; + const useFormMetadataComposition = useFormMetadataService(props, useFormSchemaComposition, schemaService); onBeforeMount(() => { useFormMetadataComposition.queryMetadata().then((formSchema: FormMetadaDataDom) => { schema.value = formSchema; @@ -81,6 +83,10 @@ export default defineComponent({ designViewModelService.assembleDesignViewModel(); // 加载状态机 useFormStateMachineComposition.queryStateMachineMetadata(); + // 加载控件属性过滤规则 + if (designerContext.getPropertyFilterRule) { + designerContext.getPropertyFilterRule(); + } }); }); }); @@ -119,6 +125,9 @@ export default defineComponent({ const metadataId = useFormSchemaComposition.getFormMetadataBasicInfo()?.id; const relativePath = useFormSchemaComposition.getFormMetadataBasicInfo()?.relativePath; const formCode = useFormSchemaComposition.getFormMetadataBasicInfo()?.code; + if (!useFormMetadataComposition.publishFormMetadata) { + return; + } useFormMetadataComposition.publishFormMetadata().then((publishInfo) => { if (publishInfo.result) { loadingInstance.value.close(); @@ -289,22 +298,23 @@ export default defineComponent({
-
-
设计器
-
onChangeDesignerView('codeEditor')}>
代码
-
+ {DesignerMode.PC_RTC !== useFormSchemaComposition.designerMode && +
+
设计器
+
onChangeDesignerView('codeEditor')}>
代码
+
}
onChangeShowDesignerType('formDesigner')}>
页面
onChangeShowDesignerType('viewModelDesigner')}>
模型
- {/*
onChangeShowDesignerType('formSetting')}>
配置
*/} + {designerContext.designerMode === 'PC' &&
onChangeShowDesignerType('formSetting')}>
配置
}
{/* */} - {/* */} +
onChangeDesignerView(type)} onSaveAll={(datas) => onCodeViewSaveAll(datas)}> diff --git a/packages/designer/src/components/types/designer-context.ts b/packages/designer/src/components/types/designer-context.ts index 33747fbee93f2628b037834c46e88626b9f67c42..33eafe180f57e014d8cf72635421ee078633446e 100644 --- a/packages/designer/src/components/types/designer-context.ts +++ b/packages/designer/src/components/types/designer-context.ts @@ -1,12 +1,17 @@ -import { FormComponent, UseControlCreator, UseFormSchema } from "../types"; +import { ElementPropertyConfig } from "@farris/ui-vue/components/property-panel"; +import { DesignerProps } from "../designer.props"; +import { FormComponent, UseControlCreator, UseFormMetadata, UseFormSchema, UseSchemaService } from "../types"; /** 设计器模式 */ export enum DesignerMode { - /** PC设计器 */ + /** PC低代码设计器 */ PC = 'PC', /** 移动设计器 */ Mobile = 'Mobile', + + /** PC 运行时定制设计器 */ + PC_RTC = 'PC_RTC' } export interface UseDesignerContext { @@ -14,7 +19,27 @@ export interface UseDesignerContext { toolboxItems: any[]; componentsToRegister: any[]; supportedControllers: any; - controllCategories:any; - useControlCreator: () => UseControlCreator; + controllCategories: any; + useControlCreator: (schemaService: UseSchemaService) => UseControlCreator; getPageComponents: (useFormSchema: UseFormSchema) => FormComponent[]; -} \ No newline at end of file + + /** 查询元数据内容 */ + useFormMetadataService: (props: DesignerProps, useFormSchemaComposition: UseFormSchema, schemaService: UseSchemaService) => UseFormMetadata; + + /** 获取控件属性过滤规则 */ + getPropertyFilterRule?: () => void; + /** 过滤控件属性配置 */ + filterPropertyEntity?: (propertyConfig: ElementPropertyConfig[], propertyData: any) => ElementPropertyConfig[]; + + /** 校验支持删除控件 */ + checkCanDeleteControl?: (propertyData: any, needNotify?: boolean) => boolean; + + /** 设计器中新增控件的属性标识 */ + identifyForNewControl?: string; + + /** 为新创建的控件添加定制标识 */ + appendIdentifyForNewControl?: (propertyData: any) => void; + + /** 为新创建的方法添加定制标识 */ + appendIdentifyForNewCommand?: (propertyData: any) => void; +} diff --git a/packages/designer/src/components/types/entity-schema.ts b/packages/designer/src/components/types/entity-schema.ts index a89a70f7dccc4b7952d3851e214897b85ff3fbac..d11ceceac6e436671f92c9e724fa0c4c74804498 100644 --- a/packages/designer/src/components/types/entity-schema.ts +++ b/packages/designer/src/components/types/entity-schema.ts @@ -1,5 +1,3 @@ -/* eslint-disable no-use-before-define */ - import { FormSchemaEntityField$Type, FormSchemaEntityFieldElementType, diff --git a/packages/designer/src/components/types/events-editor.ts b/packages/designer/src/components/types/events-editor.ts index 029667c4aff4f65d5c850d22a04cf1219a74a404..22908e746e10304c3531ea92fa4bfa18cff3d760 100644 --- a/packages/designer/src/components/types/events-editor.ts +++ b/packages/designer/src/components/types/events-editor.ts @@ -12,7 +12,7 @@ export interface EventsEditorMapItem { showTargetComponent?: boolean; targetComponentId?: string; isNewGenerated?: boolean, - isRTCmd?: boolean, + isRtcCommand?: boolean, isInvalid: boolean }, controller: { @@ -48,7 +48,7 @@ export interface ControllerListItem { isNewGenerated: any, isInvalid: boolean, property: any, - isRTCmd?: boolean, + isRtcCommand?: boolean, } export interface UseEventsEditorUtils { diff --git a/packages/designer/src/components/types/metadata.ts b/packages/designer/src/components/types/metadata.ts index 2690c12ea75704fadf7da33375b6dbd01061cd1f..9bdb4b9737c0930d701ba07becc5560c1e4a3ab2 100644 --- a/packages/designer/src/components/types/metadata.ts +++ b/packages/designer/src/components/types/metadata.ts @@ -1,6 +1,8 @@ +import { Ref } from "vue"; import { ExternalComponentSchema } from "../components/form-designer/components/external-component-panpel/composition/types"; import { FormComponent, FormExpression, FormStateMachine, FormWebCmd } from "./basic"; import { DesignViewModel } from "./design-viewmodel"; +import { DesignerMode } from "./designer-context"; import { FormSchema, FormSchemaEntity, FormSchemaEntityField } from "./entity-schema"; import { FormVariable, FormViewModel, FormViewModelField } from "./view-model"; @@ -115,29 +117,29 @@ export interface FormMetadaDataDom { export interface MetadataDto { id: string; - nameSpace: string; + nameSpace?: string; code: string; name: string; - fileName: string; + fileName?: string; - type: string; + type?: string; - bizobjectID: string; + bizobjectID?: string; relativePath: string; - extendProperty: string; + extendProperty?: string; - content: string; + content?: string; - extendable: boolean; + extendable?: boolean; - properties: { framework: string, [propsName: string]: any } + properties?: { framework: string, [propsName: string]: any } - nameLanguage: any; + nameLanguage?: any; } export interface UseFormMetadata { /** 查询表单元数据 */ @@ -147,12 +149,13 @@ export interface UseFormMetadata { /** 查询表单模板的拖拽控制规则 */ queryFormTemplateRule: (module: any) => Promise; /** 发布表单 */ - publishFormMetadata: () => Promise<{ result: boolean, error?: string }>; + publishFormMetadata?: () => Promise<{ result: boolean, error?: string }>; /** 部署表单 */ - deployFrontFile: (metadataId: string, path: string) => Promise + deployFrontFile?: (metadataId: string, path: string) => Promise } export interface UseFormSchema { - + /** 设计器当前运行环境 */ + designerMode: DesignerMode; /** 表单元数据基础信息(外层结构) */ getFormMetadataBasicInfo: () => MetadataDto; @@ -242,6 +245,18 @@ export interface UseSchemaService { entityChangeset: any; getSchemaEntities(): FormSchemaEntity[]; getPrimaryField(): string; + /** 运行时定制场景:获取某实体下来源于be或vo的字段(不在当前表单entity内的字段) */ + getRtcSchemaFieldsByEntity: (targetEntityId: string, rtSchemaNode?: any) => any; + /** 运行时定制场景: 组装be或vo的字段为树结构 */ + assembleRtcSchemaTree: (treeNodes: any[]) => any; + /** 运行时定制:打开表单时存储完整的字段信息 */ + rtcSchemaFields: Ref; + /** 运行时定制:{实体ID:实体中新增的字段树节点集合} */ + rtcAddedTreeNodes: Ref; + /** 运行时定制:平铺所有新增字段树节点(平铺关联带出字段) */ + rtcSerializedAddedTreeNodes: Ref; + /** 运行时定制:将be或vo的字段添加到表单实体中 */ + addRtcFieldsToSchemaEntity: (schemaField: FormSchemaEntityField) => void; } export interface UseDesignViewModel { assembleDesignViewModel: () => void; diff --git a/packages/mobile-ui-vue/components/designer.ts b/packages/mobile-ui-vue/components/designer.ts index 2b5f2cd317fb6aa11f7f41bb72b067282ce9b246..49fc635cbdab0f73fd543dff42840fecbc683c07 100644 --- a/packages/mobile-ui-vue/components/designer.ts +++ b/packages/mobile-ui-vue/components/designer.ts @@ -1,4 +1,3 @@ export * from './dynamic-resolver'; -export { FDesignerToolbox } from './designer-toolbox'; -export { default as FModal, FModalService, FM_MODAL_SERVICE_TOKEN } from './modal'; -export { FM_UI_PROVIDER_SERVICE_TOKEN } from './common'; +export * from './register-designer'; +export { LookupSchemaRepositoryToken, FieldSelectorRepositoryToken } from './lookup'; diff --git a/packages/ui-vue/components/avatar/src/property-config/avatar.property-config.ts b/packages/ui-vue/components/avatar/src/property-config/avatar.property-config.ts index df1b4da7ba977d364ccee4fcdf791ba7d0091332..094681fcb859bde1de3fe88e5e09c3956aa2b396 100644 --- a/packages/ui-vue/components/avatar/src/property-config/avatar.property-config.ts +++ b/packages/ui-vue/components/avatar/src/property-config/avatar.property-config.ts @@ -12,6 +12,7 @@ export class AvatarProperty extends InputBaseProperty { "title": "编辑器", "type": "avatar", "$converter": "/converter/property-editor.converter", + "parentPropertyID": "editor", "properties": { "readonly": { "description": "", diff --git a/packages/ui-vue/components/collection-property-editor/src/components/collection-property-container.component.tsx b/packages/ui-vue/components/collection-property-editor/src/components/collection-property-container.component.tsx index 1268030f8f724012c86d05a14e01f940716764fb..6208c9afa931c08f22883f7cd6f6731b642063fa 100644 --- a/packages/ui-vue/components/collection-property-editor/src/components/collection-property-container.component.tsx +++ b/packages/ui-vue/components/collection-property-editor/src/components/collection-property-container.component.tsx @@ -85,7 +85,7 @@ export default defineComponent({ if (!firstNode) { return; } - treeViewRef.value.selectItemById(firstNode[idField]) + treeViewRef.value.selectItemById(firstNode[idField]); } /** diff --git a/packages/ui-vue/components/common/types.ts b/packages/ui-vue/components/common/types.ts index 83afe8d804a69f101349bcaf92ed75f062e64dbf..b90534bc11f7e47ebe304cd0cd204260d506c2ff 100644 --- a/packages/ui-vue/components/common/types.ts +++ b/packages/ui-vue/components/common/types.ts @@ -142,4 +142,4 @@ export interface RegisterContext { schemaResolverMap: Record; propertyConfigSchemaMap: Record; propertyEffectMap: Record; -} \ No newline at end of file +} diff --git a/packages/ui-vue/components/components.ts b/packages/ui-vue/components/components.ts index e430b4918726340b464773490bcc8d2b2691fe8a..2464a1cffd50733a6105a15036f24a7375607e35 100644 --- a/packages/ui-vue/components/components.ts +++ b/packages/ui-vue/components/components.ts @@ -36,7 +36,7 @@ export * from './data-view'; export type { DataColumn, VisualData, VisualDataCell, RowOptions } from './data-view'; export { default as FDrawer } from './drawer'; export type { DrawerProps } from './drawer'; -export { FResponseForm, FResponseForm as FDynamicForm, FDynamicFormGroup, FDynamicFormInput } from './dynamic-form'; +export { FResponseForm, FResponseForm as FDynamicForm, FDynamicFormGroup, FDynamicFormInput } from './dynamic-form'; export type { EditorConfig } from './dynamic-form'; export { default as FFilterBar } from './filter-bar'; export type { FilterBarProps } from './filter-bar'; @@ -108,3 +108,5 @@ export { default as FSearchBox } from './search-box'; export type { SearchBoxProps } from './search-box'; export { default as FVerifyDetail, FVerifyDetailService } from './verify-detail'; export type { VerifyDetailProps } from './verify-detail'; +export { default as FItemCollectionEditor } from './radio-group/src/designer/item-collection-editor.component'; +export { default as FSchemaSelectorEditor } from './schema-selector/src/schema-selector-editor.component'; diff --git a/packages/ui-vue/components/data-grid/src/composition/data-grid-component-creator.service.ts b/packages/ui-vue/components/data-grid/src/composition/data-grid-component-creator.service.ts index 8d9a142f4646408c1c932cc89a9c10dfc955e9f7..983a409b30de1c52b1698365c9891bf15fee8926 100644 --- a/packages/ui-vue/components/data-grid/src/composition/data-grid-component-creator.service.ts +++ b/packages/ui-vue/components/data-grid/src/composition/data-grid-component-creator.service.ts @@ -1,5 +1,5 @@ import { DesignerHostService } from '../../../designer-canvas/src/composition/types'; -import { DynamicResolver } from '../../../../components/dynamic-resolver'; +import { DynamicResolver, getSchemaByTypeForDesigner } from '../../../../components/dynamic-resolver'; import { ComponentBuildInfo } from '../../../component/src/composition/inner-component-build-info'; import { ComponentSchema } from '../../../../components/designer-canvas'; import { FormSchemaEntityField$Type, FormSchemaEntityFieldTypeName } from '@farris/ui-vue/components/common'; @@ -111,26 +111,22 @@ export class DataGridComponentCreatorService { const stateMachineRenderState = this.formStateMachineUtils && this.formStateMachineUtils.getRenderStates(); const btnType = DgControl['tab-page'].type === resolvedContainerType ? 'tab-toolbar-item' : 'section-toolbar-item'; - const btns = [{ - id: `button-add-${buildInfo.componentId}`, - type: btnType, - text: '新增', - disabled: stateMachineRenderState.find(d => d.id === 'canAddDetail') ? `!viewModel.stateMachine['canAddDetail']` : false, - appearance: { - class: '' - }, - onClick: `root-viewModel.${viewModelNode.id}.${commandPrefix}AddItem1` - }, - { - id: `button-remove-${buildInfo.componentId}`, - type: btnType, - text: '删除', - disabled: stateMachineRenderState.find(d => d.id === 'canRemoveDetail') ? `!viewModel.stateMachine['canRemoveDetail']` : false, - appearance: { - class: '' - }, - onClick: `root-viewModel.${viewModelNode.id}.${commandPrefix}RemoveItem1` - }]; + const btnSchema = this.resolver.getSchemaByType(btnType) as ComponentSchema; + const btns = [ + Object.assign({}, btnSchema, { + id: `button-add-${buildInfo.componentId}`, + type: btnType, + text: '新增', + disabled: stateMachineRenderState.find(d => d.id === 'canAddDetail') ? `!viewModel.stateMachine['canAddDetail']` : false, + onClick: `root-viewModel.${viewModelNode.id}.${commandPrefix}AddItem1` + }), + Object.assign({}, btnSchema, { + id: `button-remove-${buildInfo.componentId}`, + type: btnType, + text: '删除', + disabled: stateMachineRenderState.find(d => d.id === 'canRemoveDetail') ? `!viewModel.stateMachine['canRemoveDetail']` : false, + onClick: `root-viewModel.${viewModelNode.id}.${commandPrefix}RemoveItem1` + })]; if (!resolvedContainerSchema.toolbar) { resolvedContainerSchema.toolbar = { id: `${resolvedContainerSchema.id}_toolbar`, buttons: [] }; } @@ -152,35 +148,39 @@ export class DataGridComponentCreatorService { const addCommandId = useGuid().guid(); const deleteCommandId = useGuid().guid(); const cardControllerId = this.resolveCommandController(); + const addCommand = { + id: addCommandId, + code: `${commandPrefix}AddItem1`, + name: '增加一条子表数据', + params: [], + handlerName: 'AddItem', + cmpId: cardControllerId, + shortcut: {}, + extensions: [] + }; + const deleteCommand = { + id: deleteCommandId, + code: `${commandPrefix}RemoveItem1`, + name: '删除一条子表数据', + params: [ + { + name: 'id', + shownName: '待删除子表数据的标识', + value: `{DATA~${viewModelNode.bindTo}/id}` + } + ], + handlerName: 'RemoveItem', + cmpId: cardControllerId, + shortcut: {}, + extensions: [] + }; - viewModelNode.commands.push( - { - id: addCommandId, - code: `${commandPrefix}AddItem1`, - name: '增加一条子表数据', - params: [], - handlerName: 'AddItem', - cmpId: cardControllerId, - shortcut: {}, - extensions: [] - }, - { - id: deleteCommandId, - code: `${commandPrefix}RemoveItem1`, - name: '删除一条子表数据', - params: [ - { - name: 'id', - shownName: '待删除子表数据的标识', - value: `{DATA~${viewModelNode.bindTo}/id}` - } - ], - handlerName: 'RemoveItem', - cmpId: cardControllerId, - shortcut: {}, - extensions: [] - } - ); + if (this.designerHostService.designerContext?.appendIdentifyForNewCommand) { + this.designerHostService.designerContext.appendIdentifyForNewCommand(addCommand); + this.designerHostService.designerContext.appendIdentifyForNewCommand(deleteCommand); + } + + viewModelNode.commands.push(addCommand, deleteCommand); // 3、记录构件命令 diff --git a/packages/ui-vue/components/data-grid/src/designer/grid-field-editor.component.tsx b/packages/ui-vue/components/data-grid/src/designer/grid-field-editor.component.tsx index 38224fd15d5154a90b22a858ff7f9ce9a3b4a360..50322fdf6debece346df1ec2918fc5252a170ba8 100644 --- a/packages/ui-vue/components/data-grid/src/designer/grid-field-editor.component.tsx +++ b/packages/ui-vue/components/data-grid/src/designer/grid-field-editor.component.tsx @@ -19,6 +19,7 @@ import FButtonEdit from '../../../button-edit/src/button-edit.component'; import { gridFieldEditorProps, GridFieldEditorProps } from './grid-field-editor.props'; import FTransfer from '../../../transfer/src/transfer.component'; import { FormSchemaEntityField$Type } from '@farris/ui-vue/components/common'; +import { DesignerHostService } from '@farris/ui-vue/components/designer-canvas'; export default defineComponent({ name: 'FGridFieldEditor', @@ -29,7 +30,10 @@ export default defineComponent({ const viewModelId = ref(props.viewModelId); const designViewModelUtils = inject('designViewModelUtils') as any; const formSchemaUtils = inject('useFormSchema') as any; + const formSchemaService = inject('schemaService') as any; const controlCreatorUtils = inject('controlCreatorUtils') as any; + const designerContext = inject('designerContext') as any; + let fieldColumns = props.gridData['columns']; // 控制表格列是否需要有编辑器 const { fieldEditable } = props.gridData; @@ -40,10 +44,24 @@ export default defineComponent({ const dataSource = ref([]); // 打平关联字段后的列数据 let plainColumns = [] as any; + /** + * 检查当前设计器环境是否支持删除字段 + */ + function checkBeforeRemoveItem(removedItem: any, needNotify = true) { + if (designerContext.checkCanDeleteControl && !designerContext.checkCanDeleteControl(removedItem, needNotify)) { + return false; + } + return true; + } const rowOptions = { customRowStatus: (visualData: any) => { const rawData = visualData['raw']; - visualData['disabled'] = rawData.type && rawData.type.fields && rawData.type.fields.length > 0 ? true : visualData['disabled']; + if (rawData.type && rawData.type.fields && rawData.type.fields.length > 0) { + visualData['disabled'] = true; + } + if (!checkBeforeRemoveItem(rawData, false)) { + visualData['disabled'] = true; + } } }; /** @@ -80,21 +98,44 @@ export default defineComponent({ } function convertTreeNodes2PlainObject(nodes: any[], r: any[] = []): any[] { if (nodes) { + const fieldColumnsIds = fieldColumns.map(column => column.binding.field); nodes.forEach(n => { r.push(n); if (n.children) { convertTreeNodes2PlainObject(n.children, r); } + // 附加定制标识,限制字段的删除 + if (designerContext.appendIdentifyForNewControl && !fieldColumnsIds.includes(n.data.id)) { + designerContext.appendIdentifyForNewControl(n); + } + }); } return r; } + /** + * 合并运行时定制中来自be或vo的字段 + */ + function resolveRtcEntityTreeData() { + + if (formSchemaUtils.designerMode === 'PC_RTC' && formSchemaService.rtcAddedTreeNodes.value) { + const entityInfo = formSchemaService.getTableInfoByViewModelId(viewModelId.value); + if (entityInfo?.id) { + const rtcNodesInEntity = formSchemaService.rtcAddedTreeNodes.value[entityInfo.id]; + if (rtcNodesInEntity?.length) { + dataSource.value = dataSource.value.concat(rtcNodesInEntity); + } + } + } + } /** * 更新dataSource */ function resetDataSource() { dataSource.value = designViewModelUtils['getAllFields2TreeByVMId'](viewModelId.value); + + resolveRtcEntityTreeData(); plainColumns = convertTreeNodes2PlainObject(dataSource.value); } @@ -202,7 +243,6 @@ export default defineComponent({ } function onBeforeOpen() { if (props.getLatestGridData) { - fieldColumns = props.getLatestGridData()['columns']; } else { fieldColumns = props.gridData['columns']; @@ -214,10 +254,10 @@ export default defineComponent({ } const columns = [{ field: 'name', title: '', dataType: 'string', width: '100%', formatter: (cellInfo, totalInfo) => { - return cellInfo.data + ` [${totalInfo.data['path'].data}]`; + return cellInfo.data + ` [${totalInfo.data['bindingField'].data}]`; } }, { - field: 'path', visible: false, title: '', dataType: 'string' + field: 'bindingField', visible: false, title: '', dataType: 'string' }]; onMounted(() => { @@ -241,10 +281,11 @@ export default defineComponent({ columns={columns} displayType={'Tree'} onChange={(datas) => onChangeHandler(datas)} + checkBeforeRemoveItem={checkBeforeRemoveItem} > {{ text: (itemInfo) => { - return
{itemInfo.data['name'].data} [{itemInfo.data['path'].data}]
; + return
{itemInfo.data['name'].data} [{itemInfo.data['bindingField'].data}]
; } }} diff --git a/packages/ui-vue/components/data-grid/src/property-config/data-grid-column.property-config.ts b/packages/ui-vue/components/data-grid/src/property-config/data-grid-column.property-config.ts index 80077a328d1cc4ce5b82bfa01990af107b429161..6822147a078a04770ad7b6e270bc7ae2cb7ddba3 100644 --- a/packages/ui-vue/components/data-grid/src/property-config/data-grid-column.property-config.ts +++ b/packages/ui-vue/components/data-grid/src/property-config/data-grid-column.property-config.ts @@ -215,8 +215,6 @@ export class DataGriColumnProperty extends BaseControlProperty { title: '编辑器类型', propertyData: propertyData.editor, tabId: 'gridFieldEditor', - // enableCascade: true, - parentPropertyID: 'editor', tabName: '编辑器', properties: { type: { @@ -224,6 +222,7 @@ export class DataGriColumnProperty extends BaseControlProperty { title: '编辑器类型', type: 'enum', $converter: '/converter/change-editor.converter', + parentPropertyID: 'editor', refreshPanelAfterChanged: true, editor: { type: 'combo-list', @@ -272,6 +271,7 @@ export class DataGriColumnProperty extends BaseControlProperty { tabName: propertyCategory.tabName || tabName, description, $converter, + parentPropertyID: 'editor', propertyData, properties, setPropertyRelates: propertyCategory?.setPropertyRelates diff --git a/packages/ui-vue/components/data-grid/src/property-config/data-grid.property-config.ts b/packages/ui-vue/components/data-grid/src/property-config/data-grid.property-config.ts index 3dfde33f80c8c7cba522c1528de5eab8158443e1..d87a0953addfa1f09ab79c293a0b45f0edfa0587 100644 --- a/packages/ui-vue/components/data-grid/src/property-config/data-grid.property-config.ts +++ b/packages/ui-vue/components/data-grid/src/property-config/data-grid.property-config.ts @@ -93,6 +93,11 @@ export class DataGridProperty extends BaseControlProperty { this.propertyConfig.categories['appearance'] = { title: "外观", properties: { + class: { + title: 'class样式', + type: 'string', + description: '组件的CSS样式' + }, columns: { title: "列设置", description: "列设置", @@ -106,7 +111,7 @@ export class DataGridProperty extends BaseControlProperty { // 这个属性,标记当属性变更得时候触发重新更新属性 refreshPanelAfterChanged: true, - }, + }, showStripe: { title: "显示条纹", type: "boolean", @@ -150,6 +155,7 @@ export class DataGridProperty extends BaseControlProperty { this.propertyConfig.categories['selection'] = { title: '多选配置', $converter: '/converter/grid-selection.converter', + parentPropertyID: 'editor', properties: { multiSelect: { title: '启用多选', @@ -163,7 +169,7 @@ export class DataGridProperty extends BaseControlProperty { refreshPanelAfterChanged: true }, showSelectAll: { - visible: propertyData.selection == null ? false : propertyData.selection.multiSelect&&propertyData.selection.showCheckbox, + visible: propertyData.selection == null ? false : propertyData.selection.multiSelect && propertyData.selection.showCheckbox, title: '显示全选', type: 'boolean' } @@ -183,6 +189,7 @@ export class DataGridProperty extends BaseControlProperty { this.propertyConfig.categories['rowNumber'] = { title: '行号配置', $converter: '/converter/row-number.converter', + parentPropertyID: 'rowNumber', properties: { enable: { title: '显示行号', @@ -204,6 +211,7 @@ export class DataGridProperty extends BaseControlProperty { this.propertyConfig.categories['pagination'] = { title: '分页', $converter: '/converter/pagination.converter', + parentPropertyID: 'pagination', properties: { enable: { title: '启用分页', diff --git a/packages/ui-vue/components/designer-canvas/src/components/designer-item.component.tsx b/packages/ui-vue/components/designer-canvas/src/components/designer-item.component.tsx index 0dbd79d0ea718eb0f4429d3332003061003b784a..973f42f5e749818facc5297bd02638de92101a8e 100644 --- a/packages/ui-vue/components/designer-canvas/src/components/designer-item.component.tsx +++ b/packages/ui-vue/components/designer-canvas/src/components/designer-item.component.tsx @@ -33,7 +33,6 @@ const FDesignerItem = defineComponent({ // 外部容器引入的表单,记录所属容器id const externalContainerId = inject('external-container-id'); - const designerItemClass = computed(() => { const componentClass = props.modelValue.appearance ? (props.modelValue.appearance.class as string) || '' : ''; const customButtons = componentInstance.value?.getCustomButtons && componentInstance.value.getCustomButtons(); @@ -82,7 +81,9 @@ const FDesignerItem = defineComponent({ payload.preventDefault(); payload.stopPropagation(); } - + if (designerHostService?.designerContext?.checkCanDeleteControl && !designerHostService.designerContext.checkCanDeleteControl(schemaToRemove)) { + return; + } // 连同所属组件一起删除,使用场景如data-grid、form控件等。 if (componentInstance.value.triggerBelongedComponentToDeleteWhenDeleted) { const belongedComponentInstance = componentInstance.value.getBelongedComponentInstance(componentInstance); @@ -241,7 +242,7 @@ const FDesignerItem = defineComponent({ } } } - + watch([() => props.modelValue, () => props.componentId], ([newValue, newComponentId]) => { schema.value = newValue; @@ -354,7 +355,7 @@ const FDesignerItem = defineComponent({ } return () => { - const prefixId = externalContainerId ? `${externalContainerId}-` : '' + const prefixId = externalContainerId ? `${externalContainerId}-` : ''; return ( schema.value.type === 'component-ref' ? renderChildComponentContent(schema.value) : diff --git a/packages/ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts b/packages/ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts index 0dddca3267549a83ff74de046031379b285c6322..fc243576dba6248f4643b57cb35f445b2a6fd8a4 100644 --- a/packages/ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts +++ b/packages/ui-vue/components/designer-canvas/src/composition/function/use-dragula.ts @@ -6,7 +6,7 @@ import { canvasChanged } from '../designer-canvas-changed'; import { ComponentSchema } from '../../types'; import { dragResolveService } from './drag-resolve'; -export function useDragula(designerHostService: DesignerHostService): UseDragula { +export function useDragula(designerHostService: DesignerHostService, designerContext: any): UseDragula { let dragulaInstance: any; @@ -138,6 +138,9 @@ export function useDragula(designerHostService: DesignerHostService): UseDragula } const sourceControlSchema = componentResolveContext.componentSchema; if (sourceControlSchema) { + if (designerContext?.appendIdentifyForNewControl) { + designerContext.appendIdentifyForNewControl(sourceControlSchema); + } addNewControlToTarget(target, sourceControlSchema, sibling); } }); diff --git a/packages/ui-vue/components/designer-canvas/src/composition/types.ts b/packages/ui-vue/components/designer-canvas/src/composition/types.ts index 4861b5b0acab3259faf2d94f85b8d5097c3d07a0..9d751003a5de6bc3f531e8e46bb7a5c883360a80 100644 --- a/packages/ui-vue/components/designer-canvas/src/composition/types.ts +++ b/packages/ui-vue/components/designer-canvas/src/composition/types.ts @@ -28,6 +28,7 @@ export interface DesignerHostService { metadataService?: any; formStateMachineUtils: any; schemaService?: any; + designerContext?: any; [key: string]: any; } /** diff --git a/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx b/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx index 98f8f0ad9de0f6f33504bec1022cc20860e7714e..591c9fd24ca1d5a5cb86e25388b75d9f441c8ee6 100644 --- a/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx +++ b/packages/ui-vue/components/designer-canvas/src/designer-canvas.component.tsx @@ -11,6 +11,8 @@ import './composition/class/control.css'; import { loadDesignerRegister, registerDesignerComponents } from './components/maps'; import { F_MODAL_SERVICE_TOKEN } from '../../modal'; import { canvasKey, refreshCanvas } from './composition/update-cancas'; +import { setDesignerContextForDesigner } from '../../dynamic-resolver/src/resolver/schema/schema-resolver-design'; +import { setDesignerContext } from '../../dynamic-resolver/src/resolver/schema/schema-resolver'; export default defineComponent({ name: 'FDesignerCanvas', @@ -28,7 +30,8 @@ export default defineComponent({ let resizeObserver: ResizeObserver | null; let resizeObserverTimer; - + /** 设计器上下文 */ + const designerContext = inject('designerContext') as any; const designerHostService = { eventsEditorUtils: inject('eventsEditorUtils'), formSchemaUtils: inject('useFormSchema'), @@ -40,11 +43,14 @@ export default defineComponent({ useFormCommand: inject('useFormCommand'), modalService: inject(F_MODAL_SERVICE_TOKEN), formStateMachineUtils: inject('useFormStateMachine'), - messagerService: inject('FMessageBoxService') + messagerService: inject('FMessageBoxService'), + designerContext }; + setDesignerContext(designerContext); + setDesignerContextForDesigner(designerContext); provide('designer-host-service', designerHostService); - const useDragulaComposition = useDragula(designerHostService); + const useDragulaComposition = useDragula(designerHostService, designerContext); // 后需统一采用registerDesignerComponents注册控件 if (props.components) { @@ -87,7 +93,7 @@ export default defineComponent({ schema.value = newSchema; componentId.value = newComponentId; } - ) + ); watch(canvasChanged, () => { setPositionOfButtonGroupInContainer(designerCanvasElementRef.value); diff --git a/packages/ui-vue/components/designer-canvas/src/types.ts b/packages/ui-vue/components/designer-canvas/src/types.ts index 8da297b5d48a8aa57046a972fdb03bc8788460c1..e6c9fcd775e520f8030ce206d1ed4bac8f1b354e 100644 --- a/packages/ui-vue/components/designer-canvas/src/types.ts +++ b/packages/ui-vue/components/designer-canvas/src/types.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-use-before-define */ import { Ref, SetupContext } from "vue"; import { DesignerHostService, DesignerHTMLElement, DraggingResolveContext } from "./composition/types"; diff --git a/packages/ui-vue/components/designer-outline/src/composition/use-data-view.ts b/packages/ui-vue/components/designer-outline/src/composition/use-data-view.ts index 205143ae5af5f5936148ea7f7a41ee819ac6f71e..09c7190ad5f643aa09373dfac36635d79beb56c6 100644 --- a/packages/ui-vue/components/designer-outline/src/composition/use-data-view.ts +++ b/packages/ui-vue/components/designer-outline/src/composition/use-data-view.ts @@ -12,7 +12,6 @@ export function useDataView( useOutlineNodeComposition: UseOutlineNode ): UseDataView { - const domJsonComponents = props.data.module ? ref(props.data.module.components) : ref([props.data]); const { getIcon, getTitle } = useOutlineNodeComposition; /** 处理子组件 */ @@ -120,6 +119,7 @@ export function useDataView( /** 获取treeview所需数据 */ function getData() { + const domJsonComponents = props.data.module ? ref(props.data.module.components) : ref([props.data]); if (!domJsonComponents.value) { return ; } diff --git a/packages/ui-vue/components/dynamic-resolver/src/resolver/property-config/use-property-config-resolver.ts b/packages/ui-vue/components/dynamic-resolver/src/resolver/property-config/use-property-config-resolver.ts index 06c4f9fb6eadd4d6b4aefd99b8e11a3a6997b8a8..a66dee7e6988f81e82b62163d8738135d102fd70 100644 --- a/packages/ui-vue/components/dynamic-resolver/src/resolver/property-config/use-property-config-resolver.ts +++ b/packages/ui-vue/components/dynamic-resolver/src/resolver/property-config/use-property-config-resolver.ts @@ -1,4 +1,4 @@ -import { computed, ref } from "vue"; +import { computed, inject, ref } from "vue"; import { EffectFunction, PropertyConverter, SchemaService } from '../../types'; import { EditorConfig } from "../../../../dynamic-form"; import { useObjectExpression } from '../../object-expression'; @@ -31,7 +31,7 @@ export function usePropertyConfigResolver(propertyConfigSchemaMap: Record([ ['string', { type: 'input-group', enableClear: false }], @@ -163,8 +163,8 @@ export function usePropertyConfigResolver(propertyConfigSchemaMap: Record; const schemaResolverMapForDesigner = {} as Record; -const { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, mappingSchemaToProps } = +const { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, mappingSchemaToProps, setDesignerContext } = useSchemaResolver(schemaMapForDesigner, schemaResolverMapForDesigner); export { getSchemaByType as getSchemaByTypeForDesigner, resolveSchemaWithDefaultValue as resolveSchemaWithDefaultValueForDesigner, - resolveSchemaToProps as resolveSchemaToPropsForDesigner, schemaMapForDesigner, schemaResolverMapForDesigner, - mappingSchemaToProps as mappingSchemaToPropsForDesigner + resolveSchemaToProps as resolveSchemaToPropsForDesigner, schemaMapForDesigner, schemaResolverMapForDesigner, + mappingSchemaToProps as mappingSchemaToPropsForDesigner, setDesignerContext as setDesignerContextForDesigner }; diff --git a/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/schema-resolver.ts b/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/schema-resolver.ts index 083e2015cd35a9579a6cccce71c5cf2120ae0367..a77a5fa1e99fa605d60c3b34640a76faf4bc2ac9 100644 --- a/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/schema-resolver.ts +++ b/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/schema-resolver.ts @@ -4,7 +4,7 @@ import { useSchemaResolver } from "./use-schema-resolver"; const schemaMap = {} as Record; const schemaResolverMap = {} as Record; -const { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, mappingSchemaToProps } = +const { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, mappingSchemaToProps, setDesignerContext } = useSchemaResolver(schemaMap, schemaResolverMap); -export { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, schemaMap, schemaResolverMap, mappingSchemaToProps }; +export { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, schemaMap, schemaResolverMap, mappingSchemaToProps, setDesignerContext }; diff --git a/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/use-schema-resolver.ts b/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/use-schema-resolver.ts index f1654b900b54f3a455cdb9b8a95041a4251ff04e..241dc5318071f0bac49e48b5961db129192e0131 100644 --- a/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/use-schema-resolver.ts +++ b/packages/ui-vue/components/dynamic-resolver/src/resolver/schema/use-schema-resolver.ts @@ -4,6 +4,7 @@ import { DesignerHostService } from "@farris/ui-vue/components/designer-canvas"; export function useSchemaResolver(schemaMap: Record, schemaResolverMap: Record) { + let designerContext; function getSchemaValueByDefault(defaultSchema: Record): Record { const { properties, title, ignore: ignoreList } = defaultSchema as Record; const canIgnoreProperty = ignoreList && Array.isArray(ignoreList); @@ -20,7 +21,7 @@ export function useSchemaResolver(schemaMap: Record, schemaResolver } return resolvedSchema; } - + /** * 获取控件元数据,只组装必填的字段 */ @@ -45,7 +46,7 @@ export function useSchemaResolver(schemaMap: Record, schemaResolver }; } - + function getSchemaByType(componentType: string, resolveContext: Record = {}, designerHostService?: DesignerHostService) : Record | null { const defaultSchema = schemaMap[componentType]; @@ -54,6 +55,9 @@ export function useSchemaResolver(schemaMap: Record, schemaResolver const schemaResolver = schemaResolverMap[componentType]; componentSchema = schemaResolver ? schemaResolver({ getSchemaByType }, componentSchema, resolveContext, designerHostService) : componentSchema; + if (designerContext?.appendIdentifyForNewControl) { + designerContext.appendIdentifyForNewControl(componentSchema); + } return componentSchema; } return null; @@ -132,5 +136,8 @@ export function useSchemaResolver(schemaMap: Record, schemaResolver return schemaValue; } - return { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, mappingSchemaToProps }; + function setDesignerContext(designerContext1) { + designerContext = designerContext1; + } + return { getSchemaByType, resolveSchemaWithDefaultValue, resolveSchemaToProps, mappingSchemaToProps, setDesignerContext }; } diff --git a/packages/ui-vue/components/events-editor/src/components/command-source/command-source.component.tsx b/packages/ui-vue/components/events-editor/src/components/command-source/command-source.component.tsx index ab985b51af5bc623c11b0c3116aca1b57a3f6cd8..6aaf20edabdf36dd5bab6b031bb998db4f3d2d33 100644 --- a/packages/ui-vue/components/events-editor/src/components/command-source/command-source.component.tsx +++ b/packages/ui-vue/components/events-editor/src/components/command-source/command-source.component.tsx @@ -160,10 +160,11 @@ export default defineComponent({
openMetadataSelector()}>引入控制器
- {shouldShowAddNewMethod.value &&
-
-
generateNewFunc()}>添加新方法
-
} + {shouldShowAddNewMethod.value && useFormSchema.designerMode !== 'PC_RTC' && +
+
+
generateNewFunc()}>添加新方法
+
} {shouldShowBondEvents.value && renderBondEvents()} {/*
diff --git a/packages/ui-vue/components/events-editor/src/components/interaction-item/interaction-item.component.tsx b/packages/ui-vue/components/events-editor/src/components/interaction-item/interaction-item.component.tsx index 349498670a9a6f23626f93106d1a4c0043687a60..1e7b6cebf6bf4b700cfbd4de14be191adc562fa3 100644 --- a/packages/ui-vue/components/events-editor/src/components/interaction-item/interaction-item.component.tsx +++ b/packages/ui-vue/components/events-editor/src/components/interaction-item/interaction-item.component.tsx @@ -200,7 +200,7 @@ export default defineComponent({ handlerName: '未绑定方法', cmpId: '', shortcut: {}, - isRTCmd: undefined, + isRtcCommand: undefined, isNewGenerated: undefined, extensions: [], isInvalid: false diff --git a/packages/ui-vue/components/events-editor/src/types.ts b/packages/ui-vue/components/events-editor/src/types.ts index 539abad2ca85c5de7f56e3e0bb3bbc4c1e824385..b84288e6686c5397f5c77111523ba5d982f8dcde 100644 --- a/packages/ui-vue/components/events-editor/src/types.ts +++ b/packages/ui-vue/components/events-editor/src/types.ts @@ -44,8 +44,8 @@ export interface CommandItem { isNewGenerated?: boolean; extensions?: []; isInvalid?: boolean; - /** isRTCmd=true 运行时定制的命令,可以删改 */ - isRTCmd?: boolean; + /** isRtcCommand=true 运行时定制的命令,可以删改 */ + isRtcCommand?: boolean; } export interface ControllerName { diff --git a/packages/ui-vue/components/external-container/src/designer/import-external-schema.component.tsx b/packages/ui-vue/components/external-container/src/designer/import-external-schema.component.tsx index 996e0f09649b6773ff2f38bb3546e9694f3da419..df3ed71e91c8fd39daf1f6451d079711e2c9cec3 100644 --- a/packages/ui-vue/components/external-container/src/designer/import-external-schema.component.tsx +++ b/packages/ui-vue/components/external-container/src/designer/import-external-schema.component.tsx @@ -80,13 +80,18 @@ export default defineComponent({ } function renderFormSelectorComponent() { const formSelectorParams = { formBasicInfo }; + const viewOptions = designerHostService.formSchemaUtils.designerMode === 'PC_RTC' ? + [ + { id: 'total', title: '全部', type: 'Card', dataSource: 'Total', pagination: false } + ] : + [ + { id: 'recommend', title: '推荐', type: 'Card', dataSource: 'Recommand', pagination: false }, + { id: 'total', title: '全部', type: 'Card', dataSource: 'Total', pagination: false } + ]; return () => ( { if (selection.id) { diff --git a/packages/ui-vue/components/filter-bar/src/composition/build-filter-bar.ts b/packages/ui-vue/components/filter-bar/src/composition/build-filter-bar.ts index 0ec6eae2589298c2a8d6031e88e69acd84c3f253..d153dc2b23e2b5286d3e3122339054ddca02acf9 100644 --- a/packages/ui-vue/components/filter-bar/src/composition/build-filter-bar.ts +++ b/packages/ui-vue/components/filter-bar/src/composition/build-filter-bar.ts @@ -186,7 +186,7 @@ export function buildFilterBar(context: Record, designerHostService // 3、将查询命令绑定到筛选条组件 if (filterBar && filterInGridViewModel) { - filterBar.query = filterInGridViewModel.code; + filterBar.onQuery = filterInGridViewModel.code; } // 4、预置筛选条查询数据的构件 diff --git a/packages/ui-vue/components/filter-bar/src/property-config/filter-bar.property-config.ts b/packages/ui-vue/components/filter-bar/src/property-config/filter-bar.property-config.ts index 9b3482eba5b9c005e70302945b30fa59048f763a..c20cc0d0c8f4a7cb7a96afef7cd7dd7d02bb1e88 100644 --- a/packages/ui-vue/components/filter-bar/src/property-config/filter-bar.property-config.ts +++ b/packages/ui-vue/components/filter-bar/src/property-config/filter-bar.property-config.ts @@ -43,7 +43,7 @@ export class FilterBarPropertyConfig extends InputBaseProperty { description: "筛选条字段设置", title: "筛选条字段", type: "", - refreshPanelAfterChanged: true, + refreshPanelAfterChanged: true, editor: { type: "filter-bar-config", fieldsConfig: allFields, diff --git a/packages/ui-vue/components/filter-bar/src/schema/filter-bar.schema.json b/packages/ui-vue/components/filter-bar/src/schema/filter-bar.schema.json index 8b1166684f560dffb4e42205c6f01e053bf5c6e5..7009b7d632c10a0dc507e0f9cfe5f8758bc6f174 100644 --- a/packages/ui-vue/components/filter-bar/src/schema/filter-bar.schema.json +++ b/packages/ui-vue/components/filter-bar/src/schema/filter-bar.schema.json @@ -39,6 +39,10 @@ "description": "", "type": "boolean", "default": true + }, + "fields": { + "description": "", + "type": "array" } }, "required": [ diff --git a/packages/ui-vue/components/input-group/src/property-config/input-group.property-config.ts b/packages/ui-vue/components/input-group/src/property-config/input-group.property-config.ts index aaae75c2910c3f8feac0974df58a14e5026dbc0d..1fb81647188c77a84b9df8b571039727c3ca967c 100644 --- a/packages/ui-vue/components/input-group/src/property-config/input-group.property-config.ts +++ b/packages/ui-vue/components/input-group/src/property-config/input-group.property-config.ts @@ -64,7 +64,8 @@ export class InputGroupProperty extends InputBaseProperty { data: inputFormatValidationTypes }, refreshPanelAfterChanged: true, - $converter: typeConverter + $converter: typeConverter, + parentPropertyID: 'formatValidation' } }, @@ -74,7 +75,8 @@ export class InputGroupProperty extends InputBaseProperty { title: "输入错误提示", type: "string", description: "输入错误提示", - $converter: commonConverter + $converter: commonConverter, + parentPropertyID: 'formatValidation' }; } @@ -83,8 +85,8 @@ export class InputGroupProperty extends InputBaseProperty { title: "匹配正则", type: "string", description: "匹配正则", - - $converter: commonConverter + $converter: commonConverter, + parentPropertyID: 'formatValidation' }; } return formatValidationSchema; diff --git a/packages/ui-vue/components/list-nav/src/property-config/list-nav.property-config.ts b/packages/ui-vue/components/list-nav/src/property-config/list-nav.property-config.ts index fd2f6180e71d75290546426bdf062ca58db56ab5..1add265ea2d39b23a515b949d8ec93a8f4d51703 100644 --- a/packages/ui-vue/components/list-nav/src/property-config/list-nav.property-config.ts +++ b/packages/ui-vue/components/list-nav/src/property-config/list-nav.property-config.ts @@ -23,7 +23,8 @@ export class ListNavProperty extends BaseControlProperty { min: 0, precision: 0 }, - $converter: "/converter/size.converter" + $converter: "/converter/size.converter", + parentPropertyID: 'size' }, height: { title: "高度", @@ -34,6 +35,7 @@ export class ListNavProperty extends BaseControlProperty { precision: 0 }, $converter: "/converter/size.converter", + parentPropertyID: 'size', visible: false } }, (changeObject, propertyData, parameters) => { diff --git a/packages/ui-vue/components/list-view/src/composition/use-remove.ts b/packages/ui-vue/components/list-view/src/composition/use-remove.ts index aa9a42d61a652bc1e0695687e7767400b5d293a9..ac79d3a03b213424aed60b6398479fb63efd3652 100644 --- a/packages/ui-vue/components/list-view/src/composition/use-remove.ts +++ b/packages/ui-vue/components/list-view/src/composition/use-remove.ts @@ -14,6 +14,9 @@ export function useRemove( function removeItem(index: number) { if (index > -1 && index < dataView.value.length) { + if (props?.checkBeforeRemoveItem && !props.checkBeforeRemoveItem(dataView.value[index])) { + return; + } const removedItem = dataView.value.splice(index, 1); updateSelectedItems(); context.emit('removeItem', removedItem[0]); diff --git a/packages/ui-vue/components/list-view/src/list-view.props.ts b/packages/ui-vue/components/list-view/src/list-view.props.ts index c4ad1470ac981c47f55b57b63d431faa5da73457..161eacae7339269cabe758112b3450cc03d26533 100644 --- a/packages/ui-vue/components/list-view/src/list-view.props.ts +++ b/packages/ui-vue/components/list-view/src/list-view.props.ts @@ -73,7 +73,8 @@ export const listViewProps = { enableHighlightSearch: { type: Boolean, default: true }, /** 虚拟化渲染数据 */ virtualized: { type: Boolean, default: true }, - + /** 删除数据前的检查方法,返回值为true时可以删除当前数据 */ + checkBeforeRemoveItem: { type: Function, default: null } } as Record; export type ListViewProps = ExtractPropTypes; diff --git a/packages/ui-vue/components/lookup/src/property-config/lookup.property-config.ts b/packages/ui-vue/components/lookup/src/property-config/lookup.property-config.ts index 1df2f5729da7b36c3b727ee86d03d8e8a2af7229..d34cad44aad9c2cdc7a01d8219963228f8e7b454 100644 --- a/packages/ui-vue/components/lookup/src/property-config/lookup.property-config.ts +++ b/packages/ui-vue/components/lookup/src/property-config/lookup.property-config.ts @@ -57,7 +57,7 @@ export class LookupPropertyConfig extends InputBaseProperty { const treeConfig = this.getTreePropConfig(propertyData.editor); // 'compute', 'dependency', - const expressons = this.getExpressionConfig(propertyData, 'Field'); + const expressions = this.getExpressionConfig(propertyData, 'Field'); const categories: any = { basic, @@ -67,7 +67,7 @@ export class LookupPropertyConfig extends InputBaseProperty { treeConfig, dialog, pager, - expressons + expressions }; if (propertyData.type === 'form-group') { @@ -165,6 +165,7 @@ export class LookupPropertyConfig extends InputBaseProperty { break; } }, + parentPropertyID: 'editor', properties: { readonly: { description: "", @@ -232,18 +233,22 @@ export class LookupPropertyConfig extends InputBaseProperty { } return ''; }, - viewOptions: [ - { - id: 'recommend', title: '推荐', type: 'List', - dataSource: 'Recommand', - enableGroup: true, - groupField: 'category', - groupFormatter: (value, data) => { - return `${value === 'local' ? '本地元数据' : '最近使用'}`; - } - }, - { id: 'total', title: '全部', type: 'List', dataSource: 'Total' } - ], + viewOptions: this.formSchemaUtils.designerMode === 'PC_RTC' ? + [ + { id: 'total', title: '全部', type: 'List', dataSource: 'Total' } + ] : + [ + { + id: 'recommend', title: '推荐', type: 'List', + dataSource: 'Recommand', + enableGroup: true, + groupField: 'category', + groupFormatter: (value, data) => { + return `${value === 'local' ? '本地元数据' : '最近使用'}`; + } + }, + { id: 'total', title: '全部', type: 'List', dataSource: 'Total' } + ], repositoryToken: LookupSchemaRepositoryToken, onSubmitModal: (dataSourceSchema: any) => { if (dataSourceSchema) { @@ -323,7 +328,7 @@ export class LookupPropertyConfig extends InputBaseProperty { if (JSON.stringify(conditions.value) === JSON.stringify(originalConditions.value)) { return true; } else { - await repository.saveFilterCondition(conditions.value, repositoryParams); + await repository.saveFilterCondition(conditions.value, repositoryParams, this.formSchemaUtils.getFormMetadataBasicInfo()); return true; } } @@ -532,6 +537,7 @@ export class LookupPropertyConfig extends InputBaseProperty { return { description: "帮助窗口尺寸配置", title: "帮助窗口", + parentPropertyID: 'dialog', properties: { title: { description: "帮助标题", @@ -631,6 +637,7 @@ export class LookupPropertyConfig extends InputBaseProperty { hide: this.getDisplayType(editorOptions) === 'TREELIST' || !editorOptions.helpId || disablePager, description: "分页配置", title: "分页", + parentPropertyID: 'pagination', properties: { // enable: { // description: "启用分页", @@ -720,6 +727,7 @@ export class LookupPropertyConfig extends InputBaseProperty { hide: this.getDisplayType(editorOptions) !== 'TREELIST' && this.getDisplayType(editorOptions) !== 'NAVTREELIST', description: "树形数据配置", title: "树形数据配置", + parentPropertyID: 'editor', properties: { treeToList: { description: "以列表的形式展示树结构数据", diff --git a/packages/ui-vue/components/number-range/src/property-config/number-range.property-config.json b/packages/ui-vue/components/number-range/src/property-config/number-range.property-config.json index 89975d2467a2768ed46df7b3a2a081ec413952c5..6c1ea9af744250f5b763ef1755f3311d22c43d13 100644 --- a/packages/ui-vue/components/number-range/src/property-config/number-range.property-config.json +++ b/packages/ui-vue/components/number-range/src/property-config/number-range.property-config.json @@ -41,8 +41,9 @@ "editor": { "description": "Basic Infomation", "title": "组件信息", - "type":"number-range", - "$converter":"/converter/property-editor.converter", + "type": "number-range", + "$converter": "/converter/property-editor.converter", + "parentPropertyID": "editor", "properties": { "readonly": { "description": "", @@ -53,7 +54,7 @@ "description": "", "title": "禁用", "type": "boolean" - }, + }, "editable": { "description": "", "title": "可编辑", @@ -67,4 +68,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts index 68a52edecde373c78455aa098f27cd817c7c51e4..18d39018d9b489a1f13830eccfadd18859ccc4a1 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/base-property.ts @@ -102,13 +102,15 @@ export class BaseControlProperty { title: "class样式", type: "string", description: "组件的CSS样式", - $converter: "/converter/appearance.converter" + $converter: "/converter/appearance.converter", + parentPropertyID: 'appearance' }, style: { title: "style样式", type: "string", description: "组件的样式", - $converter: "/converter/appearance.converter" + $converter: "/converter/appearance.converter", + parentPropertyID: 'appearance' } }; 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 527b57264302f1d1fffb14c28e419ece825ed1c9..ad4ad877bb5de19b82efce18428bd2cae6c8d5f5 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 @@ -34,7 +34,7 @@ export class InputBaseProperty extends BaseControlProperty { // 编辑器 this.propertyConfig.categories['editor'] = this.getEditorProperties(propertyData); // 表达式编辑器 - this.propertyConfig.categories['expressons'] = this.getExpressionConfig(propertyData, 'Field'); + this.propertyConfig.categories['expressions'] = this.getExpressionConfig(propertyData, 'Field'); // 事件 暂不支持 // this.propertyConfig.categories['eventsEditor'] = this.getEventPropertyConfig(propertyData); return this.propertyConfig; @@ -74,6 +74,7 @@ export class InputBaseProperty extends BaseControlProperty { title: '编辑器类型', type: 'string', $converter: '/converter/change-editor.converter', + parentPropertyID: 'editor', editor: { type: 'combo-list', textField: 'value', @@ -197,13 +198,15 @@ export class InputBaseProperty extends BaseControlProperty { title: "class样式", type: "string", description: "组件的CSS样式", - $converter: "/converter/appearance.converter" + $converter: "/converter/appearance.converter", + parentPropertyID: 'appearance' }, style: { title: "style样式", type: "string", description: "组件的内联样式", - $converter: "/converter/appearance.converter" + $converter: "/converter/appearance.converter", + parentPropertyID: 'appearance' }, responseLayout: { description: "响应式列宽", @@ -332,7 +335,8 @@ export class InputBaseProperty extends BaseControlProperty { description: "编辑器", title: "编辑器", type: "input-group", - $converter: "/converter/property-editor.converter" + $converter: "/converter/property-editor.converter", + parentPropertyID: 'editor' }, info); const readonlyEditor = this.getPropertyEditorParams(propertyData, [], 'readonly'); diff --git a/packages/ui-vue/components/property-panel/src/composition/entity/property-entity.ts b/packages/ui-vue/components/property-panel/src/composition/entity/property-entity.ts index a4a543fdd335bd652c180073ff77cd120b7d1b5d..9eed2a146f0c8ab4d69e399c13cb3c454da24b4a 100644 --- a/packages/ui-vue/components/property-panel/src/composition/entity/property-entity.ts +++ b/packages/ui-vue/components/property-panel/src/composition/entity/property-entity.ts @@ -118,6 +118,8 @@ export interface PropertyEntity { questionMessage?: string; editor?: EditorConfig; + + parentPropertyID?: string; } export interface ElementPropertyConfig { diff --git a/packages/ui-vue/components/property-panel/src/property-panel.component.tsx b/packages/ui-vue/components/property-panel/src/property-panel.component.tsx index 12becbbe364d284ebe19748d71a498f982ee2afc..c9481645f3f63d5bc325d015053b3512ee769317 100644 --- a/packages/ui-vue/components/property-panel/src/property-panel.component.tsx +++ b/packages/ui-vue/components/property-panel/src/property-panel.component.tsx @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { defineComponent, SetupContext, ref, watch, onMounted, onBeforeMount, inject, nextTick } from 'vue'; +import { defineComponent, SetupContext, ref, watch, onMounted, onBeforeMount, inject, nextTick, computed } from 'vue'; import { PropertyPanelProps, propertyPanelProps } from './composition/props/property-panel.props'; import { getPropertyConfigBySchemaForDesigner } from '../../dynamic-resolver/src/resolver/property-config/property-config-resolver-design'; import { SchemaService } from '../../dynamic-resolver'; @@ -73,6 +73,13 @@ export default defineComponent({ /** 给分类组件配置唯一id,用于切换控件时强制刷新分类 */ const categoryReload = ref(0); + /** 当前是否只有一个标签页 */ + const isOnlyTab = computed(() => { + return categoryTabs.map(category => !category.hide).length === 1; + }); + /** 设计器上下文 */ + const designerContext = inject('designerContext') as any; + function collectProperties() { properties = []; if (selectedTab.value && selectedTab.value.categoryList && Array.isArray(selectedTab.value.categoryList) && selectedTab.value.categoryList.length > 0) { @@ -309,6 +316,9 @@ export default defineComponent({ propertyConfig.value = []; } else { propertyConfig.value = getPropertyConfigBySchemaForDesigner(propertyData.value, schemaService as SchemaService, designerItem, componentId); + if (designerContext.filterPropertyEntity) { + propertyConfig.value = designerContext.filterPropertyEntity(propertyConfig.value, propertyData.value); + } } checkShowTabCategory(); onClearEvent(keyword.value); @@ -325,6 +335,9 @@ export default defineComponent({ propertyData.value = newSchema || props.schema; } propertyConfig.value = getPropertyConfigBySchemaForDesigner(propertyData.value, schemaService as SchemaService, designerItem, componentId, newPropertyConfig); + if (designerContext.filterPropertyEntity) { + propertyConfig.value = designerContext.filterPropertyEntity(propertyConfig.value, propertyData.value); + } checkShowTabCategory(); enableSearch.value && onClearEvent(keyword.value); refreshFlag && categoryReload.value++; @@ -370,6 +383,9 @@ export default defineComponent({ } function onRefreshPanel() { propertyConfig.value = getPropertyConfigBySchemaForDesigner(propertyData.value, schemaService as SchemaService, designerItem, componentId); + if (designerContext.filterPropertyEntity) { + propertyConfig.value = designerContext.filterPropertyEntity(propertyConfig.value, propertyData.value); + } checkShowTabCategory(); } /** 搜索框 */ @@ -486,7 +502,7 @@ export default defineComponent({ return categoryTabs.map((tab: any) => { return (
onChangeSelectedTab(tab)}> {tab.tabName}
@@ -525,7 +541,7 @@ export default defineComponent({ class={['property-panel', { 'white-theme': isWhiteTheme.value }]} style={handlePropertyPanelStyleObject()}>