Alsmile преди 2 години
родител
ревизия
4258944d5f
променени са 6 файла, в които са добавени 264 реда и са изтрити 68 реда
  1. 10 0
      index.html
  2. 4 0
      src/styles/app.css
  3. 73 1
      src/styles/props.css
  4. 8 30
      src/views/Index.vue
  5. 169 36
      src/views/components/ElementTree.vue
  6. 0 1
      src/views/components/Header.vue

+ 10 - 0
index.html

@@ -18,6 +18,16 @@
       href="https://editor.yuque.com/ne-editor/lake-content-v1.css"
       rel="stylesheet"
     />
+    <style type="text/css">
+      .l-icon {
+        width: 1em;
+        height: 1em;
+        vertical-align: -0.15em;
+        fill: currentColor;
+        overflow: hidden;
+      }
+    </style>
+    <script src="//at.alicdn.com/t/c/font_4042197_m37o5op4iyq.js"></script>
   </head>
   <body>
     <div id="app"></div>

+ 4 - 0
src/styles/app.css

@@ -199,6 +199,10 @@ a.hover:hover {
   margin-left: 4px;
 }
 
+.mr-4 {
+  margin-right: 4px;
+}
+
 .ml-8 {
   margin-left: 8px;
 }

+ 73 - 1
src/styles/props.css

@@ -33,7 +33,7 @@
           background: none;
           border-color: transparent;
           color: var(--color-title);
-          padding-right: 20px;
+          padding-right: 16px;
 
           &:hover,
           &.t-is-focused {
@@ -116,4 +116,76 @@
       color: var(--color-primary);
     }
   }
+
+  .t-tree__empty {
+    color: var(--color-gray);
+    margin-left: 12px;
+  }
+
+  .t-tree__item {
+    cursor: pointer;
+
+    svg {
+      width: 16px;
+      color: var(--td-text-color-primary);
+
+      &:hover {
+        color: var(--color-primary);
+      }
+    }
+
+    .gray svg {
+      color: var(--color-gray);
+    }
+
+    .t-tree__label {
+      .t-icon {
+        font-size: 14px;
+        margin-right: 4px;
+      }
+    }
+
+    &.t-is-active {
+      .t-tree__label,
+      svg,
+      .gray {
+        color: var(--color-primary);
+      }
+    }
+
+    .t-tree__operations {
+      padding: 0 8px;
+
+      .operations {
+        * {
+          display: none;
+        }
+
+        &.show {
+          * {
+            display: flex;
+          }
+        }
+      }
+    }
+
+    &:hover {
+      color: var(--color-primary);
+      .t-tree__label,
+      svg,
+      .gray {
+        color: var(--color-primary);
+      }
+
+      .t-tree__operations {
+        .operations * {
+          display: flex;
+        }
+      }
+    }
+
+    .t-tree__icon:not(:empty):hover {
+      background: none;
+    }
+  }
 }

+ 8 - 30
src/views/Index.vue

@@ -15,18 +15,9 @@
 </template>
 
 <script lang="ts" setup>
-import {
-  onBeforeMount,
-  reactive,
-  onMounted,
-  onUnmounted,
-  ref,
-  provide,
-  nextTick,
-} from 'vue';
+import { onUnmounted, nextTick } from 'vue';
 import axios from 'axios';
-// import { Pen } from "@meta2d/core";
-import { strictAssign } from '@/services/utils';
+import { Pen } from '@meta2d/core';
 
 import Header from './components/Header.vue';
 import Graphics from './components/Graphics.vue';
@@ -39,22 +30,12 @@ import { useSelection, SelectionMode } from '@/services/selections';
 
 const { selections } = useSelection();
 
