Commit 4458cd983103fc0648cd3ce99ea90397da61b875

Authored by fengtao
Committed by xp.Huang
1 parent db42c0a2

fix: 单个视频切换视频源,切换后未播放为新的视频源

1 1 <template>
2   - <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">
  2 + <div class="go-content-box" :style="{ width: baseSize?.w + 'px', height: baseSize?.h + 'px' }">
3 3 <video
4 4 crossOrigin="anonymous"
5 5 :id="`my-player`"
... ... @@ -9,7 +9,7 @@
9 9 </div>
10 10 </template>
11 11 <script setup lang="ts">
12   -import { onMounted, ref, onUnmounted, watch, unref } from 'vue'
  12 +import { onMounted, ref, onUnmounted, watch, unref, PropType } from 'vue'
13 13 import videojs from 'video.js'
14 14 import 'videojs-flvjs-es6'
15 15 import type { VideoJsPlayerOptions } from 'video.js'
... ... @@ -19,6 +19,7 @@ import { isShareMode } from '@/views/share/hook'
19 19 import { getOpenFlvPlayUrl, closeFlvPlay } from '@/api/external/flvPlay'
20 20 import { useFingerprint } from '@/utils/external/useFingerprint'
21 21 import { GetResult } from '@fingerprintjs/fingerprintjs'
  22 +import { VideoPlayerTypeEnum } from '../config'
