Skip to content

Commit

Permalink
refactor(editor): 代码编辑、数据源重构
Browse files Browse the repository at this point in the history
  • Loading branch information
roymondchen committed Dec 8, 2023
1 parent 258d2bc commit 741140f
Show file tree
Hide file tree
Showing 17 changed files with 245 additions and 212 deletions.
4 changes: 4 additions & 0 deletions packages/editor/src/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<slot name="layer-node-content" :data="data"></slot>
</template>

<template #layer-node-label="{ data }">
<slot name="layer-node-label" :data="data"></slot>
</template>

<template #layer-node-tool="{ data }">
<slot name="layer-node-tool" :data="data"></slot>
</template>
Expand Down
5 changes: 5 additions & 0 deletions packages/editor/src/components/Tree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<slot name="tree-node-content" :data="nodeData"> </slot>
</template>

<template #tree-node-label="{ data: nodeData }">
<slot name="tree-node-label" :data="nodeData"> </slot>
</template>

<template #tree-node-tool="{ data: nodeData }">
<slot name="tree-node-tool" :data="nodeData"> </slot>
</template>
Expand All @@ -28,6 +32,7 @@ import TreeNode from './TreeNode.vue';
defineSlots<{
'tree-node-content'(props: { data: TreeNodeData }): any;
'tree-node-label'(props: { data: TreeNodeData }): any;
'tree-node-tool'(props: { data: TreeNodeData }): any;
}>();
Expand Down
8 changes: 7 additions & 1 deletion packages/editor/src/components/TreeNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@

<div class="tree-node-content" @click="nodeClickHandler">
<slot name="tree-node-content" :data="data">
<div class="tree-node-label">{{ `${data.name} (${data.id})` }}</div>
<div class="tree-node-label">
<slot name="tree-node-label" :data="data">{{ `${data.name} (${data.id})` }}</slot>
</div>
<div class="tree-node-tool">
<slot name="tree-node-tool" :data="data"></slot>
</div>
Expand All @@ -44,6 +46,9 @@
<template #tree-node-content="{ data: nodeData }">
<slot name="tree-node-content" :data="nodeData"> </slot>
</template>
<template #tree-node-label="{ data: nodeData }">
<slot name="tree-node-label" :data="nodeData"> </slot>
</template>
<template #tree-node-tool="{ data: nodeData }">
<slot name="tree-node-tool" :data="nodeData"> </slot>
</template>
Expand All @@ -63,6 +68,7 @@ import type { LayerNodeStatus, TreeNodeData } from '@editor/type';
import { updateStatus } from '@editor/utils/tree';
defineSlots<{
'tree-node-label'(props: { data: TreeNodeData }): any;
'tree-node-tool'(props: { data: TreeNodeData }): any;
'tree-node-content'(props: { data: TreeNodeData }): any;
}>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { computed, type ComputedRef, ref } from 'vue';
import { type Ref, ref } from 'vue';

import { Id, MNode } from '@tmagic/schema';
import type { Id, MNode } from '@tmagic/schema';

import { LayerNodeStatus, Services } from '@editor/type';
import type { LayerNodeStatus, TreeNodeData } from '@editor/type';
import { traverseNode } from '@editor/utils';
import { updateStatus } from '@editor/utils/tree';

