ElementTree.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <template>
  2. <div class="elements">
  3. <div class="title" style="margin: 8px 0 0 12px">图纸结构</div>
  4. <t-tree
  5. class="flex-grow"
  6. ref="tree"
  7. :data="data.tree"
  8. v-model:actived="data.actived"
  9. activable
  10. :expand-parent="true"
  11. @active="onActive"
  12. style="padding: 0 4px 8px 0"
  13. >
  14. <template #label="{ node }: any">
  15. <div class="flex middle" :class="{ gray: node.data.visible === false }">
  16. <template v-if="node.getChildren()">
  17. <t-icon v-if="node.expanded" name="folder-open" />
  18. <t-icon v-else name="folder" />
  19. </template>
  20. <t-icon v-else name="control-platform" />
  21. {{ node.label }}
  22. </div>
  23. </template>
  24. <template #operations="{ node }: any">
  25. <div
  26. class="flex middle operations"
  27. :class="{
  28. gray: node.data.visible === false,
  29. show: node.data.visible === false || node.data.locked,
  30. }"
  31. style="width: 36px; height: 16px"
  32. >
  33. <t-tooltip
  34. class="mr-4"
  35. v-if="!node.data.locked"
  36. content="可编辑"
  37. placement="top"
  38. >
  39. <t-icon name="lock-off" @click="lock(node, 1)" />
  40. </t-tooltip>
  41. <t-tooltip
  42. class="mr-4"
  43. v-else-if="node.data.locked == 1"
  44. content="禁止编辑"
  45. placement="top"
  46. >
  47. <t-icon name="lock-on" @click="lock(node, 2)" />
  48. </t-tooltip>
  49. <t-tooltip
  50. class="mr-4"
  51. v-else-if="node.data.locked == 2"
  52. content="禁止编辑和移动"
  53. placement="top"
  54. >
  55. <svg class="l-icon" aria-hidden="true" @click="lock(node, 10)">
  56. <use xlink:href="#l-wufayidong"></use>
  57. </svg>
  58. </t-tooltip>
  59. <t-tooltip
  60. class="mr-4"
  61. v-else-if="node.data.locked == 10"
  62. content="禁止所有事件"
  63. placement="top"
  64. >
  65. <svg class="l-icon" aria-hidden="true" @click="lock(node, 0)">
  66. <use xlink:href="#l-jinyong"></use>
  67. </svg>
  68. </t-tooltip>
  69. <t-icon
  70. v-if="node.data.visible !== false"
  71. name="browse"
  72. @click="visible(node, false)"
  73. />
  74. <t-icon v-else name="browse-off" @click="visible(node, true)" />
  75. </div>
  76. </template>
  77. </t-tree>
  78. <div class="groups">
  79. <div class="flex middle between">
  80. <div class="title" style="margin-bottom: 8px">图层分组</div>
  81. <a> +新建分组</a>
  82. </div>
  83. </div>
  84. </div>
  85. </template>
  86. <script lang="ts" setup>
  87. import { onBeforeMount, onBeforeUnmount, reactive, ref } from 'vue';
  88. import { LockState, Pen } from '@meta2d/core';
  89. const tree = ref<any>(null);
  90. const data = reactive<any>({
  91. tree: [],
  92. actived: [],
  93. });
  94. onBeforeMount(() => {
  95. meta2d.on('opened', getTree);
  96. meta2d.on('add', getTree);
  97. meta2d.on('undo', getTree);
  98. meta2d.on('redo', getTree);
  99. meta2d.on('delete', getTree);
  100. meta2d.on('combine', getTree);
  101. getTree();
  102. });
  103. const getTree = () => {
  104. data.tree = [];
  105. for (const item of meta2d.store.data.pens) {
  106. if (item.parentId) {
  107. continue;
  108. }
  109. const elem = calcElem(item);
  110. elem && data.tree.push(elem);
  111. }
  112. };
  113. const calcElem = (node: Pen) => {
  114. if (!node) {
  115. return;
  116. }
  117. const elem: any = {
  118. label: (node as any).description || node.name,
  119. value: node.id,
  120. locked: node.locked,
  121. visible: node.visible,
  122. };
  123. if (!node.children) {
  124. return elem;
  125. }
  126. elem.children = [];
  127. for (const id of node.children) {
  128. const child = calcElem(meta2d.store.pens[id]);
  129. child && elem.children.push(child);
  130. }
  131. return elem;
  132. };
  133. const onActive = (value: string[]) => {
  134. if (!value.length) {
  135. return;
  136. }
  137. const pens: Pen[] = [];
  138. for (const item of meta2d.store.data.pens) {
  139. for (const v of value) {
  140. if (item.id === v) {
  141. pens.push(item);
  142. }
  143. }
  144. }
  145. meta2d.active(pens, false);
  146. meta2d.render();
  147. };
  148. const lock = (node: any, v: LockState) => {
  149. node.data.locked = v;
  150. meta2d.setValue({
  151. id: node.value,
  152. locked: v,
  153. });
  154. };
  155. const visible = (node: any, v: boolean) => {
  156. node.data.visible = v;
  157. setChildrenVisible(node, v);
  158. const pen = meta2d.findOne(node.value);
  159. pen && meta2d.setVisible(pen, v);
  160. };
  161. function setChildrenVisible(node: any, v: boolean) {
  162. const children = node.getChildren();
  163. if (children && children.length > 0) {
  164. for (const child of children) {
  165. child.data.visible = v;
  166. setChildrenVisible(child, v);
  167. }
  168. }
  169. }
  170. onBeforeUnmount(() => {
  171. meta2d.off('opened', getTree);
  172. meta2d.off('add', getTree);
  173. meta2d.off('undo', getTree);
  174. meta2d.off('redo', getTree);
  175. meta2d.off('delete', getTree);
  176. meta2d.off('combine', getTree);
  177. });
  178. </script>
  179. <style lang="postcss" scoped>
  180. .elements {
  181. display: flex;
  182. flex-direction: column;
  183. height: 100%;
  184. & > * {
  185. overflow-y: auto;
  186. width: 100%;
  187. &::-webkit-scrollbar {
  188. width: 2px;
  189. height: 6px;
  190. }
  191. }
  192. .groups {
  193. flex-shrink: 0;
  194. height: 240px;
  195. border-top: 1px solid var(--color-border);
  196. padding: 8px 12px;
  197. }
  198. }
  199. </style>