Commit dbf9275699ce514bfb6fc4b01f5116fc49674c85

Authored by fengwotao
1 parent 7ad8ff6a

perf(externa/Composes): 修改摄像头

  1 +<template>
  2 + <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">
  3 + <video :id="`my-player${index}`" ref="videoRef" class="video-js my-video vjs-theme-city vjs-big-play-centered">
  4 + <source :src="sourceSrc" />
  5 + </video>
  6 + </div>
  7 +</template>
  8 +<script setup lang="ts">
  9 +import { onMounted, ref, onUnmounted, watch } from 'vue'
  10 +import videojs from 'video.js'
  11 +import type { VideoJsPlayerOptions } from 'video.js'
  12 +import 'video.js/dist/video-js.min.css'
  13 +
  14 +const props = defineProps({
  15 + sourceSrc: {
  16 + type: String
  17 + },
  18 + w: {
  19 + type: Number,
  20 + default: 300
  21 + },
  22 + h: {
  23 + type: Number,
  24 + default: 300
  25 + },
  26 + index: {
  27 + type: Number
  28 + }
  29 +})
  30 +
  31 +// video标签
  32 +const videoRef = ref<HTMLElement | null>(null)
  33 +
  34 +// video实例对象
  35 +let videoPlayer: videojs.Player | null = null
  36 +
  37 +//options配置
  38 +const options: VideoJsPlayerOptions = {
  39 + language: 'zh-CN', // 设置语言
  40 + controls: true, // 是否显示控制条
  41 + preload: 'auto', // 预加载
  42 + autoplay: true, // 是否自动播放
  43 + fluid: false, // 自适应宽高
  44 + src: props.sourceSrc, // 要嵌入的视频源的源 URL
  45 + muted: true,
  46 + userActions: {
  47 + hotkeys: true
  48 + }
  49 +}
  50 +
  51 +// 初始化videojs
  52 +const initVideo = () => {
  53 + if (videoRef.value) {
  54 + // 创建 video 实例
  55 + videoPlayer = videojs(videoRef.value, options)
  56 + }
  57 +}
  58 +
  59 +watch(
  60 + () => props.sourceSrc,
  61 + (newData: any) => {
  62 + // props.sourceSrc = newData
  63 + videoPlayer?.src(newData) as any
  64 + videoPlayer?.play()
  65 + },
  66 + {
  67 + immediate: true
  68 + }
  69 +)
  70 +
  71 +onMounted(() => {
  72 + initVideo()
  73 +})
  74 +
  75 +onUnmounted(() => {
  76 + handleVideoDispose()
  77 +})
  78 +
  79 +//播放
  80 +const handleVideoPlay = () => videoPlayer?.play()
  81 +
  82 +const handleVideoDispose = () => videoPlayer?.dispose() && videoPlayer?.pause()
  83 +//暂停
  84 +defineExpose({
  85 + handleVideoPlay,
  86 + handleVideoDispose
  87 +})
  88 +</script>
  89 +
  90 +<style lang="scss" scoped>
  91 +.go-content-box {
  92 + display: flex;
  93 + align-items: center;
  94 + justify-content: center;
  95 + .my-video {
  96 + width: 100% !important;
  97 + height: 100% !important;
  98 + position: relative;
  99 + }
  100 +}
  101 +</style>
... ...
... ... @@ -4,7 +4,36 @@ import { CameraConfig } from './index'
4 4 import cloneDeep from 'lodash/cloneDeep'
5 5
6 6 export const option = {
7   - dataset: ''
  7 + dataset: [
  8 + {
  9 + url: 'https://vcsplay.scjtonline.cn:8094/live/HD_664c01b9-4b67-11eb-bf78-3cd2e55e0a36.m3u8?auth_key=1681457689-0-0-a797d264f2889a388c52ff188fedf7dc'
  10 + },
  11 + {
  12 + url: 'https://vcsplay.scjtonline.cn:8196/live/HD_c53fd3cb-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457668-0-0-7ef56e21fddd9ffb9740cbe499a1824c'
  13 + },
  14 + {
  15 + url: 'https://vcsplay.scjtonline.cn:8199/live/HD_53713154-1371-489a-a929-015cca5569fc.m3u8?auth_key=1681441451-0-0-4f1ebdcf28a71b7631c0028c099923c9'
  16 + },
  17 + {
  18 + url: 'https://vcsplay.scjtonline.cn:8195/live/HD_c54034ca-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457640-0-0-3a53b856ac19c09273986e8281f3d727'
  19 + },
  20 + {
  21 + url: 'https://vcsplay.scjtonline.cn:8094/live/HD_664c01b9-4b67-11eb-bf78-3cd2e55e0a36.m3u8?auth_key=1681457689-0-0-a797d264f2889a388c52ff188fedf7dc'
  22 + },
  23 + {
  24 + url: 'https://vcsplay.scjtonline.cn:8196/live/HD_c53fd3cb-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457668-0-0-7ef56e21fddd9ffb9740cbe499a1824c'
  25 + },
  26 + {
  27 + url: 'https://vcsplay.scjtonline.cn:8199/live/HD_53713154-1371-489a-a929-015cca5569fc.m3u8?auth_key=1681441451-0-0-4f1ebdcf28a71b7631c0028c099923c9'
  28 + },
  29 + {
  30 + url: 'https://vcsplay.scjtonline.cn:8195/live/HD_c54034ca-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681457640-0-0-3a53b856ac19c09273986e8281f3d727'
  31 + }
  32 + ] as any,
  33 + // 自动播放的间隔(ms)
  34 + interval: 5000,
  35 + autoplay: true,
  36 + effect: 'slide'
8 37 }
9 38
10 39 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
1 1 <template>
2   - <CollapseItem name="配置" :expanded="true">
  2 + <CollapseItem name="播放器配置" :expanded="true">
