sign.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <!-- -->
  3. <ui-group-option
  4. :class="`sign-guide ${hover || focus ? 'active' : ''} `"
  5. @click.stop="clickHandler"
  6. @mouseenter="enterHandler"
  7. @mouseleave="leaveHandler"
  8. >
  9. <div class="info">
  10. <div class="guide-cover">
  11. <span class="img">
  12. <ui-icon type="pic_path" class="path-icon" />
  13. </span>
  14. <!-- @click="playSceneGuide(paths, undefined, true)" -->
  15. <ui-icon
  16. type="preview"
  17. class="icon"
  18. ctrl
  19. @click.stop="playHandler()"
  20. v-if="path.points.length"
  21. />
  22. </div>
  23. <div>
  24. <p>{{ path.name }}</p>
  25. </div>
  26. </div>
  27. <div class="actions" v-if="edit" @click.stop>
  28. <ui-more
  29. :options="menus"
  30. style="margin-left: 20px"
  31. @click="(action: keyof typeof actions) => actions[action]()"
  32. />
  33. </div>
  34. </ui-group-option>
  35. </template>
  36. <script setup lang="ts">
  37. import { Path } from "@/store";
  38. import { getPathNode, playScenePath } from "@/sdk/association/path";
  39. import { computed, ref, watch, watchEffect } from "vue";
  40. import { custom } from "@/env";
  41. const props = withDefaults(defineProps<{ path: Path; edit?: boolean }>(), {
  42. edit: true,
  43. });
  44. const emit = defineEmits<{
  45. (e: "delete"): void;
  46. (e: "edit"): void;
  47. }>();
  48. const menus = [
  49. { label: "编辑", value: "edit" },
  50. { label: "删除", value: "delete" },
  51. ];
  52. const actions = {
  53. edit: () => emit("edit"),
  54. delete: () => emit("delete"),
  55. };
  56. const playHandler = () => {
  57. node.value?.focus(true);
  58. playScenePath(props.path, true);
  59. };
  60. const focus = ref(false);
  61. const hover = ref(false);
  62. const node = computed(() => getPathNode(props.path.id));
  63. watchEffect((onCleanup) => {
  64. if (!node.value) return;
  65. const $node = node.value;
  66. const focusHandler = (f: boolean) => {
  67. // node.value?.fly();
  68. focus.value = f;
  69. console.error("focus", f);
  70. };
  71. const leaveHandler = () => {
  72. hover.value = false;
  73. };
  74. const enterHandler = () => {
  75. hover.value = true;
  76. };
  77. $node.bus.on("enter", enterHandler);
  78. $node.bus.on("leave", leaveHandler);
  79. $node.bus.on("focus", focusHandler);
  80. onCleanup(() => $node.bus.off("focus", focusHandler));
  81. });
  82. const leaveHandler = () => {
  83. hover.value = false;
  84. node.value?.highlight && node.value?.highlight(false);
  85. };
  86. const enterHandler = () => {
  87. hover.value = true;
  88. node.value?.highlight && node.value?.highlight(true);
  89. };
  90. const clickHandler = () => {
  91. node.value?.fly();
  92. node.value?.focus(true);
  93. };
  94. </script>
  95. <style lang="scss" scoped>
  96. .sign-guide {
  97. display: flex;
  98. justify-content: space-between;
  99. align-items: center;
  100. padding: 20px 0;
  101. margin-bottom: 0;
  102. position: relative;
  103. cursor: pointer;
  104. &:first-child {
  105. }
  106. &.active::after {
  107. content: "";
  108. position: absolute;
  109. pointer-events: none;
  110. inset: 0 -20px;
  111. background-color: rgba(0, 200, 175, 0.16);
  112. }
  113. .info {
  114. flex: 1;
  115. display: flex;
  116. align-items: center;
  117. .guide-cover {
  118. position: relative;
  119. &::after {
  120. content: "";
  121. position: absolute;
  122. inset: 0;
  123. background: rgba(0, 0, 0, 0.2);
  124. }
  125. .icon {
  126. position: absolute;
  127. z-index: 1;
  128. left: 50%;
  129. top: 50%;
  130. transform: translate(-50%, -50%);
  131. font-size: 16px;
  132. }
  133. .path-icon {
  134. color: rgba(255, 255, 255, 0.2);
  135. font-size: 30px;
  136. }
  137. .img {
  138. width: 48px;
  139. height: 48px;
  140. object-fit: cover;
  141. border-radius: 4px;
  142. overflow: hidden;
  143. background-color: #535555;
  144. display: block;
  145. }
  146. }
  147. div {
  148. margin-left: 10px;
  149. p {
  150. color: #fff;
  151. word-break: break-all;
  152. font-size: 14px;
  153. margin-bottom: 6px;
  154. }
  155. }
  156. }
  157. .actions {
  158. flex: none;
  159. }
  160. }
  161. </style>