index.vue 4.55 KB
<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, toRaw, unref } from 'vue'
import 'video.js/dist/video-js.css'

import type { VideoJsPlayerOptions } from 'video.js'
import { BasicVideoPlay } from './component/index.ts'
import { VideoPlayerType, getVideoTypeByUrl, isRtspProtocol, useFingerprint } from './component/config'

import { getJwtToken, getShareJwtToken } from '@/utils/auth'
import { isLightboxMode, isShareMode } from '@/utils/env'
import type { CreateComponentType } from '@/core/Library/types'
import { closeFlvPlay, getFlvPlayUrl, getStreamingPlayUrl, getVideoControlStart } from '@/api/video'
import { useContentDataStore } from '@/store/modules/contentData'
import { VideoAccessModeEnum } from '@/enums/videoEnum'

const props = defineProps<{
  config: CreateComponentType

}>()

// 获取节点数据
const contentDataStore = useContentDataStore()
const { getResult } = useFingerprint()

const getOptions = computed<VideoJsPlayerOptions>(() => {
  const { config } = props || {}
  const { cellBounds } = config || {}
  const { height, width } = cellBounds as any
  return { height, width }
})

// 存储视频数据
const videoConfig = computed(() => {
  return contentDataStore?.contentData.filter((item) => {
    return props.config.cellInfo?.id === item.id
  })
})

// const loading = ref<boolean>(false)
const exampleVideoPlay = 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm'

const basicVideoPlayEl = ref<Nullable<InstanceType<typeof BasicVideoPlay>>>(null)
const withToken = ref(false)
const playSource = ref<Record<'src' | 'type', string>>(
  {} as unknown as Record<'src' | 'type', string>,
)

// 数据绑定获取的url
const handleGetVideoPlay = async () => {
  const { dataSourceJson } = unref(videoConfig)[0] || {}
  const { videoOption } = dataSourceJson || {}
  const { id, accessMode, videoUrl, deviceId, channelId } = videoOption || {}
  let type = getVideoTypeByUrl(videoUrl!)
  let playUrl = videoUrl

  // 判断是否是流媒体播放
  if (accessMode === VideoAccessModeEnum.Streaming && id) {
    const { data: { url } = { url: '' } } = await getStreamingPlayUrl(id!)
    playUrl = url
    playUrl && (type = getVideoTypeByUrl(playUrl!))
  }
  else if (accessMode === VideoAccessModeEnum.GBT28181 && deviceId && channelId) {
    const {
      data: { flv },
    } = await getVideoControlStart({ channelId, deviceId })

    playUrl = flv
    type = VideoPlayerType.flv
  }

  // 判断是否是rtsp播放
  if (isRtspProtocol(videoUrl!)) {
    const result = await getResult()
    const { visitorId } = result
    playUrl = getFlvPlayUrl(playUrl!, visitorId)
    withToken.value = true
  }

  playSource.value = {
    src: playUrl!,
    type,
  }

  const instance = unref(basicVideoPlayEl)?.customInit((options) => {
    if (unref(withToken)) {
      (options as any).flvjs.config.headers = {
        'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
      }
    }
    return {
      ...options,
      sources: [toRaw(unref(playSource))],
    } as VideoJsPlayerOptions
  })

  instance?.play()
}

// 默认播放
const handleSelectPreview = () => {
  // loading.value = false
  const instance = unref(basicVideoPlayEl)?.customInit((options) => {
    withToken.value = true
    if (unref(withToken)) {
      (options as any).flvjs.config.headers = {
        'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
      }
    }
    return {
      ...options,
      sources: [{ type: getVideoTypeByUrl(exampleVideoPlay), src: exampleVideoPlay }],
    } as VideoJsPlayerOptions
  })

  instance?.play()
}

onMounted(async () => {
  await nextTick()
  isLightboxMode() || isShareMode()
    ? handleGetVideoPlay()
    : handleSelectPreview()
})

onUnmounted(async () => {
  const { visitorId } = await getResult()
  const { dataSourceJson } = unref(videoConfig)[0] || {}
  const { videoOption } = dataSourceJson || {}
  const { videoUrl } = videoOption || {}
  isRtspProtocol(videoUrl!) && closeFlvPlay(videoUrl!, visitorId)
  await nextTick()
  unref(basicVideoPlayEl)?.getInstance()?.dispose()
})
</script>

<template>
  <div class="w-full h-full flex justify-center items-center">
    <!-- <Spin :spinning="loading" wrapper-class-name="video-spin" class="w-full h-full"> -->
    <BasicVideoPlay
      ref="basicVideoPlayEl" :options="getOptions" :with-token="withToken"
      :immediate-init-on-mounted="false"
    />
    <!-- </Spin> -->
  </div>
</template>

<style lang="less" scoped>
.video-spin {
  @apply w-full h-full;

  :deep(.ant-spin-container) {
    @apply w-full h-full;
  }
}
</style>