3 3 <setting-item-box name="源地址" :alone="true">
  4 + <setting-item v-for="(item, index) in optionData.dataset" :key="index">
  5 + <n-input-group>
  6 + <n-input v-model:value="item.url" size="small" placeholder="请输入源地址"></n-input>
  7 + <n-button ghost @click="optionData.dataset.splice(index, 1)"> - </n-button>
  8 + </n-input-group>
  9 + </setting-item>
4 10 <setting-item>
5   - <n-input v-model:value="optionData.dataset" size="small"></n-input>
  11 + <n-button v-if="optionData.dataset.length < 5" size="small" @click="optionData.dataset.push({ url: '' })">
  12 + +
  13 + </n-button>
6 14 </setting-item>
7 15 </setting-item-box>
8 16 </CollapseItem>
... ...
1 1 <template>
2   - <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">
3   - <video id="my-player" ref="videoRef" class="video-js my-video vjs-theme-city vjs-big-play-centered">
4   - <source :src="dataset" />
5   - </video>
  2 + <div class="banner-box" ref="root">
  3 + <div class="wrapper">
  4 + <div v-for="(item, index) in option.dataset" :key="index + item" :class="item.className" :style="item.sty">
  5 + <CameraItem ref="cameraRef" :key="item + index" :sourceSrc="item.url" :w="w" :h="h" :index="index" />
  6 + </div>
  7 + </div>
  8 + <a href="javascript:;" class="left" @click="changeSlide('left')"></a>
  9 + <a href="javascript:;" class="right" @click="changeSlide('right')"></a>
6 10 </div>
7 11 </template>
8 12 <script setup lang="ts">
9   -import { PropType, onMounted, ref, watch, toRefs, onUnmounted } from 'vue'
  13 +import { PropType, watch, toRefs, shallowReactive, onMounted, ref } from 'vue'
10 14 import { CreateComponentType } from '@/packages/index.d'
11   -import videojs from 'video.js'
12   -import type { VideoJsPlayerOptions } from 'video.js'
13 15 import 'video.js/dist/video-js.min.css'
  16 +import { option as configOption } from './config'
  17 +import CameraItem from './cameraItem.vue'
