index.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <template>
  2. <div class="video-box w-100%">
  3. <TopTools />
  4. <div class="video-box-wrapper mt-10px relative bg-#00000080">
  5. <UseFullscreen v-slot="{ toggle, isFullscreen }">
  6. <div class="relative w-full h-full flex">
  7. <vue-photo-zoom-pro
  8. ref="zoomRef"
  9. class="w-full h-full"
  10. :scale="3"
  11. :width="200"
  12. :disabled-event="isZoom"
  13. >
  14. <div class="h-full flex items-center">
  15. <pub-video-new
  16. class="aspect-ratio-video"
  17. @click="isShow = false"
  18. @click.right.prevent="rightClickFn"
  19. />
  20. </div>
  21. <template v-slot:zoomer>
  22. <pub-video-new newClass="zoom-video" class="h-full" :key="resetKey" />
  23. </template>
  24. </vue-photo-zoom-pro>
  25. <div class="flex items-center z-99 absolute right-8px top-8px">
  26. <ul class="flex justify-around items-center mr-2">
  27. <li
  28. v-for="item in listComputed"
  29. class="mr-3 last:mr-0"
  30. :key="item.iCom"
  31. v-auth="item.auth"
  32. @click.stop="toolsHandler(item.type)"
  33. >
  34. <div
  35. :class="[item.iCom, 'cursor-pointer']"
  36. :style="{ width: item.w + 'px', height: item.h + 'px', color: item.color }"
  37. >
  38. </div>
  39. <!-- <Icon
  40. v-else
  41. :class="[item.class]"
  42. :icon="item.iCom"
  43. :color="item.color"
  44. :width="item.w"
  45. :height="item.h"
  46. /> -->
  47. </li>
  48. </ul>
  49. <span
  50. class="size-28px mr-2 color-#8ac5ff cursor-pointer i-ph:magnifying-glass-plus"
  51. @click="magnifying(!magnifyingFlag)"
  52. ></span>
  53. <!-- 全屏按钮 -->
  54. <div v-auth="['mrfullScreenBtn']">
  55. <span
  56. v-if="isFullscreen"
  57. class="block size-28px color-#8ac5ff cursor-pointer i-icon-park-outline:off-screen"
  58. @click="toggle"
  59. ></span>
  60. <span
  61. v-else
  62. class="block size-28px color-#8ac5ff cursor-pointer i-iconamoon:screen-full"
  63. @click="toggle"
  64. ></span>
  65. </div>
  66. </div>
  67. <div
  68. v-if="loading"
  69. class="absolute top-50% left-50% transform-translate--50% flex justify-center items-center"
  70. >
  71. <NSpin />
  72. </div>
  73. </div>
  74. </UseFullscreen>
  75. <TagBox
  76. v-auth="['mrpanoramicTagShow']"
  77. v-for="(tag, i) in tagList"
  78. :key="i"
  79. :index="i"
  80. :tag="tag"
  81. ></TagBox>
  82. <RightClick v-auth="['mrtagCreationBtn']" v-model="isShow" :x="xy.x" :y="xy.y" />
  83. </div>
  84. </div>
  85. </template>
  86. <script setup>
  87. import { useModal, NSpin } from 'naive-ui'
  88. // import useWorker from '@/assets/js/video-lib/omnimatrix-video-player'
  89. // import { useWindowSize, watchDebounced } from '@vueuse/core'
  90. import { omatVideoPlayer } from '@/assets/js/video-lib/flv/omatVideoPlayer'
  91. import { useOutsideSystemStore } from '@/stores/modules/system.js'
  92. import { useOutsideTagStore } from '@/stores/modules/tag.js'
  93. import TagBox from './components/tagBox.vue'
  94. import RemotePlayback from './RemotePlayback/RemotePlayback.vue'
  95. import { UseFullscreen } from '@vueuse/components'
  96. import { $mitt, uuid } from '@/utils'
  97. import RightClick from './components/rightClick.vue'
  98. import TopTools from './components/topTools.vue'
  99. import VuePhotoZoomPro from 'vue-photo-zoom-pro'
  100. import 'vue-photo-zoom-pro/dist/style/vue-photo-zoom-pro.css'
  101. const props = defineProps({
  102. id: Number,
  103. RtspMain: String
  104. })
  105. const playbackModal = useModal()
  106. const useSystem = useOutsideSystemStore()
  107. const useTag = useOutsideTagStore()
  108. const loading = ref(true)
  109. let playerObj = null
  110. let magnifyingWorkerObj = null
  111. const videoList = computed(() => useSystem.videoList)
  112. const tagList = ref([])
  113. let tagListClone = []
  114. const init = async () => {
  115. loading.value = true
  116. const { url } = await useSystem.getStream({ device_id: props.RtspMain })
  117. useSystem.videoUrl = url
  118. console.log('url', url)
  119. try {
  120. playerObj = omatVideoPlayer(
  121. '.pub-video',
  122. url,
  123. () => {
  124. loading.value = false
  125. setTimeout(() => {
  126. useSystem.setRatio()
  127. useTag.getGroupTag()
  128. }, 50)
  129. },
  130. {
  131. enableZoom: false,
  132. enableDrag: false
  133. }
  134. )
  135. } catch (error) {
  136. console.log(error)
  137. }
  138. }
  139. const xy = ref({ x: 0, y: 0 })
  140. const rightClickFn = (event) => {
  141. isShow.value = true
  142. xy.value.x = event.offsetX
  143. xy.value.y = event.offsetY
  144. }
  145. const isShow = ref(false)
  146. // watchDebounced([width, height], useSystem.setRatio, { debounce: 500, maxWait: 1000 })
  147. // watch(
  148. // () => useSystem.ratio,
  149. // () => {
  150. // const [t, tc] = useTag.initTagList()
  151. // tagList.value = t
  152. // tagListClone = tc
  153. // }
  154. // )
  155. const isZoom = ref(true)
  156. const zoomRef = ref(null)
  157. const resetKey = ref(uuid())
  158. const magnifyingFlag = ref(false)
  159. const magnifying = (flag) => {
  160. zoomRef.value?.mouseLeave()
  161. magnifyingFlag.value = flag
  162. if (flag) {
  163. if (magnifyingWorkerObj) return
  164. // const url = videoList.value.pano_view.replace('{14}', useSystem.deviceInfo.id)
  165. magnifyingWorkerObj = omatVideoPlayer('.zoom-video', useSystem.videoUrl, () => {
  166. isZoom.value = false
  167. zoomRef.value.mouseEnter()
  168. })
  169. } else {
  170. isZoom.value = true
  171. zoomRef.value.mouseLeave()
  172. magnifyingWorkerObj?.destroyed()
  173. resetKey.value = uuid()
  174. magnifyingWorkerObj = null
  175. }
  176. }
  177. useTag.$subscribe(() => {
  178. const [t, tc] = useTag.initTagList()
  179. tagList.value = t
  180. tagListClone = tc
  181. })
  182. const keyupHedler = (e) => {
  183. if (e.code === 'Escape') {
  184. if (magnifyingFlag.value) {
  185. magnifying(false)
  186. }
  187. }
  188. }
  189. const listComputed = computed(() => {
  190. return tools.value.map((item) => {
  191. if (item.type === 'lx') {
  192. if (state.value) {
  193. item.iCom = 'i-fad:armrecording showhide-anim'
  194. item.color = 'red'
  195. } else {
  196. item.iCom = 'i-gala-video'
  197. item.color = '#8ac5ff'
  198. item.class = ''
  199. }
  200. }
  201. return item
  202. })
  203. })
  204. const tools = ref([
  205. {
  206. iCom: 'i-fluent-mdl2-playback-rate-1x',
  207. label: '远程回放',
  208. color: '#8ac5ff',
  209. type: 'hf',
  210. w: 25,
  211. h: 25,
  212. auth: ['mrpanoramicPlaybackBtn']
  213. },
  214. {
  215. iCom: 'i-iconoir:screenshot',
  216. label: '截图',
  217. color: '#8ac5ff',
  218. type: 'jt',
  219. w: 25,
  220. h: 25,
  221. auth: ['mrscreenshotBtn']
  222. },
  223. {
  224. iCom: 'i-gala-video',
  225. label: '录像',
  226. type: 'lx',
  227. color: '#8ac5ff',
  228. class: '',
  229. w: 30,
  230. h: 30,
  231. auth: ['mrrecordingBtn']
  232. }
  233. ])
  234. const state = ref(false)
  235. const toolsHandler = (type) => {
  236. switch (type) {
  237. case 'lx':
  238. // switchState()
  239. state.value = !state.value
  240. playerObj.recording(state.value)
  241. break
  242. case 'jt':
  243. playerObj.screenshot()
  244. break
  245. case 'hf':
  246. {
  247. const m = playbackModal.create({
  248. title: '全景回放',
  249. preset: 'card',
  250. maskClosable: false,
  251. autoFocus: false,
  252. style: {
  253. width: '60%',
  254. marginTop: '10%'
  255. },
  256. content: () => h(RemotePlayback, { device_id: props.RtspMain })
  257. })
  258. }
  259. break
  260. }
  261. }
  262. onMounted(() => {
  263. init()
  264. document.body.addEventListener('keyup', keyupHedler)
  265. })
  266. onUnmounted(() => {
  267. playerObj?.destroyed()
  268. keyupHedler({ code: 'Escape' })
  269. document.body.removeEventListener('keyup', keyupHedler)
  270. })
  271. </script>