-const data = reactive<any>({});
-// const activePen= ref<Pen>({});
-//   const activePens= ref<Pen[]>([]);
-//   provide('activePen', activePen);
-//   provide('activePens', activePens);
-
-onBeforeMount(async () => {});
-
 const active = (oldPens: Pen[]) => {
   setTimeout(() => {
     const pens = getPenRectPens(oldPens);
     checkPropType(pens);
-    // 永远提供一个数组值
-    // activePens.value = oldPens;
     selections.pens = oldPens;
-  }, 1);
+  }, 10);
 };
 
 /**
@@ -62,22 +43,15 @@ const active = (oldPens: Pen[]) => {
  */
 const checkPropType = (pens: Pen[]) => {
   if (pens.length === 1) {
-    // 选中单个画笔
     selections.mode = SelectionMode.Pen;
     if (Array.isArray(pens[0].frames)) {
       (pens[0] as any).showDuration = meta2d.calcAnimateDuration(pens[0]);
     }
-    // strictAssign(activePen.value, pens[0]);
     selections.pen = pens[0];
-    // changeHidden(lastActive.Pen);
   } else if (pens.length > 1) {
     selections.mode = SelectionMode.Pens;
-    // type.value = Type.Pens;
-    // changeHidden(lastActive.Pens);
   } else {
     selections.mode = SelectionMode.File;
-    // type.value = Type.Canvas;
-    // changeHidden(lastActive.Canvas);
   }
 };
 