14 18
15 19 const props = defineProps({
16 20 chartConfig: {
... ... @@ -21,66 +25,165 @@ const props = defineProps({
21 25
22 26 const { w, h } = toRefs(props.chartConfig.attr)
23 27
24   -const { dataset } = toRefs(props.chartConfig.option)
  28 +const option = shallowReactive({
  29 + dataset: configOption.dataset
  30 +})
25 31
26   -// video标签
27   -const videoRef = ref<HTMLElement | null>(null)
  32 +const cameraRef = ref<InstanceType<typeof CameraItem>>()
28 33
29   -// video实例对象
30   -let videoPlayer: videojs.Player | null = null
  34 +let initial = ref(0)
31 35
32   -//options配置
33   -const options: VideoJsPlayerOptions = {
34   - language: 'zh-CN', // 设置语言
35   - controls: true, // 是否显示控制条
36   - preload: 'auto', // 预加载
37   - autoplay: true, // 是否自动播放
38   - fluid: false, // 自适应宽高
39   - src: dataset?.value, // 要嵌入的视频源的源 URL
40   - muted:true,
41   - userActions: {
42   - hotkeys: true
43   - }
44   -}
  36 +let interval = ref(4000)
45 37
46   -// 初始化videojs
47   -const initVideo = () => {
48   - if (videoRef.value) {
49   - // 创建 video 实例
50   - videoPlayer = videojs(videoRef.value, options)
51   - }
  38 +const computedFunc = (initial: number, source: any) => {
  39 + if (initial < 0) initial = 0
  40 + let len = source.length,
  41 + temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,
  42 + temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,
  43 + temp3 = initial,
  44 + temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,
  45 + temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2
  46 + return source.map((item: any, index: number) => {
  47 + let transform = `translate(-50%, -50%) scale(0.7)`,
  48 + zIndex = 0,
  49 + className = 'slide'
  50 + switch (index) {
  51 + case temp3:
  52 + transform = `translate(-50%, -50%) scale(1)`
  53 + className = ['slide', 'activate'] as any
  54 + zIndex = 3
  55 + break
  56 + case temp1:
  57 + transform = `translate(-80%, -50%) scale(0.7)`
  58 + zIndex = 1
  59 + break
  60 + case temp5:
  61 + transform = `translate(100%, -50%) scale(0.7)`
  62 + zIndex = 1
  63 + break
  64 + case temp2:
  65 + transform = `translate(-100%, -50%) scale(0.85)`
  66 + zIndex = 2
  67 + break
  68 + case temp4:
  69 + transform = `translate(58%, -50%) scale(0.85)`
  70 + zIndex = 2
  71 + break
  72 + }
  73 + item.sty = {
  74 + transform,
  75 + zIndex
  76 + }
  77 + item.className = className
  78 + return item
  79 + })
52 80 }
53 81
54   -onMounted(() => {
55   - initVideo()
56   -})
57   -
58   -onUnmounted(() => {
59   - videoPlayer?.dispose()
60   -})
61   -
62 82 watch(
63 83 () => props.chartConfig.option.dataset,
64 84 newData => {
65   - props.chartConfig.option.dataset = newData
66   - videoPlayer?.src(newData)
67   - videoPlayer?.play()
  85 + option.dataset = newData
  86 + console.log(option.dataset)
68 87 },
69 88 {
70   - immediate: true
  89 + immediate: true,
  90 + deep: true
71 91 }
72 92 )
  93 +option.dataset = computedFunc(initial.value, option.dataset)
  94 +
  95 +watch(
  96 + () => initial.value,
  97 + newV => {
  98 + option.dataset = computedFunc(newV, option.dataset)
  99 + }
  100 +)
  101 +// 处理自动轮播
  102 +let timer: any = null
  103 +
  104 +const autoPlay = () => {
  105 + timer = setInterval(() => {
  106 + initial.value++
  107 + if (initial.value >= option.dataset.length) {
  108 + initial.value = 0
  109 + }
  110 + }, interval.value)
  111 +}
  112 +
  113 +// 鼠标移入移除效果
  114 +let root = ref(null)
  115 +
  116 +onMounted(() => {
  117 + clearInterval(timer)
  118 + autoPlay()
  119 + const box: any = root.value
  120 + box.onmouseenter = () => clearInterval(timer)
  121 + box.onmouseleave = () => autoPlay()
  122 +})
  123 +
  124 +// 点击左右按钮切换图片
  125 +function changeVideo(dir: string) {
  126 + if (dir === 'left') {
  127 + // cameraRef.value?.handleVideoPlay()
  128 + clearInterval(timer)
  129 + initial.value++
  130 + initial.value >= option.dataset.length ? (initial.value = 0) : false
  131 + return
  132 + }
  133 + // cameraRef.value?.handleVideoDispose()
  134 + initial.value--
  135 + initial.value < 0 ? (initial.value = option.dataset.length - 1) : false
  136 +}
  137 +
  138 +// 左右切换图片设置防抖效果
  139 +function changeSlide(dir: string) {
  140 + changeVideo(dir)
  141 +}
73 142 </script>
74 143
75 144 <style lang="scss" scoped>
76   -.go-content-box {
77   - display: flex;
78   - align-items: center;
79   - justify-content: center;
80   - .my-video {
81   - width: 100% !important;
82   - height: 100% !important;
  145 +.banner-box {
  146 + width: 100%;
  147 + height: 100%;
  148 + // position: absolute;
  149 + top: 50%;
  150 + left: 50%;
  151 + transform: translate(-50%, -50%);
  152 + .wrapper {
  153 + width: 100%;
  154 + height: 100%;
83 155 position: relative;
  156 + .slide {
  157 + width: 20%;
  158 + height: 100%;
  159 + position: absolute;
  160 + top: 50%;
  161 + left: 10%;
  162 + transform: translate(-50%, -50%);
  163 + transition: 0.5s;
  164 + box-shadow: 0 0 4px black;
  165 + }
  166 + }
  167 + .arrow {
  168 + position: absolute;
  169 + top: 50%;
  170 + transform: translateY(-50%);
  171 + z-index: 9;
  172 + width: 50px;
  173 + height: 50px;
  174 + background-size: contain;
  175 + background-color: white;
  176 + opacity: 0.5;
  177 + }
  178 + a.left {
  179 + @extend .arrow;
  180 + background-image: url(./left.svg);
  181 + left: 0px;
  182 + }
  183 + a.right {
  184 + @extend .arrow;
  185 + background-image: url(./right.svg);
  186 + right: 0px;
84 187 }
85 188 }
86 189 </style>
... ...
  1 +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill="none"><path d="M10.26 3.2a.75.75 0 0 1 .04 1.06L6.773 8l3.527 3.74a.75.75 0 1 1-1.1 1.02l-4-4.25a.75.75 0 0 1 0-1.02l4-4.25a.75.75 0 0 1 1.06-.04z" fill="currentColor"></path></g></svg>
\ No newline at end of file
... ...
  1 +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill="none"><path d="M5.74 3.2a.75.75 0 0 0-.04 1.06L9.227 8L5.7 11.74a.75.75 0 1 0 1.1 1.02l4-4.25a.75.75 0 0 0 0-1.02l-4-4.25a.75.75 0 0 0-1.06-.04z" fill="currentColor"></path></g></svg>
\ No newline at end of file
... ...