sign.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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="playScenePath(path, true)"
  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 focus = ref(false);
  57. const hover = ref(false);
  58. const node = computed(() => getPathNode(props.path.id));
  59. watchEffect((onCleanup) => {
  60. if (!node.value) return;
  61. const $node = node.value;
  62. const focusHandler = (f: boolean) => {
  63. // node.value?.fly();
  64. focus.value = f;
  65. console.error("focus", f);
  66. };
  67. const leaveHandler = () => {
  68. hover.value = false;
  69. };
  70. const enterHandler = () => {
  71. hover.value = true;
  72. };
  73. $node.bus.on("enter", enterHandler);
  74. $node.bus.on("leave", leaveHandler);
  75. $node.bus.on("focus", focusHandler);
  76. onCleanup(() => $node.bus.off("focus", focusHandler));
  77. });
  78. const leaveHandler = () => {
  79. hover.value = false;
  80. node.value?.highlight && node.value?.highlight(false);
  81. };
  82. const enterHandler = () => {
  83. hover.value = true;
  84. node.value?.highlight && node.value?.highlight(true);
  85. };
  86. const clickHandler = () => {
  87. node.value?.fly();
  88. };
  89. </script>
  90. <style lang="scss" scoped>
  91. .sign-guide {
  92. display: flex;
  93. justify-content: space-between;
  94. align-items: center;
  95. padding: 20px 0;
  96. margin-bottom: 0;
  97. border-bottom: 1px solid var(--colors-border-color);
  98. position: relative;
  99. cursor: pointer;
  100. &:first-child {
  101. border-top: 1px solid var(--colors-border-color);
  102. }
  103. &.active::after {
  104. content: "";
  105. position: absolute;
  106. pointer-events: none;
  107. inset: 0 -20px;
  108. background-color: rgba(0, 200, 175, 0.16);
  109. }
  110. .info {
  111. flex: 1;
  112. display: flex;
  113. align-items: center;
  114. .guide-cover {
  115. position: relative;
  116. &::after {
  117. content: "";
  118. position: absolute;
  119. inset: 0;
  120. background: rgba(0, 0, 0, 0.2);
  121. }
  122. .icon {
  123. position: absolute;
  124. z-index: 1;
  125. left: 50%;
  126. top: 50%;
  127. transform: translate(-50%, -50%);
  128. font-size: 16px;
  129. }
  130. .path-icon {
  131. color: rgba(255, 255, 255, 0.2);
  132. font-size: 30px;
  133. }
  134. .img {
  135. width: 48px;
  136. height: 48px;
  137. object-fit: cover;
  138. border-radius: 4px;
  139. overflow: hidden;
  140. background-color: #535555;
  141. display: block;
  142. }
  143. }
  144. div {
  145. margin-left: 10px;
  146. p {
  147. color: #fff;
  148. word-break: break-all;
  149. font-size: 14px;
  150. margin-bottom: 6px;
  151. }
  152. }
  153. }
  154. .actions {
  155. flex: none;
  156. }
  157. }
  158. </style>