@@ -93,7 +67,7 @@ function getPenRectPens(oldPens: Pen[]): Pen[] {
 
 const inactive = (pens: Pen[]) => {
   setTimeout(() => {
-    active(meta2d.store.active);
+    active(meta2d.store.active as Pen[]);
   });
 };
 
@@ -103,12 +77,16 @@ const inactive = (pens: Pen[]) => {
 // });
 
 nextTick(() => {
+  // @ts-ignore
   meta2d.on('active', active);
+  // @ts-ignore
   meta2d.on('inactive', inactive);
 });
 
 onUnmounted(() => {
+  // @ts-ignore
   meta2d.off('active', active);
+  // @ts-ignore
   meta2d.off('inactive', inactive);
 });
 </script>

+ 169 - 36
src/views/components/ElementTree.vue

@@ -1,5 +1,6 @@
 <template>
   <div class="elements">
+    <div class="title" style="margin: 8px 0 0 12px">图纸结构</div>
     <t-tree
       class="flex-grow"
       ref="tree"
@@ -8,19 +9,73 @@
       activable
       :expand-parent="true"
       @active="onActive"
-      style="margin: 8px 0"
+      style="padding: 0 4px 8px 0"
     >
-      <template #icon="{ node }">
-        <template v-if="!node.data.leaf">
-          <t-icon v-if="node.expanded" name="chevron-down" />
-          <t-icon v-else name="chevron-right" />
-        </template>
-      </template>
-      <template #label="{ node }">
-        <div class="flex middle">
+      <template #label="{ node }: any">
+        <div class="flex middle" :class="{ gray: node.data.visible === false }">
+          <template v-if="node.getChildren()">
+            <t-icon v-if="node.expanded" name="folder-open" />
+            <t-icon v-else name="folder" />
+          </template>
+          <t-icon v-else name="control-platform" />
+
           {{ node.label }}
         </div>
       </template>
+      <template #operations="{ node }: any">
+        <div
+          class="flex middle operations"
+          :class="{
+            gray: node.data.visible === false,
+            show: node.data.visible === false || node.data.locked,
+          }"
+          style="width: 36px; height: 16px"
+        >
+          <t-tooltip
+            class="mr-4"
+            v-if="!node.data.locked"
+            content="可编辑"
+            placement="top"
+          >
+            <t-icon name="lock-off" @click="lock(node, 1)" />
+          </t-tooltip>
+          <t-tooltip
+            class="mr-4"
+            v-else-if="node.data.locked == 1"
+            content="禁止编辑"
+            placement="top"
+          >
+            <t-icon name="lock-on" @click="lock(node, 2)" />
+          </t-tooltip>
+          <t-tooltip
+            class="mr-4"
+            v-else-if="node.data.locked == 2"
+            content="禁止编辑和移动"
+            placement="top"
+          >
+            <svg class="l-icon" aria-hidden="true" @click="lock(node, 10)">
+              <use xlink:href="#l-wufayidong"></use>
+            </svg>
+          </t-tooltip>
+          <t-tooltip
+            class="mr-4"
+            v-else-if="node.data.locked == 10"
+            content="禁止所有事件"
+            placement="top"
+          >
+            <svg class="l-icon" aria-hidden="true" @click="lock(node, 0)">
+              <use xlink:href="#l-jinyong"></use>
+            </svg>
+          </t-tooltip>
+
+          <t-icon
+            v-if="node.data.visible !== false"
+            name="browse"
+            @click="visible(node, false)"
+          />
+          <t-icon v-else name="browse-off" @click="visible(node, true)" />
+        </div>
+      </template>
     </t-tree>
     <div class="groups">
       <div class="flex middle between">
@@ -32,40 +87,112 @@
 </template>
 
 <script lang="ts" setup>
-import { onBeforeMount, reactive, ref } from 'vue';
+import { onBeforeMount, onBeforeUnmount, reactive, ref } from 'vue';
+import { LockState, Pen } from '@meta2d/core';
 
 const tree = ref<any>(null);
 const data = reactive<any>({
-  tree: [
-    {
-      label: '图元1',
-      children: [
-        {
-          label: '图元1.1',
-        },
-        {
-          label: '图元1.2',
-        },
-      ],
-    },
-    {
-      label: '图元2',
-      children: [
-        {
-          label: '图元2.1',
-        },
-        {
-          label: '图元2.2',
-        },
-      ],
-    },
-  ],
+  tree: [],
   actived: [],
 });
 
-onBeforeMount(() => {});
+onBeforeMount(() => {
+  meta2d.on('opened', getTree);
+  meta2d.on('add', getTree);
+  meta2d.on('undo', getTree);
+  meta2d.on('redo', getTree);
+  meta2d.on('delete', getTree);
+  meta2d.on('combine', getTree);
+
+  getTree();
+});
+
+const getTree = () => {
+  data.tree = [];
+  for (const item of meta2d.store.data.pens) {
+    if (item.parentId) {
+      continue;
+    }
+    const elem = calcElem(item);
+    elem && data.tree.push(elem);
+  }
+};
+
+const calcElem = (node: Pen) => {
+  if (!node) {
+    return;
+  }
+
+  const elem: any = {
+    label: (node as any).description || node.name,
+    value: node.id,
+    locked: node.locked,
+    visible: node.visible,
+  };
+
+  if (!node.children) {
+    return elem;
+  }
+
+  elem.children = [];
+  for (const id of node.children) {
+    const child = calcElem(meta2d.store.pens[id]);
+    child && elem.children.push(child);
+  }
+
+  return elem;
+};
+
+const onActive = (value: string[]) => {
+  if (!value.length) {
+    return;
+  }
+
+  const pens: Pen[] = [];
+  for (const item of meta2d.store.data.pens) {
+    for (const v of value) {
+      if (item.id === v) {
+        pens.push(item);
+      }
+    }
+  }
+  meta2d.active(pens, false);
+  meta2d.render();
+};
+
+const lock = (node: any, v: LockState) => {
+  node.data.locked = v;
+  meta2d.setValue({
+    id: node.value,
+    locked: v,
+  });
+};
+
+const visible = (node: any, v: boolean) => {
+  node.data.visible = v;
+  setChildrenVisible(node, v);
+  const pen = meta2d.findOne(node.value);
+  pen && meta2d.setVisible(pen, v);
+};
 
-const onActive = (value: string[]) => {};
+function setChildrenVisible(node: any, v: boolean) {
+  const children = node.getChildren();
+  if (children && children.length > 0) {
+    for (const child of children) {
+      child.data.visible = v;
+      setChildrenVisible(child, v);
+    }
+  }
+}
+
+onBeforeUnmount(() => {
+  meta2d.off('opened', getTree);
+  meta2d.off('add', getTree);
+  meta2d.off('undo', getTree);
+  meta2d.off('redo', getTree);
+  meta2d.off('delete', getTree);
+  meta2d.off('combine', getTree);
+});
 </script>
 <style lang="postcss" scoped>
 .elements {
@@ -75,6 +202,12 @@ const onActive = (value: string[]) => {};
 
   & > * {
     overflow-y: auto;
+    width: 100%;
+
+    &::-webkit-scrollbar {
+      width: 2px;
+      height: 6px;
+    }
   }
 
   .groups {

+ 0 - 1
src/views/components/Header.vue

@@ -9,7 +9,6 @@
       :maxHeight="560"
       :delay2="[10, 150]"
       overlayClassName="header-dropdown"
-      trigger="click"
     >
       <a> 文件 </a>
       <t-dropdown-menu>