From 4f73e2b82110a005c33d254cd522bc3c869ba324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E9=B9=8F=E6=97=AD?= Date: Sun, 30 Nov 2025 14:18:37 +0800 Subject: [PATCH] =?UTF-8?q?feat(editor):=20=E4=BD=BF=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=A4=A7=E7=BB=84=E4=BB=B6=E7=9A=84=E5=86=85=E9=83=A8=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E8=83=BD=E5=8D=95=E7=8B=AC=E8=BF=9B=E8=A1=8C=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E9=85=8D=E7=BD=AE=EF=BC=8C=E5=B9=B6=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E4=B8=80=E4=B8=AAgame=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor/src/components/TreeNode.vue | 6 + .../src/layouts/props-panel/PropsPanel.vue | 37 ++- packages/editor/src/services/editor.ts | 33 +- vue-components/game/package.json | 36 +++ vue-components/game/src/event.ts | 6 + vue-components/game/src/formConfig.ts | 43 +++ vue-components/game/src/index.ts | 25 ++ vue-components/game/src/index.vue | 282 ++++++++++++++++++ vue-components/game/src/initValue.ts | 30 ++ 9 files changed, 492 insertions(+), 6 deletions(-) create mode 100644 vue-components/game/package.json create mode 100644 vue-components/game/src/event.ts create mode 100644 vue-components/game/src/formConfig.ts create mode 100644 vue-components/game/src/index.ts create mode 100644 vue-components/game/src/index.vue create mode 100644 vue-components/game/src/initValue.ts diff --git a/packages/editor/src/components/TreeNode.vue b/packages/editor/src/components/TreeNode.vue index 958e7364af..518331796b 100644 --- a/packages/editor/src/components/TreeNode.vue +++ b/packages/editor/src/components/TreeNode.vue @@ -154,6 +154,12 @@ const expandHandler = () => { }; const nodeClickHandler = (event: MouseEvent) => { + const { data, parent } = props; + if (data.comInnerModule) { + data[data.comInnerModule] = parent?.[data.comInnerModule]; + data.parentId = parent?.id; + data.type = parent?.type; + } treeEmit?.('node-click', event, props.data); }; diff --git a/packages/editor/src/layouts/props-panel/PropsPanel.vue b/packages/editor/src/layouts/props-panel/PropsPanel.vue index bffbf306f1..f9e6ef8068 100644 --- a/packages/editor/src/layouts/props-panel/PropsPanel.vue +++ b/packages/editor/src/layouts/props-panel/PropsPanel.vue @@ -100,7 +100,7 @@ const values = ref({}); const curFormConfig = ref([]); const node = computed(() => editorService.get('node')); const nodes = computed(() => editorService.get('nodes')); - +let innerModuleEditingInfo: { name: string; parentId: string; id: string } | null = null; const styleFormConfig = [ { tabPosition: 'right', @@ -116,7 +116,36 @@ const init = async () => { const type = node.value.type || (node.value.items ? 'container' : 'text'); curFormConfig.value = await propsService.getPropsConfig(type); - values.value = node.value; + innerModuleEditingInfo = null; + if (node.value.comInnerModule) { + // 从左侧点击进入子模块配置 + innerModuleEditingInfo = { + name: node.value.comInnerModule, + parentId: node.value.parentId, + id: String(node.value.id), + }; + } + + if (innerModuleEditingInfo) { + const { name } = innerModuleEditingInfo; + const curFormConfigItems = curFormConfig.value[0].items; + const { length } = curFormConfigItems; + for (let i = 0; i < length; i++) { + if (curFormConfigItems[i].title !== '属性') { + continue; + } + const len2 = curFormConfigItems[i].items.length; + for (let j = 0; j < len2; j++) { + if (curFormConfigItems[i].items[j].name === name) { + curFormConfigItems[i].items = curFormConfigItems[i].items[j].items; + break; + } + } + } + values.value = node.value[name] || {}; + } else { + values.value = node.value; + } }; watchEffect(init); @@ -128,6 +157,10 @@ onBeforeUnmount(() => { const submit = async (v: MNode, eventData?: ContainerChangeEventData) => { try { + if (innerModuleEditingInfo !== null) { + v._innerModuleEditingInfo = innerModuleEditingInfo; + v.id = innerModuleEditingInfo.id; + } if (!v.id) { v.id = values.value.id; } diff --git a/packages/editor/src/services/editor.ts b/packages/editor/src/services/editor.ts index 60ac1560c7..150b923968 100644 --- a/packages/editor/src/services/editor.ts +++ b/packages/editor/src/services/editor.ts @@ -519,14 +519,31 @@ class Editor extends BaseService { if (!config?.id) throw new Error('没有配置或者配置缺少id值'); - const info = this.getNodeInfo(config.id, false); + let info = this.getNodeInfo(config.id, false); if (!info.node) throw new Error(`获取不到id为${config.id}的节点`); - const node = toRaw(info.node); - - let newConfig = await this.toggleFixedPosition(toRaw(config), node, root); + let node = toRaw(info.node); + let tempConfig = config; + if (config._innerModuleEditingInfo) { + // 如果是组件内嵌模块的属性修改,则找到组件node进行修改(只能是组件内一层的结构 -- 只找了一个parent) + const moduleKey = config._innerModuleEditingInfo.name; + const parentNode = toRaw(info.parent); + + const nodeSubModule = (node as any)[moduleKey]; + if (nodeSubModule) { + const newObj: Record = {}; + Object.keys(nodeSubModule).forEach((key) => { + newObj[key] = (config as any)[key]; + }); + (parentNode as any)[moduleKey] = newObj; + tempConfig = parentNode!; + node = toRaw(info.parent)!; + info = this.getNodeInfo(parentNode!.id, true); + } + } + let newConfig = await this.toggleFixedPosition(toRaw(tempConfig), node, root); newConfig = mergeWith(cloneDeep(node), newConfig, (objValue, srcValue, key, object: any, source: any) => { if (typeof srcValue === 'undefined' && Object.hasOwn(source, key)) { return ''; @@ -542,6 +559,14 @@ class Editor extends BaseService { }); if (!newConfig.type) throw new Error('配置缺少type值'); + if (config._innerModuleEditingInfo) { + // 如果是组件内嵌模块的属性修改, 不做后面的更新 + return { + oldNode: node, + newNode: newConfig, + changeRecords, + }; + } if (newConfig.type === NodeType.ROOT) { this.set('root', newConfig as MApp); diff --git a/vue-components/game/package.json b/vue-components/game/package.json new file mode 100644 index 0000000000..13c6af3869 --- /dev/null +++ b/vue-components/game/package.json @@ -0,0 +1,36 @@ +{ + "version": "0.2.0", + "name": "@tmagic/vue-game", + "type": "module", + "main": "src/index.ts", + "files": [ + "src" + ], + "engines": { + "node": ">=18" + }, + "repository": { + "type": "git", + "url": "https://github.com/Tencent/tmagic-editor.git" + }, + "dependencies": { + "@tmagic/form-schema": "workspace:^", + "vue-demi": "^0.14.10" + }, + "peerDependencies": { + "@tmagic/core": "workspace:^", + "@tmagic/vue-runtime-help": "workspace:^", + "@vue/composition-api": ">=1.7.2", + "typescript": "catalog:", + "vue": ">=2.6.0 || >=3.5.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + + "typescript": { + "optional": true + } + } +} diff --git a/vue-components/game/src/event.ts b/vue-components/game/src/event.ts new file mode 100644 index 0000000000..51bc8ffb3e --- /dev/null +++ b/vue-components/game/src/event.ts @@ -0,0 +1,6 @@ +import { COMMON_EVENT_PREFIX } from '@tmagic/core'; + +export default { + methods: [], + events: [{ label: '点击', value: `${COMMON_EVENT_PREFIX}click` }], +}; diff --git a/vue-components/game/src/formConfig.ts b/vue-components/game/src/formConfig.ts new file mode 100644 index 0000000000..7c4828b470 --- /dev/null +++ b/vue-components/game/src/formConfig.ts @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making TMagicEditor available. + * + * Copyright (C) 2025 Tencent. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineFormConfig } from '@tmagic/form-schema'; + +export default defineFormConfig([ + { + text: '游戏级别', + name: 'level', + type: 'select', + placeholder: '请选择级别', + options: [ + { text: '简单', value: 1 }, + { text: '困难', value: 2 }, + ], + }, + { + name: 'prizeDialog', + type: 'hide', + items: [ + { + text: '奖品名称', + name: 'prizeName', + type: 'data-source-input', + }, + ], + }, +]); diff --git a/vue-components/game/src/index.ts b/vue-components/game/src/index.ts new file mode 100644 index 0000000000..04b870fec8 --- /dev/null +++ b/vue-components/game/src/index.ts @@ -0,0 +1,25 @@ +/* + * Tencent is pleased to support the open source community by making TMagicEditor available. + * + * Copyright (C) 2025 Tencent. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Game from './index.vue'; + +export { default as config } from './formConfig'; +export { default as value } from './initValue'; +export { default as event } from './event'; + +export default Game; diff --git a/vue-components/game/src/index.vue b/vue-components/game/src/index.vue new file mode 100644 index 0000000000..7559fea593 --- /dev/null +++ b/vue-components/game/src/index.vue @@ -0,0 +1,282 @@ + + + + diff --git a/vue-components/game/src/initValue.ts b/vue-components/game/src/initValue.ts new file mode 100644 index 0000000000..30d46758ab --- /dev/null +++ b/vue-components/game/src/initValue.ts @@ -0,0 +1,30 @@ +/* + * Tencent is pleased to support the open source community by making TMagicEditor available. + * + * Copyright (C) 2025 Tencent. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default { + style: { + width: '100%', + height: '200', + border: 0, + backgroundColor: '#fb6f00', + }, + level: 1, + prizeDialog: { + prizeName: '可乐糖', + }, +};