style(editor): 将节点类型改成枚举

This commit is contained in:
roymondchen 2022-03-30 19:33:54 +08:00 committed by khuntoriia
parent 148d4547b0
commit 6dbda7b565
14 changed files with 67 additions and 43 deletions

View File

@ -41,6 +41,8 @@
import { computed, defineComponent, inject, PropType } from 'vue'; import { computed, defineComponent, inject, PropType } from 'vue';
import { ArrowDown, Back, Delete, Grid, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons'; import { ArrowDown, Back, Delete, Grid, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons';
import { NodeType } from '@tmagic/schema';
import MIcon from '@editor/components/Icon.vue'; import MIcon from '@editor/components/Icon.vue';
import type { MenuButton, MenuComponent, MenuItem, Services } from '@editor/type'; import type { MenuButton, MenuComponent, MenuItem, Services } from '@editor/type';
@ -87,7 +89,7 @@ export default defineComponent({
type: 'button', type: 'button',
icon: Delete, icon: Delete,
tooltip: '刪除', tooltip: '刪除',
disabled: () => services?.editorService.get('node')?.type === 'page', disabled: () => services?.editorService.get('node')?.type === NodeType.PAGE,
handler: () => services?.editorService.remove(services?.editorService.get('node')), handler: () => services?.editorService.remove(services?.editorService.get('node')),
}; };
case 'undo': case 'undo':

View File

@ -15,6 +15,8 @@
import { defineComponent, inject, toRaw } from 'vue'; import { defineComponent, inject, toRaw } from 'vue';
import { Plus } from '@element-plus/icons'; import { Plus } from '@element-plus/icons';
import { NodeType } from '@tmagic/schema';
import { Services } from '@editor/type'; import { Services } from '@editor/type';
import { generatePageNameByApp } from '@editor/utils'; import { generatePageNameByApp } from '@editor/utils';
@ -31,7 +33,7 @@ export default defineComponent({
if (!editorService) return; if (!editorService) return;
editorService.add({ editorService.add({
type: 'page', type: NodeType.PAGE,
name: generatePageNameByApp(toRaw(editorService.get('root'))), name: generatePageNameByApp(toRaw(editorService.get('root'))),
}); });
}, },

View File

@ -58,6 +58,7 @@ import type { ElTree } from 'element-plus';
import { throttle } from 'lodash-es'; import { throttle } from 'lodash-es';
import type { MNode, MPage } from '@tmagic/schema'; import type { MNode, MPage } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import type { EditorService } from '@editor/services/editor'; import type { EditorService } from '@editor/services/editor';
import type { Services } from '@editor/type'; import type { Services } from '@editor/type';
@ -88,8 +89,8 @@ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorServi
const { type: ingType } = ingData; const { type: ingType } = ingData;
if (ingType !== 'page' && data.type === 'page') return false; if (ingType !== NodeType.PAGE && data.type === NodeType.PAGE) return false;
if (ingType === 'page' && data.type !== 'page') return false; if (ingType === NodeType.PAGE && data.type !== NodeType.PAGE) return false;
if (!data || !data.type) return false; if (!data || !data.type) return false;
if (['prev', 'next'].includes(type)) return true; if (['prev', 'next'].includes(type)) return true;
if (data.items || data.type === 'container') return true; if (data.items || data.type === 'container') return true;

View File

@ -38,6 +38,7 @@ import { computed, defineComponent, inject, toRaw } from 'vue';
import { CaretBottom, Plus } from '@element-plus/icons'; import { CaretBottom, Plus } from '@element-plus/icons';
import type { MPage } from '@tmagic/schema'; import type { MPage } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import type { Services } from '@editor/type'; import type { Services } from '@editor/type';
import { generatePageNameByApp } from '@editor/utils/editor'; import { generatePageNameByApp } from '@editor/utils/editor';
@ -60,7 +61,7 @@ export default defineComponent({
addPage() { addPage() {
if (!editorService) return; if (!editorService) return;
const pageConfig = { const pageConfig = {
type: 'page', type: NodeType.PAGE,
name: generatePageNameByApp(toRaw(editorService.get('root'))), name: generatePageNameByApp(toRaw(editorService.get('root'))),
}; };
editorService.add(pageConfig); editorService.add(pageConfig);

View File

@ -24,6 +24,7 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, inject, onMounted, ref, watch } from 'vue'; import { computed, defineComponent, inject, onMounted, ref, watch } from 'vue';
import { NodeType } from '@tmagic/schema';
import type StageCore from '@tmagic/stage'; import type StageCore from '@tmagic/stage';
import { LayerOffset, Layout, Services } from '@editor/type'; import { LayerOffset, Layout, Services } from '@editor/type';
@ -53,7 +54,8 @@ export default defineComponent({
if (!parent.value || !editorService) return (canCenter.value = false); if (!parent.value || !editorService) return (canCenter.value = false);
const layout = await editorService.getLayout(parent.value); const layout = await editorService.getLayout(parent.value);
canCenter.value = canCenter.value =
[Layout.ABSOLUTE, Layout.FIXED].includes(layout) && !['app', 'page', 'pop'].includes(`${node.value?.type}`); [Layout.ABSOLUTE, Layout.FIXED].includes(layout) &&
![NodeType.ROOT, NodeType.PAGE, 'pop'].includes(`${node.value?.type}`);
}, },
{ immediate: true }, { immediate: true },
); );
@ -62,8 +64,8 @@ export default defineComponent({
menu, menu,
canPaste, canPaste,
canDelete: computed(() => node.value?.type !== 'page'), canDelete: computed(() => node.value?.type !== NodeType.PAGE),
canMoveZPos: computed(() => node.value?.type !== 'page'), canMoveZPos: computed(() => node.value?.type !== NodeType.PAGE),
canCenter, canCenter,
center() { center() {

View File

@ -21,6 +21,7 @@ import { cloneDeep, mergeWith } from 'lodash-es';
import serialize from 'serialize-javascript'; import serialize from 'serialize-javascript';
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema'; import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import type StageCore from '@tmagic/stage'; import type StageCore from '@tmagic/stage';
import { getNodePath, isPop } from '@tmagic/utils'; import { getNodePath, isPop } from '@tmagic/utils';
@ -121,7 +122,7 @@ class Editor extends BaseService {
info.parent = path[path.length - 2] as MContainer; info.parent = path[path.length - 2] as MContainer;
path.forEach((item) => { path.forEach((item) => {
if (item.type === 'page') { if (item.type === NodeType.PAGE) {
info.page = item as MPage; info.page = item as MPage;
return; return;
} }
@ -209,7 +210,7 @@ class Editor extends BaseService {
let parentNode: MNode | undefined; let parentNode: MNode | undefined;
if (type === 'page') { if (type === NodeType.PAGE) {
parentNode = this.get<MApp>('root'); parentNode = this.get<MApp>('root');
// 由于支持中间件扩展在parent参数为undefined时parent会变成next函数 // 由于支持中间件扩展在parent参数为undefined时parent会变成next函数
} else if (parent && typeof parent !== 'function') { } else if (parent && typeof parent !== 'function') {
@ -225,7 +226,7 @@ class Editor extends BaseService {
const layout = await this.getLayout(parentNode); const layout = await this.getLayout(parentNode);
const newNode = initPosition({ ...toRaw(await propsService.getPropsValue(type)), ...config }, layout); const newNode = initPosition({ ...toRaw(await propsService.getPropsValue(type)), ...config }, layout);
if ((parentNode?.type === 'app' || curNode.type === 'app') && newNode.type !== 'page') { if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
throw new Error('app下不能添加组件'); throw new Error('app下不能添加组件');
} }
@ -264,7 +265,7 @@ class Editor extends BaseService {
parent.items?.splice(index, 1); parent.items?.splice(index, 1);
this.get<StageCore>('stage')?.remove({ id: node.id, root: this.get('root') }); this.get<StageCore>('stage')?.remove({ id: node.id, root: this.get('root') });
if (node.type === 'page') { if (node.type === NodeType.PAGE) {
await this.select(root.items[0] || root); await this.select(root.items[0] || root);
} else { } else {
await this.select(parent); await this.select(parent);
@ -300,7 +301,7 @@ class Editor extends BaseService {
if (!newConfig.type) throw new Error('配置缺少type值'); if (!newConfig.type) throw new Error('配置缺少type值');
if (newConfig.type === 'app') { if (newConfig.type === NodeType.ROOT) {
this.set('root', newConfig); this.set('root', newConfig);
return newConfig; return newConfig;
} }
@ -327,7 +328,7 @@ class Editor extends BaseService {
this.get<StageCore>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') }); this.get<StageCore>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
if (newConfig.type === 'page') { if (newConfig.type === NodeType.PAGE) {
this.set('page', newConfig); this.set('page', newConfig);
} }

View File

@ -18,7 +18,8 @@
import { random } from 'lodash-es'; import { random } from 'lodash-es';
import { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema'; import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import { getNodePath, isPop } from '@tmagic/utils'; import { getNodePath, isPop } from '@tmagic/utils';
import { Layout } from '@editor/type'; import { Layout } from '@editor/type';
@ -34,7 +35,7 @@ export const generateId = (type: string | number): string => `${type}_${random(1
*/ */
export const getPageList = (app: MApp): MPage[] => { export const getPageList = (app: MApp): MPage[] => {
if (app.items && Array.isArray(app.items)) { if (app.items && Array.isArray(app.items)) {
return app.items.filter((item: MPage) => item.type === 'page'); return app.items.filter((item: MPage) => item.type === NodeType.PAGE);
} }
return []; return [];
}; };
@ -108,7 +109,7 @@ export const setNewItemId = (config: MNode, parent?: MPage) => {
config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`; config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
// 只有弹窗在页面下的一级子元素才有效 // 只有弹窗在页面下的一级子元素才有效
if (isPop(config) && parent?.type === 'page') { if (isPop(config) && parent?.type === NodeType.PAGE) {
updatePopId(oldId, config.id, parent); updatePopId(oldId, config.id, parent);
} }

View File

@ -20,6 +20,7 @@ import { mount } from '@vue/test-utils';
import ElementPlus from 'element-plus'; import ElementPlus from 'element-plus';
import MagicForm from '@tmagic/form'; import MagicForm from '@tmagic/form';
import { NodeType } from '@tmagic/schema';
import Editor from '@editor/Editor.vue'; import Editor from '@editor/Editor.vue';
@ -47,14 +48,14 @@ describe('编辑器', () => {
}, },
props: { props: {
modelValue: { modelValue: {
type: 'app', type: NodeType.ROOT,
id: 1, id: 1,
name: 'app', name: 'app',
items: [ items: [
{ {
type: 'page', type: NodeType.PAGE,
id: 2, id: 2,
name: 'page', name: NodeType.PAGE,
items: [], items: [],
}, },
], ],

View File

@ -19,13 +19,15 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import ElementPlus from 'element-plus'; import ElementPlus from 'element-plus';
import { NodeType } from '@tmagic/schema';
import PageBar from '@editor/layouts/workspace/PageBar.vue'; import PageBar from '@editor/layouts/workspace/PageBar.vue';
const editorState: Record<string, any> = { const editorState: Record<string, any> = {
root: { root: {
items: [{ key: 0, id: 1, name: 'testName', type: 'page' }], items: [{ key: 0, id: 1, name: 'testName', type: NodeType.PAGE }],
}, },
page: { id: 1, type: 'page' }, page: { id: 1, type: NodeType.PAGE },
}; };
const editorService = { const editorService = {
@ -54,7 +56,7 @@ describe('PageBar', () => {
await wrapper.find('i[class="el-icon m-editor-page-bar-menu-add-icon"]').trigger('click'); await wrapper.find('i[class="el-icon m-editor-page-bar-menu-add-icon"]').trigger('click');
expect(editorService.add.mock.calls[0][0]).toEqual({ expect(editorService.add.mock.calls[0][0]).toEqual({
type: 'page', type: NodeType.PAGE,
name: 'page_1', name: 'page_1',
}); });
done(); done();

View File

@ -18,6 +18,8 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { NodeType } from '@tmagic/schema';
import Stage from '@editor/layouts/workspace/Stage.vue'; import Stage from '@editor/layouts/workspace/Stage.vue';
globalThis.ResizeObserver = globalThis.ResizeObserver =
@ -40,7 +42,7 @@ describe('Stage.vue', () => {
); );
const page = { const page = {
type: 'page', type: NodeType.PAGE,
id: '2', id: '2',
items: [ items: [
{ {
@ -55,7 +57,7 @@ describe('Stage.vue', () => {
runtimeUrl: '', runtimeUrl: '',
root: { root: {
id: '1', id: '1',
type: 'app', type: NodeType.ROOT,
items: [page], items: [page],
}, },

View File

@ -18,7 +18,8 @@
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { MApp, MContainer, MNode, MPage } from '@tmagic/schema'; import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import editorService from '@editor/services/editor'; import editorService from '@editor/services/editor';
import { COPY_STORAGE_KEY } from '@editor/utils'; import { COPY_STORAGE_KEY } from '@editor/utils';
@ -72,12 +73,12 @@ enum NodeId {
// mock 页面数据,包含一个页面,两个组件 // mock 页面数据,包含一个页面,两个组件
const root: MNode = { const root: MNode = {
id: NodeId.ROOT_ID, id: NodeId.ROOT_ID,
type: 'app', type: NodeType.ROOT,
items: [ items: [
{ {
id: NodeId.PAGE_ID, id: NodeId.PAGE_ID,
layout: 'absolute', layout: 'absolute',
type: 'page', type: NodeType.PAGE,
style: { style: {
width: 375, width: 375,
}, },
@ -237,7 +238,7 @@ describe('add', () => {
const rootNode = editorService.get<MApp>('root'); const rootNode = editorService.get<MApp>('root');
const newNode = await editorService.add( const newNode = await editorService.add(
{ {
type: 'page', type: NodeType.PAGE,
}, },
rootNode, rootNode,
); );
@ -279,7 +280,7 @@ describe('remove', () => {
// 先加一个页面 // 先加一个页面
const newPage = await editorService.add( const newPage = await editorService.add(
{ {
type: 'page', type: NodeType.PAGE,
}, },
rootNode, rootNode,
); );
@ -395,7 +396,7 @@ describe('alignCenter', () => {
it('正常', async () => { it('正常', async () => {
// 设置当前编辑的页面 // 设置当前编辑的页面
await editorService.select(NodeId.PAGE_ID); await editorService.select(NodeId.PAGE_ID);
await editorService.update({ id: NodeId.PAGE_ID, isAbsoluteLayout: true, type: 'page' }); await editorService.update({ id: NodeId.PAGE_ID, isAbsoluteLayout: true, type: NodeType.PAGE });
await editorService.select(NodeId.NODE_ID); await editorService.select(NodeId.NODE_ID);
const node = editorService.get<MNode>('node'); const node = editorService.get<MNode>('node');
await editorService.alignCenter(node); await editorService.alignCenter(node);

View File

@ -16,7 +16,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { MNode } from '@tmagic/schema'; import type { MNode } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import * as editor from '@editor/utils/editor'; import * as editor from '@editor/utils/editor';
@ -30,12 +31,12 @@ describe('util form', () => {
it('getPageList', () => { it('getPageList', () => {
const pageList = editor.getPageList({ const pageList = editor.getPageList({
id: 'app_1', id: 'app_1',
type: 'app', type: NodeType.ROOT,
items: [ items: [
{ {
id: 'page_1', id: 'page_1',
name: 'index', name: 'index',
type: 'page', type: NodeType.PAGE,
items: [], items: [],
}, },
], ],
@ -49,7 +50,7 @@ describe('util form', () => {
{ {
id: 'page_1', id: 'page_1',
name: 'index', name: 'index',
type: 'page', type: NodeType.PAGE,
items: [], items: [],
}, },
]); ]);
@ -79,7 +80,7 @@ describe('setNewItemId', () => {
it('items', () => { it('items', () => {
const config = { const config = {
id: 1, id: 1,
type: 'page', type: NodeType.PAGE,
items: [ items: [
{ {
type: 'text', type: 'text',
@ -95,7 +96,7 @@ describe('setNewItemId', () => {
it('pop', () => { it('pop', () => {
const config = { const config = {
id: 1, id: 1,
type: 'page', type: NodeType.PAGE,
items: [ items: [
{ {
type: 'button', type: 'button',
@ -158,7 +159,7 @@ describe('getNodeIndex', () => {
}, },
{ {
id: 2, id: 2,
type: 'page', type: NodeType.PAGE,
items: [ items: [
{ {
type: 'text', type: 'text',
@ -179,7 +180,7 @@ describe('getNodeIndex', () => {
}, },
{ {
id: 2, id: 2,
type: 'page', type: NodeType.PAGE,
items: [ items: [
{ {
type: 'text', type: 'text',

View File

@ -16,6 +16,12 @@
* limitations under the License. * limitations under the License.
*/ */
export enum NodeType {
CONTAINER = 'container',
PAGE = 'page',
ROOT = 'app',
}
export type Id = string | number; export type Id = string | number;
export interface EventItemConfig { export interface EventItemConfig {
@ -47,19 +53,19 @@ export interface MComponent {
export interface MContainer extends MComponent { export interface MContainer extends MComponent {
/** 容器类型,默认为'container' */ /** 容器类型,默认为'container' */
type: 'container' | string; type: NodeType.CONTAINER | string;
/** 容器子元素 */ /** 容器子元素 */
items: (MComponent | MContainer)[]; items: (MComponent | MContainer)[];
} }
export interface MPage extends MContainer { export interface MPage extends MContainer {
/** 页面类型 */ /** 页面类型 */
type: 'page'; type: NodeType.PAGE;
} }
export interface MApp extends MComponent { export interface MApp extends MComponent {
/** App页面类型app作为整个结构的根节点有且只有一个 */ /** App页面类型app作为整个结构的根节点有且只有一个 */
type: 'app'; type: NodeType.ROOT;
/** */ /** */
items: MPage[]; items: MPage[];
} }

View File

@ -31,6 +31,7 @@ import { ElMessage } from 'element-plus';
import serialize from 'serialize-javascript'; import serialize from 'serialize-javascript';
import type { MenuBarData, MoveableOptions, TMagicEditor } from '@tmagic/editor'; import type { MenuBarData, MoveableOptions, TMagicEditor } from '@tmagic/editor';
import { NodeType } from '@tmagic/schema';
import StageCore from '@tmagic/stage'; import StageCore from '@tmagic/stage';
import { asyncLoadJs } from '@tmagic/utils'; import { asyncLoadJs } from '@tmagic/utils';
@ -155,7 +156,7 @@ export default defineComponent({
if (!node) return options; if (!node) return options;
const isPage = node.type === 'page'; const isPage = node.type === NodeType.PAGE;
options.draggable = !isPage; options.draggable = !isPage;
options.resizable = !isPage; options.resizable = !isPage;