index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <template>
  2. <RightFillPano>
  3. <h3>{{ tagging?.title }}放置位置</h3>
  4. <Collapse v-model:activeKey="showId" ghost accordion expandIconPosition="end">
  5. <template v-for="(position, i) in positions" :key="position.id">
  6. <PositionSign
  7. v-show="!(unKeepAdding && position.id !== showId)"
  8. :position="position"
  9. :title="`位置${i + 1}`"
  10. @applyGlobal="(keys) => applyGlobal(position, keys)"
  11. @delete="deletePosition(position)"
  12. @show="showId = position.id"
  13. />
  14. </template>
  15. </Collapse>
  16. <Teleport to="#layout-app">
  17. <span
  18. @click="unKeepAdding ? unKeepAdding() : keepAdding()"
  19. class="pin-position strengthen fun-ctrl"
  20. >
  21. <ui-icon
  22. :style="{ color: unKeepAdding ? 'var(--color-main-normal)' : 'currentColor' }"
  23. type="pin1"
  24. size="22px"
  25. />
  26. </span>
  27. </Teleport>
  28. </RightFillPano>
  29. </template>
  30. <script lang="ts" setup>
  31. import PositionSign from "./sign.vue";
  32. import { router } from "@/router";
  33. import { Dialog, Message } from "bill/index";
  34. import { RightFillPano } from "@/layout";
  35. import { asyncTimeout, debounce } from "@/utils";
  36. import { useViewStack } from "@/hook";
  37. import { flyTaggingPosition as flyTaggingPositionRaw } from "@/hook/use-fly";
  38. import {
  39. computed,
  40. nextTick,
  41. onUnmounted,
  42. ref,
  43. shallowRef,
  44. watch,
  45. watchEffect,
  46. } from "vue";
  47. import { getTaggingPosNode, sdk, taggingsGroup } from "@/sdk";
  48. import { custom, showTaggingPositionsStack } from "@/env";
  49. import {
  50. autoSaveTaggings,
  51. getFuseModel,
  52. getFuseModelShowVariable,
  53. getTaggingPositions,
  54. taggingPositions,
  55. createTaggingPosition,
  56. getTagging,
  57. enterEdit,
  58. } from "@/store";
  59. import { Collapse } from "ant-design-vue";
  60. import type { TaggingPosition } from "@/store";
  61. import { clickListener } from "@/utils/event";
  62. import { useCameraChange } from "@/hook/use-pixel";
  63. const showId = ref<TaggingPosition["id"]>();
  64. const tagging = computed(() => getTagging(router.currentRoute.value.params.id as string));
  65. const positions = computed(() => tagging.value && getTaggingPositions(tagging.value));
  66. onUnmounted(() => unKeepAdding.value && unKeepAdding.value());
  67. useViewStack(autoSaveTaggings);
  68. useViewStack(() => {
  69. taggingsGroup.changeCanMove(true);
  70. taggingsGroup.showDelete(true);
  71. enterEdit(() => router.back());
  72. return () => {
  73. taggingsGroup.changeCanMove(false);
  74. taggingsGroup.showDelete(false);
  75. };
  76. });
  77. watch(showId, (id) => {
  78. const position = positions.value?.find((item) => item.id === id);
  79. if (custom.showMode === "fuse") {
  80. position && flyTaggingPosition(position);
  81. }
  82. });
  83. const [pose] = useCameraChange(() => sdk.getPose());
  84. watch(
  85. [
  86. showId,
  87. pose,
  88. () => {
  89. const pos = positions.value?.find((item) => item.id === showId.value);
  90. return [pos?.localPos, pos?.lineHeight];
  91. },
  92. ],
  93. debounce((a) => {
  94. const position = positions.value?.find((item) => item.id === showId.value);
  95. if (position) {
  96. position.pose = sdk.getPose({ modelId: position.modelId, isFlyToTag: true });
  97. console.log("set Pose", position.pose);
  98. }
  99. }, 300)
  100. );
  101. let pop: () => void;
  102. const flyTaggingPosition = (position: TaggingPosition) => {
  103. pop && pop();
  104. const model = getFuseModel(position.modelId);
  105. if (!model || !getFuseModelShowVariable(model).value) {
  106. return;
  107. }
  108. pop = showTaggingPositionsStack.push(ref(new WeakSet([position])));
  109. flyTaggingPositionRaw(position);
  110. };
  111. onUnmounted(() => pop && pop());
  112. const deletePosition = (position: TaggingPosition) => {
  113. const index = taggingPositions.value.indexOf(position);
  114. if (~index) {
  115. taggingPositions.value.splice(index, 1);
  116. }
  117. };
  118. const applyGlobal = async (position: TaggingPosition, keys: string | string[]) => {
  119. if (!(await Dialog.confirm("确定要将此属性应用到所有位置?"))) return;
  120. keys = Array.isArray(keys) ? keys : [keys];
  121. for (const current of positions.value!) {
  122. let val: any = current;
  123. let newVal: any = position;
  124. for (let i = 0; i < keys.length; i++) {
  125. if (i === keys.length - 1) {
  126. val[keys[i]] = newVal[keys[i]];
  127. } else {
  128. val = val[keys[i]];
  129. newVal = newVal[keys[i]];
  130. }
  131. }
  132. }
  133. };
  134. let unKeepAdding = shallowRef<() => void>();
  135. const keepAdding = () => {
  136. unKeepAdding.value && unKeepAdding.value();
  137. sdk.startAddSth();
  138. const hide = Message.show({ msg: "请在模型上单击选择标签位置", type: "warning" });
  139. showId.value = void 0;
  140. const removeListener = clickListener(sdk.layout, async (pos) => {
  141. await nextTick();
  142. await asyncTimeout();
  143. const position = sdk.getPositionByScreen(pos);
  144. if (!position) {
  145. Message.error("当前位置无法添加");
  146. } else {
  147. const storePosition = createTaggingPosition({
  148. ...position,
  149. normal: position.localNormal,
  150. taggingId: tagging.value!.id,
  151. });
  152. taggingPositions.value.push(storePosition);
  153. showId.value = storePosition.id;
  154. nextTick(() => {
  155. getTaggingPosNode(storePosition)!.changeCanMove(true);
  156. });
  157. }
  158. });
  159. unKeepAdding.value = () => {
  160. hide();
  161. sdk.endAddSth();
  162. removeListener();
  163. unKeepAdding.value = void 0;
  164. };
  165. };
  166. keepAdding();
  167. </script>
  168. <style lang="scss" scoped>
  169. h3 {
  170. font-family: Microsoft YaHei, Microsoft YaHei;
  171. font-weight: bold;
  172. font-size: 16px;
  173. color: #999999;
  174. margin-bottom: 4px;
  175. }
  176. .pin-position {
  177. position: absolute;
  178. left: 50%;
  179. transform: translate(-50%);
  180. width: 64px;
  181. height: 64px;
  182. background: rgba(27, 27, 28, 0.8);
  183. border-radius: 50%;
  184. bottom: 20px;
  185. z-index: 9;
  186. display: flex;
  187. align-items: center;
  188. justify-content: center;
  189. }
  190. </style>
  191. <style lang="scss">
  192. .position-group .group-title {
  193. margin-bottom: 0;
  194. }
  195. </style>