diff --git a/packages/editor/src/services/editor.ts b/packages/editor/src/services/editor.ts index 623be30f..8a1b7f89 100644 --- a/packages/editor/src/services/editor.ts +++ b/packages/editor/src/services/editor.ts @@ -38,7 +38,6 @@ import { initPosition, isFixed, setLayout, - setNewItemId, } from '@editor/utils/editor'; import { log } from '@editor/utils/logger'; @@ -495,7 +494,7 @@ class Editor extends BaseService { return; } - setNewItemId(config, this.get('root')); + await propsService.setNewItemId(config, this.get('root')); if (config.style) { config.style = { ...config.style, diff --git a/packages/editor/src/services/props.ts b/packages/editor/src/services/props.ts index 3f571249..b5ab80ae 100644 --- a/packages/editor/src/services/props.ts +++ b/packages/editor/src/services/props.ts @@ -17,11 +17,12 @@ */ import { reactive } from 'vue'; -import { cloneDeep, mergeWith } from 'lodash-es'; +import { cloneDeep, mergeWith, random } from 'lodash-es'; import type { FormConfig } from '@tmagic/form'; -import type { MComponent, MNode } from '@tmagic/schema'; -import { toLine } from '@tmagic/utils'; +import type { Id, MComponent, MNode, MPage } from '@tmagic/schema'; +import { NodeType } from '@tmagic/schema'; +import { isPop, toLine } from '@tmagic/utils'; import type { PropsState } from '@editor/type'; import { DEFAULT_CONFIG, fillConfig, getDefaultPropsValue } from '@editor/utils/props'; @@ -35,7 +36,7 @@ class Props extends BaseService { }); constructor() { - super(['setPropsConfig', 'getPropsConfig', 'setPropsValue', 'getPropsValue']); + super(['setPropsConfig', 'getPropsConfig', 'setPropsValue', 'getPropsValue', 'createId', 'setNewItemId']); } public setPropsConfigs(configs: Record) { @@ -87,7 +88,7 @@ class Props extends BaseService { * @param type 组件类型 * @returns 组件初始值 */ - public async getPropsValue(type: string, defaultValue = {}) { + public async getPropsValue(type: string, defaultValue: Record = {}) { if (type === 'area') { const value = (await this.getPropsValue('button')) as MComponent; value.className = 'action-area'; @@ -98,13 +99,67 @@ class Props extends BaseService { return value; } + const data = cloneDeep(defaultValue as any); + + await this.setNewItemId(data); + return { - ...getDefaultPropsValue(type), - ...mergeWith(cloneDeep(this.state.propsValueMap[type] || {}), cloneDeep(defaultValue)), + ...getDefaultPropsValue(type, await this.createId(type)), + ...mergeWith(cloneDeep(this.state.propsValueMap[type] || {}), data), }; } + + public async createId(type: string | number): Promise { + return `${type}_${random(10000, false)}`; + } + + /** + * 将组件与组件的子元素配置中的id都设置成一个新的ID + * @param {Object} config 组件配置 + */ + /* eslint no-param-reassign: ["error", { "props": false }] */ + public async setNewItemId(config: MNode, parent?: MPage) { + const oldId = config.id; + + config.id = await this.createId(config.type || 'component'); + + // 只有弹窗在页面下的一级子元素才有效 + if (isPop(config) && parent?.type === NodeType.PAGE) { + updatePopId(oldId, config.id, parent); + } + + if (config.items && Array.isArray(config.items)) { + for (const item of config.items) { + await this.setNewItemId(item, config as MPage); + } + } + } } +/** + * 复制页面时,需要把组件下关联的弹窗id换测复制出来的弹窗的id + * @param {number} oldId 复制的源弹窗id + * @param {number} popId 新的弹窗id + * @param {Object} pageConfig 页面配置 + */ +const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => { + pageConfig.items?.forEach((config) => { + if (config.pop === oldId) { + config.pop = popId; + return; + } + + if (config.popId === oldId) { + config.popId = popId; + return; + } + + if (Array.isArray(config.items)) { + updatePopId(oldId, popId, config as MPage); + } + }); +}; + export type PropsService = Props; export default new Props(); diff --git a/packages/editor/src/utils/editor.ts b/packages/editor/src/utils/editor.ts index 43491fea..915c0e90 100644 --- a/packages/editor/src/utils/editor.ts +++ b/packages/editor/src/utils/editor.ts @@ -16,9 +16,7 @@ * limitations under the License. */ -import { random } from 'lodash-es'; - -import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema'; +import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema'; import { NodeType } from '@tmagic/schema'; import type StageCore from '@tmagic/stage'; import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils'; @@ -27,8 +25,6 @@ import { Layout } from '@editor/type'; export const COPY_STORAGE_KEY = '$MagicEditorCopyData'; -export const generateId = (type: string | number): string => `${type}_${random(10000, false)}`; - /** * 获取所有页面配置 * @param app DSL跟节点 @@ -74,51 +70,6 @@ export const generatePageName = (pageNameList: string[]): string => { */ export const generatePageNameByApp = (app: MApp): string => generatePageName(getPageNameList(getPageList(app))); -/** - * 复制页面时,需要把组件下关联的弹窗id换测复制出来的弹窗的id - * @param {number} oldId 复制的源弹窗id - * @param {number} popId 新的弹窗id - * @param {Object} pageConfig 页面配置 - */ -const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => { - pageConfig.items?.forEach((config) => { - if (config.pop === oldId) { - config.pop = popId; - return; - } - - if (config.popId === oldId) { - config.popId = popId; - return; - } - - if (Array.isArray(config.items)) { - updatePopId(oldId, popId, config as MPage); - } - }); -}; - -/** - * 将组件与组件的子元素配置中的id都设置成一个新的ID - * @param {Object} config 组件配置 - */ -/* eslint no-param-reassign: ["error", { "props": false }] */ -export const setNewItemId = (config: MNode, parent?: MPage) => { - const oldId = config.id; - - config.id = generateId(config.type || 'component'); - config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`; - - // 只有弹窗在页面下的一级子元素才有效 - if (isPop(config) && parent?.type === NodeType.PAGE) { - updatePopId(oldId, config.id, parent); - } - - if (config.items && Array.isArray(config.items)) { - config.items.forEach((item) => setNewItemId(item, config as MPage)); - } -}; - /** * @param {Object} node * @returns {boolean} diff --git a/packages/editor/src/utils/props.ts b/packages/editor/src/utils/props.ts index 1fbc1c5a..8a194602 100644 --- a/packages/editor/src/utils/props.ts +++ b/packages/editor/src/utils/props.ts @@ -20,7 +20,6 @@ import { FormConfig, FormState } from '@tmagic/form'; import editorService from '@editor/services/editor'; import eventsService from '@editor/services/events'; -import { generateId } from '@editor/utils/editor'; /** * 统一为组件属性表单加上事件、高级、样式配置 @@ -244,9 +243,9 @@ export const DEFAULT_CONFIG: FormConfig = fillConfig([]); * @param type 组件类型 * @returns Object */ -export const getDefaultPropsValue = (type: string) => ({ +export const getDefaultPropsValue = (type: string, id: string) => ({ type, - id: generateId(type), + id, style: {}, name: type, }); diff --git a/packages/editor/tests/unit/services/props.spec.ts b/packages/editor/tests/unit/services/props.spec.ts new file mode 100644 index 00000000..295d6c06 --- /dev/null +++ b/packages/editor/tests/unit/services/props.spec.ts @@ -0,0 +1,63 @@ +import { describe, expect, test } from 'vitest'; + +import { NodeType } from '@tmagic/schema'; + +import props from '@editor/services/props'; + +test('createId', async () => { + const id = await props.createId('text'); + + console.log(id); + + expect(id.startsWith('text')).toBeTruthy(); +}); + +describe('setNewItemId', () => { + test('普通', async () => { + const config = { + id: 1, + type: 'text', + }; + // 将组件与组件的子元素配置中的id都设置成一个新的ID + await props.setNewItemId(config); + expect(config.id === 1).toBeFalsy(); + }); + + test('items', async () => { + const config = { + id: 1, + type: NodeType.PAGE, + items: [ + { + type: 'text', + id: 2, + }, + ], + }; + await props.setNewItemId(config); + expect(config.id === 1).toBeFalsy(); + expect(config.items[0].id === 2).toBeFalsy(); + }); + + test('pop', async () => { + const config = { + id: 1, + type: NodeType.PAGE, + items: [ + { + type: 'button', + id: 2, + pop: 3, + }, + { + type: 'pop', + id: 3, + }, + ], + }; + await props.setNewItemId(config); + expect(config.items[0].pop === 3).toBeFalsy(); + expect(config.items[1].id === 3).toBeFalsy(); + expect(config.items[1].id === config.items[0].pop).toBeTruthy(); + }); +}); diff --git a/packages/editor/tests/unit/utils/editor.spec.ts b/packages/editor/tests/unit/utils/editor.spec.ts index b4382e03..6576c2e4 100644 --- a/packages/editor/tests/unit/utils/editor.spec.ts +++ b/packages/editor/tests/unit/utils/editor.spec.ts @@ -23,12 +23,6 @@ import { NodeType } from '@tmagic/schema'; import * as editor from '@editor/utils/editor'; describe('util form', () => { - test('generateId', () => { - const id = editor.generateId('text'); - - expect(id.startsWith('text')).toBeTruthy(); - }); - test('getPageList', () => { const pageList = editor.getPageList({ id: 'app_1', @@ -67,56 +61,6 @@ describe('util form', () => { }); }); -describe('setNewItemId', () => { - test('普通', () => { - const config = { - id: 1, - type: 'text', - }; - // 将组件与组件的子元素配置中的id都设置成一个新的ID - editor.setNewItemId(config); - expect(config.id === 1).toBeFalsy(); - }); - - test('items', () => { - const config = { - id: 1, - type: NodeType.PAGE, - items: [ - { - type: 'text', - id: 2, - }, - ], - }; - editor.setNewItemId(config); - expect(config.id === 1).toBeFalsy(); - expect(config.items[0].id === 2).toBeFalsy(); - }); - - test('pop', () => { - const config = { - id: 1, - type: NodeType.PAGE, - items: [ - { - type: 'button', - id: 2, - pop: 3, - }, - { - type: 'pop', - id: 3, - }, - ], - }; - editor.setNewItemId(config); - expect(config.items[0].pop === 3).toBeFalsy(); - expect(config.items[1].id === 3).toBeFalsy(); - expect(config.items[1].id === config.items[0].pop).toBeTruthy(); - }); -}); - describe('isFixed', () => { test('true', () => { expect( diff --git a/packages/editor/tests/unit/utils/form.spec.ts b/packages/editor/tests/unit/utils/form.spec.ts index be828b96..6234ae44 100644 --- a/packages/editor/tests/unit/utils/form.spec.ts +++ b/packages/editor/tests/unit/utils/form.spec.ts @@ -44,7 +44,8 @@ describe('util form', () => { }); test('getDefaultValue', () => { - const value = props.getDefaultPropsValue('text'); - expect(value.id.startsWith('text')).toBeTruthy(); + const value = props.getDefaultPropsValue('text', '1'); + expect(value.id).toBe('1'); + expect(value.type).toBe('text'); }); });