diff --git a/packages/amis-editor-core/src/component/Panel/CodeEditorPanel.tsx b/packages/amis-editor-core/src/component/Panel/CodeEditorPanel.tsx index da5c6034f..36ffecd62 100644 --- a/packages/amis-editor-core/src/component/Panel/CodeEditorPanel.tsx +++ b/packages/amis-editor-core/src/component/Panel/CodeEditorPanel.tsx @@ -9,7 +9,7 @@ export default class CodeEditorPanel extends React.Component { setTimeout(() => { this.props.manager.patchSchema(true); - // 检测是否整体粘贴组件,如果是的话强制替换ID避免样式bug + // 检测是否整体粘贴组件,如果是的话对指定类型组件存在重复ID的重新生成 if ( e?.languageId === 'json' && e.range?.startColumn === 1 && @@ -17,7 +17,7 @@ export default class CodeEditorPanel extends React.Component { e.range?.endColumn === 2 && e.range?.endLineNumber > 1 ) { - this.props.manager.reGenerateCurrentNodeID(); + this.props.manager.reGenerateNodeDuplicateID(['布局容器', '展示']); } }, 500); } diff --git a/packages/amis-editor-core/src/manager.ts b/packages/amis-editor-core/src/manager.ts index 397b75756..57492bbab 100644 --- a/packages/amis-editor-core/src/manager.ts +++ b/packages/amis-editor-core/src/manager.ts @@ -9,7 +9,7 @@ import debounce from 'lodash/debounce'; import findIndex from 'lodash/findIndex'; import omit from 'lodash/omit'; import {openContextMenus, toast, alert, DataScope, DataSchema} from 'amis'; -import {getRenderers, RenderOptions, mapTree, isEmpty} from 'amis-core'; +import {getRenderers, RenderOptions, JSONTraverse} from 'amis-core'; import { PluginInterface, BasicPanelItem, @@ -57,7 +57,8 @@ import { JSONPipeOut, scrollToActive, JSONPipeIn, - JSONGetById + generateNodeId, + JSONGetNodesById } from './util'; import {hackIn, makeSchemaFormRender, makeWrapper} from './component/factory'; import {env} from './env'; @@ -1565,14 +1566,56 @@ export class EditorManager { } /** - * 重新生成当前节点的 id + * 重新生成当前节点的重复的id */ - reGenerateCurrentNodeID() { + reGenerateNodeDuplicateID(types: Array = []) { const node = this.store.getNodeById(this.store.activeId); if (!node) { return; } - this.replaceChild(node.id, reGenerateID(node.schema)); + let schema = node.schema; + let changed = false; + + // 支持按照类型过滤某类型组件 + let tags = node.info?.plugin?.tags || []; + if (!Array.isArray(tags)) { + tags = [tags]; + } + if (types.length && !tags.some(tag => types.includes(tag))) { + return; + } + + // 记录组件新旧ID映射关系方便当前组件内事件动作替换 + let idRefs: {[propKey: string]: string} = {}; + + // 如果有多个重复组件,则重新生成ID + JSONTraverse(schema, (value: any, key: string, host: any) => { + const isNodeIdFormat = + typeof value === 'string' && value.indexOf('u:') === 0; + if (key === 'id' && isNodeIdFormat && host) { + let sameNodes = JSONGetNodesById(this.store.schema, value, 'id'); + if (sameNodes && sameNodes.length > 1) { + let newId = generateNodeId(); + idRefs[value] = newId; + host[key] = newId; + changed = true; + } + } + return value; + }); + + if (changed) { + // 替换当前组件内事件动作里面可能的ID + JSONTraverse(schema, (value: any, key: string, host: any) => { + const isNodeIdFormat = + typeof value === 'string' && value.indexOf('u:') === 0; + if (key === 'componentId' && isNodeIdFormat && idRefs[value]) { + host.componentId = idRefs[value]; + } + return value; + }); + this.replaceChild(node.id, schema); + } } /** diff --git a/packages/amis-editor-core/src/util.ts b/packages/amis-editor-core/src/util.ts index abddb39b6..c140bfef9 100644 --- a/packages/amis-editor-core/src/util.ts +++ b/packages/amis-editor-core/src/util.ts @@ -322,6 +322,21 @@ export function JSONGetById(json: any, id: string, idKey?: string): any { return JSONGetByPath(json, paths); } +export function JSONGetNodesById( + json: any, + id: string, + idKey: string = '$$id' +): Array { + let result: Array = []; + + JSONTraverse(json, (value: any, key: string, host: any) => { + if (key === idKey && value == id) { + result.push(host); + } + }); + return result; +} + export function JSONGetParentById( json: any, id: string,