sign.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <template>
  2. <div
  3. v-if="posStyle"
  4. class="hot-item pc"
  5. :style="posStyle"
  6. @mouseenter="isHover = true"
  7. @mouseleave="isHover = false"
  8. >
  9. <img :src="taggingStyle?.icon" @click="iconClickHandler" />
  10. <div @click.stop>
  11. <UIBubble
  12. class="hot-bubble pc"
  13. :show="showContent"
  14. type="left"
  15. level="center"
  16. >
  17. <h2>{{ tagging.title }} </h2>
  18. <div class="content">
  19. <p><span>特征描述:</span>{{ tagging.desc }}</p>
  20. <p><span>遗留部位:</span>{{ tagging.part }}</p>
  21. <p><span>提取方法:</span>{{ tagging.method }}</p>
  22. <p><span>提取人:</span>{{ tagging.principal }}</p>
  23. </div>
  24. <Images
  25. :tagging="tagging"
  26. :in-full="true"
  27. @pull="index => (pullIndex = index)"
  28. />
  29. </UIBubble>
  30. <Preview
  31. @close="pullIndex = -1"
  32. :type="MediaType.img"
  33. :url="getFileUrl(tagging.images[pullIndex])"
  34. v-if="!!~pullIndex"
  35. />
  36. </div>
  37. </div>
  38. </template>
  39. <script lang="ts" setup>
  40. import { computed, ref, watchEffect } from 'vue'
  41. import UIBubble from 'bill/components/bubble/index.vue'
  42. import Images from '@/views/tagging/images.vue'
  43. import Preview, { MediaType } from '../static-preview/index.vue'
  44. import { Tagging, getTaggingStyle } from '@/store';
  45. import { getFileUrl } from '@/utils'
  46. import { sdk } from '@/sdk'
  47. import { custom, showTaggingPositionsStack } from '@/env'
  48. export type SignProps = { tagging: Tagging, scenePos: Tagging['positions'][number], show?: boolean }
  49. const props = defineProps<SignProps>()
  50. const posStyle = ref<null | { left: string, top: string}>(null)
  51. const updatePosStyle = () => {
  52. const screenPos = sdk.getScreenByPosition(props.scenePos.localPos, props.scenePos.modelId)
  53. if (!screenPos) {
  54. posStyle.value = null
  55. } else {
  56. posStyle.value = {
  57. left: screenPos.pos.x + 'px',
  58. top: screenPos.pos.y + 'px',
  59. }
  60. }
  61. }
  62. watchEffect(updatePosStyle)
  63. const showContent = computed(() => {
  64. return !~pullIndex.value
  65. && (
  66. isHover.value || show.value
  67. || custom.showTaggingPositions.has(props.scenePos)
  68. )
  69. })
  70. sdk.sceneBus.on('cameraChange', updatePosStyle)
  71. const taggingStyle = getTaggingStyle(props.tagging.styleId)
  72. const pullIndex = ref(-1)
  73. const isHover = ref(false)
  74. const show = ref(false)
  75. const iconClickHandler = () => {
  76. show.value = !show.value
  77. }
  78. </script>
  79. <style lang="scss" scoped>
  80. .hot-item {
  81. pointer-events: all;
  82. position: absolute;
  83. cursor: pointer;
  84. > img {
  85. width: 32px;
  86. height: 32px;
  87. }
  88. .hot-bubble {
  89. cursor: initial;
  90. &.pc {
  91. width: 400px;
  92. }
  93. &:not(.pc) {
  94. width: 80vw;
  95. --bottom-left: 40vw;
  96. }
  97. h2 {
  98. font-size: 20px;
  99. margin-bottom: 10px;
  100. color: #FFFFFF;
  101. position: relative;
  102. }
  103. .content {
  104. font-size: 14px;
  105. font-family: MicrosoftYaHei;
  106. color: #999999;
  107. line-height: 1.35em;
  108. margin-bottom: 20px;
  109. word-break: break-all;
  110. p {
  111. margin-bottom: 10px;
  112. }
  113. }
  114. }
  115. &.active,
  116. &:hover {
  117. z-index: 3;
  118. }
  119. }
  120. </style>