22 23
23 24 const props = defineProps({
24 25 sourceSrc: {
... ... @@ -33,23 +34,11 @@ const props = defineProps({
33 34 avatar: {
34 35 type: String
35 36 },
36   - w: {
37   - type: Number,
38   - default: 300
39   - },
40   - h: {
41   - type: Number,
42   - default: 300
  37 + baseSize: {
  38 + type: Object as PropType<{ w: number; h: number }>
43 39 }
44 40 })
45 41
46   -enum VideoPlayerType {
47   - m3u8 = 'application/x-mpegURL',
48   - mp4 = 'video/mp4',
49   - webm = 'video/webm',
50   - flv = 'video/x-flv'
51   -}
52   -
53 42 const isRtspProtocol = (url: string) => {
54 43 const reg = /^rtsp:\/\//g
55 44 return reg.test(url)
... ... @@ -58,15 +47,15 @@ const isRtspProtocol = (url: string) => {
58 47 const getVideoTypeByUrl = (url = '') => {
59 48 try {
60 49 const { protocol, pathname } = new URL(url)
61   - if (protocol.startsWith('rtsp:')) return VideoPlayerType.flv
  50 + if (protocol.startsWith('rtsp:')) return VideoPlayerTypeEnum.flv
62 51 const reg = /[^.]\w*$/
63 52 const mathValue = pathname.match(reg) || []
64   - const ext = (mathValue[0] as keyof typeof VideoPlayerType) || 'webm'
65   - const type = VideoPlayerType[ext]
66   - return type ? type : VideoPlayerType.webm
  53 + const ext = (mathValue[0] as keyof typeof VideoPlayerTypeEnum) || 'webm'
  54 + const type = VideoPlayerTypeEnum[ext]
  55 + return type ? type : VideoPlayerTypeEnum.webm
67 56 } catch (error) {
68 57 console.error(error)
69   - return VideoPlayerType.webm
  58 + return VideoPlayerTypeEnum.webm
70 59 }
71 60 }
72 61
... ... @@ -82,11 +71,9 @@ const fingerprintResult = ref<Nullable<GetResult>>(null)
82 71 const options: VideoJsPlayerOptions & Recordable = {
83 72 language: 'zh-CN', // 设置语言
84 73 controls: true, // 是否显示控制条
85   - // preload: 'auto', // 预加载
86 74 autoplay: props.autoPlay ? true : false, // 是否自动播放
87 75 fluid: false, // 自适应宽高
88 76 poster: props?.avatar || '',
89   - // src: getSource() || '', // 要嵌入的视频源的源 URL
90 77 sources: [],
91 78 muted: props.autoPlay ? true : false,
92 79 userActions: {
... ... @@ -107,6 +94,7 @@ const options: VideoJsPlayerOptions & Recordable = {
107 94 }
108 95
109 96 const { getResult } = useFingerprint()
  97 +
110 98 async function getSource() {
111 99 fingerprintResult.value = await getResult()
112 100 let src = props.sourceSrc || ''
... ... @@ -144,11 +132,11 @@ const initVideo = async () => {
144 132
145 133 watch(
146 134 () => props.sourceSrc,
147   - async (newData: any) => {
  135 + async () => {
  136 + videoPlayer?.src('')
148 137 const result = await getSource()
149   - // props.sourceSrc = newData
150   - if(props.autoPlay){
151   - videoPlayer?.src(result) as any
  138 + if (props.autoPlay) {
  139 + videoPlayer?.src(result)
152 140 videoPlayer?.play()
153 141 }
154 142 },
... ... @@ -157,6 +145,20 @@ watch(
157 145 }
158 146 )
159 147
  148 +watch(
  149 + () => props.autoPlay,
  150 + async (newData: boolean) => {
  151 + if (newData) {
  152 + handleVideoPlay()
  153 + } else {
  154 + videoPlayer?.pause()
  155 + }
  156 + },
  157 + {
  158 + immediate: true
  159 + }
  160 +)
  161 +
160 162 onMounted(() => {
161 163 initVideo()
162 164 })
... ... @@ -171,8 +173,8 @@ onUnmounted(() => {
171 173 //播放
172 174 const handleVideoPlay = () => videoPlayer?.play()
173 175
  176 +//暂停和销毁
174 177 const handleVideoDispose = () => videoPlayer?.dispose() && videoPlayer?.pause()
175   -//暂停
176 178 defineExpose({
177 179 handleVideoPlay,
178 180 handleVideoDispose
... ...
... ... @@ -8,10 +8,30 @@ export enum sourceTypeEnum {
8 8 PLATFORM = 'platform'
9 9 }
10 10
  11 +export enum VideoPlayerTypeEnum {
  12 + m3u8 = 'application/x-mpegURL',
  13 + mp4 = 'video/mp4',
  14 + webm = 'video/webm',
  15 + flv = 'video/x-flv'
  16 +}
  17 +
  18 +export interface videoListInterface {
  19 + name: string
  20 + accessMode: number
  21 + id: string
  22 + videoUrl: string
  23 + label: string
  24 + value: string
  25 +}
  26 +
  27 +export enum AccessMode {
  28 + ManuallyEnter = 0,
  29 + Streaming = 1
  30 +}
  31 +
11 32 export const option = {
12   - url:'',
13 33 dataset: '',
14   - autoplay: false,
  34 + autoplay: true,
15 35 poster: '',
16 36 sourceType: 'custom',
17 37 organization: ''
... ...
... ... @@ -9,7 +9,7 @@
9 9 <setting-item>
10 10 <n-radio-group @update:value="handleChecked" v-model:value="optionData.sourceType" name="radiogroup">
11 11 <n-space>
12   - <n-radio v-for="(item, index) in sourceTypes" :key="item.value" :value="item.value">
  12 + <n-radio v-for="(item, index) in sourceTypes" :key="item.value + index" :value="item.value">
13 13 {{ item.label }}
14 14 </n-radio>
15 15 </n-space>
... ... @@ -40,7 +40,7 @@
40 40 <setting-item>
41 41 <n-select
42 42 @update:value="handleSelect"
43   - v-model:value="optionData.dataset"
  43 + v-model:value="url"
44 44 :options="videoOptions"
45 45 placeholder="请选择视频地址"
46 46 />
... ... @@ -56,21 +56,12 @@
56 56
57 57 <script setup lang="ts">
58 58 import { PropType, ref, onMounted } from 'vue'
59   -import { option, sourceTypeEnum } from './config'
  59 +import { AccessMode, option, sourceTypeEnum, videoListInterface } from './config'
60 60 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
61 61 import { NTreeSelect } from 'naive-ui'
62 62 import { getOrganizationList, getVideoList, getVideoUrl } from '@/api/external/common/index'
63 63 import { TKUpload } from '@/components/external/Common/TKUpload'
64 64
65   -interface videoListIF {
66   - name: string
67   - accessMode: number
68   - id: string
69   - videoUrl: string
70   - label: string
71   - value: string
72   -}
73   -
74 65 const props = defineProps({
75 66 optionData: {
76 67 type: Object as PropType<typeof option>,
... ... @@ -91,7 +82,9 @@ const sourceTypes = [
91 82
92 83 const originationOption = ref([])
93 84
94   -const videoOptions = ref<videoListIF[]>([])
  85 +const url = ref('')
  86 +
  87 +const videoOptions = ref<videoListInterface[]>([])
95 88
96 89 const getOriginationList = async () => {
97 90 const res = await getOrganizationList()
... ... @@ -106,9 +99,9 @@ const handleUpdateTreeValue = (value: string) => {
106 99 const getVideoLists = async (organizationId: string) => {
107 100 const res = await getVideoList({ organizationId })
108 101 if (!res) return
109   - videoOptions.value = res?.data?.map((item: videoListIF) => ({
  102 + videoOptions.value = res?.data?.map((item: videoListInterface) => ({
110 103 label: item.name,
111   - value: item.accessMode === 1 ? item.id : item.videoUrl,
  104 + value: item.accessMode === AccessMode.Streaming ? item.id : item.videoUrl,
112 105 id: item.id,
113 106 accessMode: item.accessMode
114 107 }))
... ... @@ -118,7 +111,7 @@ const getVideoUrlById = async (id: string) => {
118 111 const res = await getVideoUrl(id)
119 112 if (!res) return
120 113 const { url } = res.data
121   - props.optionData.url = url
  114 + props.optionData.dataset = url
122 115 }
123 116
124 117 const handleChecked = (value: string) => {
... ... @@ -128,13 +121,13 @@ const handleChecked = (value: string) => {
128 121 }
129 122 }
130 123
131   -const handleSelect = (_: string, e: videoListIF) => {
132   - const { accessMode, id } = e
  124 +const handleSelect = (_: string, e: videoListInterface) => {
  125 + const { accessMode, id, value } = e
133 126 //1表示,需要从服务端调取接口换取播放的地址,0则不需要
134   - if (accessMode === 1) {
  127 + if (accessMode === AccessMode.Streaming) {
135 128 getVideoUrlById(id)
136 129 } else {
137   - props.optionData.url = ''
  130 + props.optionData.dataset = value as string
138 131 }
139 132 }
140 133
... ...
1 1 <template>
2 2 <div>
3   - <VideoPlay :w="w" :h="h" :sourceSrc="option.dataset" :autoPlay="option.autoplay" :avatar="option.poster" />
  3 + <VideoPlay :baseSize="{ w, h }" :sourceSrc="option.dataset" :autoPlay="option.autoplay" :avatar="option.poster" />
4 4 </div>
5 5 </template>
6 6 <script setup lang="ts">
... ... @@ -18,22 +18,18 @@ const props = defineProps({
18 18
19 19 const { w, h } = toRefs(props.chartConfig.attr)
20 20
21   -const { autoplay, dataset, poster, url } = toRefs(props.chartConfig.option)
  21 +const { autoplay, dataset, poster } = toRefs(props.chartConfig.option as typeof configOption)
22 22
23 23 const option = shallowReactive({
24 24 dataset: configOption.dataset,
25 25 poster: configOption.poster,
26   - autoplay:configOption.autoplay
  26 + autoplay: configOption.autoplay
27 27 })
28 28
29 29 watch(
30 30 () => dataset?.value,
31 31 (newData: string) => {
32   - if (url?.value) {
33   - option.dataset = url?.value
34   - } else {
35   - option.dataset = newData
36   - }
  32 + option.dataset = newData
37 33 },
38 34 {
39 35 immediate: true
... ... @@ -41,19 +37,10 @@ watch(
41 37 )
42 38
43 39 watch(
44   - () => poster?.value,
45   - (newData: string) => {
46   - option.poster = newData
47   - },
48   - {
49   - immediate: true
50   - }
51   -)
52   -
53   -watch(
54   - () => autoplay?.value,
55   - (newData:boolean) => {
56   - option.autoplay = newData
  40 + () => [poster.value, autoplay.value],
  41 + newData => {
  42 + option.poster = newData.at(-2) as string
  43 + option.autoplay = newData.at(-1) as boolean
57 44 },
58 45 {
59 46 immediate: true
... ...