export const useFilter = (
services: Services | undefined,
nodeStatusMap: ComputedRef<Map<Id, LayerNodeStatus> | undefined>,
nodeData: Ref<TreeNodeData[]>,
nodeStatusMap: Ref<Map<Id, LayerNodeStatus> | undefined>,
filterNodeMethod: (value: string, data: MNode) => boolean,
) => {
const page = computed(() => services?.editorService.get('page'));

// tree方法:对树节点进行筛选时执行的方法
const filterIsMatch = (value: string | string[], data: MNode): boolean => {
const string = !Array.isArray(value) ? [value] : value;
Expand All @@ -25,18 +23,14 @@ export const useFilter = (
};

const filter = (text: string | string[]) => {
if (!page.value?.items?.length) return;
if (!nodeData.value.length) return;

page.value.items.forEach((node) => {
nodeData.value.forEach((node) => {
traverseNode(node, (node: MNode, parents: MNode[]) => {
if (!nodeStatusMap.value) return;

const visible = filterIsMatch(text, node);
if (visible && parents.length) {
console.log(
node.id,
parents.map((a) => a.id),
);
parents.forEach((parent) => {
updateStatus(nodeStatusMap.value!, parent.id, {
visible,
Expand Down
48 changes: 48 additions & 0 deletions packages/editor/src/hooks/use-node-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ComputedRef, ref, watch } from 'vue';

import type { Id, MNode } from '@tmagic/schema';

import { LayerNodeStatus, TreeNodeData } from '@editor/type';
import { traverseNode } from '@editor/utils';

const createPageNodeStatus = (nodeData: TreeNodeData[], initalLayerNodeStatus?: Map<Id, LayerNodeStatus>) => {
const map = new Map<Id, LayerNodeStatus>();

nodeData.forEach((node: MNode) =>
traverseNode(node, (node) => {
map.set(
node.id,
initalLayerNodeStatus?.get(node.id) || {
visible: true,
expand: false,
selected: false,
draggable: false,
},
);
}),
);

return map;
};

export const useNodeStatus = (nodeData: ComputedRef<TreeNodeData[]>) => {
/** 所有页面的节点状态 */
const nodeStatusMap = ref(new Map<Id, LayerNodeStatus>());

// 切换页面或者新增页面,重新生成节点状态
watch(
nodeData,
(nodeData) => {
// 生成节点状态
nodeStatusMap.value = createPageNodeStatus(nodeData, nodeStatusMap.value);
},
{
immediate: true,
deep: true,
},
);

return {
nodeStatusMap,
};
};
5 changes: 5 additions & 0 deletions packages/editor/src/layouts/sidebar/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
<component v-else-if="config.slots?.layerNodeContent" :is="config.slots.layerNodeContent" :data="nodeData" />
</template>

<template #layer-node-label="{ data: nodeData }" v-if="config.$key === 'layer' || config.slots?.layerNodeLabel">
<slot v-if="config.$key === 'layer'" name="layer-node-label" :data="nodeData"></slot>
<component v-else-if="config.slots?.layerNodeLabel" :is="config.slots.layerNodeTool" :data="nodeData" />
</template>

<template #layer-node-tool="{ data: nodeData }" v-if="config.$key === 'layer' || config.slots?.layerNodeTool">
<slot v-if="config.$key === 'layer'" name="layer-node-tool" :data="nodeData"></slot>
<component v-else-if="config.slots?.layerNodeTool" :is="config.slots.layerNodeTool" :data="nodeData" />
Expand Down
120 changes: 55 additions & 65 deletions packages/editor/src/layouts/sidebar/code-block/CodeBlockList.vue
Original file line number Diff line number Diff line change
@@ -1,57 +1,42 @@
<template>
<TMagicTree
ref="tree"
class="magic-editor-layer-tree"
node-key="id"
empty-text="暂无代码块"
:default-expanded-keys="expandedKeys"
:expand-on-click-node="false"
:data="codeList"
:props="{
children: 'children',
label: 'name',
value: 'id',
}"
:highlight-current="true"
:filter-node-method="filterNode"
@node-click="clickHandler"
>
<template #default="{ data }">
<div :id="data.id" class="list-container">
<div class="list-item">
<CodeIcon v-if="data.type === 'code'" class="codeIcon"></CodeIcon>
<AppManageIcon v-if="data.type === 'node'" class="compIcon"></AppManageIcon>
<span class="name" :class="{ code: data.type === 'code', hook: data.type === 'key' }"
>{{ data.name }} ({{ data.id }})</span
>
<!-- 右侧工具栏 -->
<div class="right-tool" v-if="data.type === 'code'">
<TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
<Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(data.id)"></Icon>
</TMagicTooltip>
<TMagicTooltip v-if="editable" effect="dark" content="删除" placement="bottom">
<Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.id}`)"></Icon>
</TMagicTooltip>
<slot name="code-block-panel-tool" :id="data.id" :data="data.codeBlockContent"></slot>
</div>
</div>
<Tree :data="codeList" :node-status-map="nodeStatusMap" @node-click="clickHandler">
<template #tree-node-label="{ data }">
<div
:class="{
code: data.type === 'code',
hook: data.type === 'key',
disabled: data.type === 'key' || data.type === 'code',
}"
>
{{ data.name }} {{ data.key ? `(${data.key})` : '' }}
</div>
</template>
</TMagicTree>

<template #tree-node-tool="{ data }">
<TMagicTooltip v-if="data.type === 'code'" effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
<Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(`${data.key}`)"></Icon>
</TMagicTooltip>
<TMagicTooltip v-if="data.type === 'code' && editable" effect="dark" content="删除" placement="bottom">
<Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.key}`)"></Icon>
</TMagicTooltip>
<slot name="code-block-panel-tool" :id="data.key" :data="data.codeBlockContent"></slot>
</template>
</Tree>
</template>

<script lang="ts" setup>
import { computed, inject, ref } from 'vue';
import { computed, inject } from 'vue';
import { Close, Edit, View } from '@element-plus/icons-vue';
import { DepTargetType } from '@tmagic/dep';
import { tMagicMessage, tMagicMessageBox, TMagicTooltip, TMagicTree } from '@tmagic/design';
import type { Id } from '@tmagic/schema';
import { tMagicMessage, tMagicMessageBox, TMagicTooltip } from '@tmagic/design';
import type { Id, MNode } from '@tmagic/schema';
import Icon from '@editor/components/Icon.vue';
import AppManageIcon from '@editor/icons/AppManageIcon.vue';
import CodeIcon from '@editor/icons/CodeIcon.vue';
import { type CodeBlockListSlots, CodeDeleteErrorType, type CodeDslItem, type Services } from '@editor/type';
import Tree from '@editor/components/Tree.vue';
import { useFilter } from '@editor/hooks/use-filter';
import { useNodeStatus } from '@editor/hooks/use-node-status';
import { type CodeBlockListSlots, CodeDeleteErrorType, type Services, type TreeNodeData } from '@editor/type';
defineSlots<CodeBlockListSlots>();
Expand All @@ -68,50 +53,59 @@ const emit = defineEmits<{
remove: [id: string];
}>();
const { codeBlockService, depService, editorService } = inject<Services>('services') || {};
const services = inject<Services>('services');
const { codeBlockService, depService, editorService } = services || {};
// 代码块列表
const codeList = computed(() =>
const codeList = computed<TreeNodeData[]>(() =>
Object.values(depService?.getTargets(DepTargetType.CODE_BLOCK) || {}).map((target) => {
// 组件节点
const compNodes = Object.entries(target.deps).map(([id, dep]) => ({
const compNodes: TreeNodeData[] = Object.entries(target.deps).map(([id, dep]) => ({
name: dep.name,
type: 'node',
id,
children: dep.keys.map((key) => ({ name: key, id: key, type: 'key' })),
id: `${target.id}_${id}`,
key: id,
items: dep.keys.map((key) => {
const data: TreeNodeData = { name: `${key}`, id: `${target.id}_${id}_${key}`, type: 'key' };
return data;
}),
}));
return {
const data: TreeNodeData = {
id: target.id,
key: target.id,
name: target.name,
type: 'code',
codeBlockContent: codeBlockService?.getCodeContentById(target.id),
children: compNodes,
items: compNodes,
};
return data;
}),
);
// 默认展开组件层级的节点
const expandedKeys = computed(() => codeList.value.map((item) => item.id));
const editable = computed(() => codeBlockService?.getEditStatus());
const filterNode = (value: string, data: CodeDslItem): boolean => {
const filterNode = (value: string, data: MNode): boolean => {
if (!value) {
return true;
}
return `${data.name}${data.id}`.toLocaleLowerCase().indexOf(value.toLocaleLowerCase()) !== -1;
return `${data.name}${data.id}`.toLocaleLowerCase().includes(value.toLocaleLowerCase());
};
const { nodeStatusMap } = useNodeStatus(codeList);
const { filterTextChangeHandler } = useFilter(codeList, nodeStatusMap, filterNode);
const editable = computed(() => codeBlockService?.getEditStatus());
// 选中组件
const selectComp = (compId: Id) => {
const stage = editorService?.get('stage');
editorService?.select(compId);
stage?.select(compId);
};
const clickHandler = (data: any, node: any) => {
const clickHandler = (event: MouseEvent, data: any) => {
if (data.type === 'node') {
selectComp(data.id);
} else if (data.type === 'key') {
selectComp(node.parent.data.id);
selectComp(data.key);
}
};
Expand All @@ -122,7 +116,7 @@ const editCode = (id: string) => {
const deleteCode = async (id: string) => {
const currentCode = codeList.value.find((codeItem) => codeItem.id === id);
const existBinds = Boolean(currentCode?.children.length);
const existBinds = Boolean(currentCode?.items?.length);
const undeleteableList = codeBlockService?.getUndeletableList() || [];
if (!existBinds && !undeleteableList.includes(id)) {
await tMagicMessageBox.confirm('确定删除该代码块吗?', '提示', {
Expand All @@ -142,11 +136,7 @@ const deleteCode = async (id: string) => {
}
};
const tree = ref<InstanceType<typeof TMagicTree>>();
defineExpose({
filter(val: string) {
tree.value?.filter(val);
},
filter: filterTextChangeHandler,
});
</script>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<TMagicScrollbar class="m-editor-code-block-list m-editor-dep-list-panel">
<TMagicScrollbar class="m-editor-code-block-list m-editor-layer-panel">
<slot name="code-block-panel-header">
<div class="search-wrapper">
<SearchInput @search="filterTextChangeHandler"></SearchInput>
Expand All @@ -17,6 +17,7 @@
</template>
</CodeBlockList>
</TMagicScrollbar>

<!-- 代码块编辑区 -->
<CodeBlockEditor
v-if="codeConfig"
Expand Down
Loading

0 comments on commit 741140f

Please sign in to comment.