Commit 771ef12d8e8b1c7df786f768f4533d367223e9dd

Authored by xp.Huang
2 parents f7790b8f 283633a8

Merge branch 'ft' into 'main_dev'

pref: 修改摄像头和大标题

See merge request yunteng/thingskit-view!41
1 1 <template>
2 2 <div class="go-text-box">
3   - <n-grid :style="{'background-image': 'url('+option.configOption.bgSrc+')'}" class="go-n-grid" :x-gap="12" :y-gap="3"
4   - :cols="3" layout-shift-disabled>
  3 + <n-grid
  4 + :style="{ 'background-image': 'url(' + option.configOption.bgSrc + ')', height: h + 'px' }"
  5 + class="go-n-grid"
  6 + :x-gap="12"
  7 + :y-gap="3"
  8 + :cols="3"
  9 + layout-shift-disabled
  10 + >
5 11 <n-grid-item>
6 12 <!-- 占位-->
7 13 <div></div>
8 14 </n-grid-item>
9 15 <n-grid-item>
10 16 <span
11   - style="position:relative"
12   - :style="{ top:option.configOption.y+'px',marginLeft:option.configOption.x+'px',color: option.configOption.textColor, fontSize: option.configOption.fontSize + 'px' }">{{
13   - option.configOption.dataset
14   - }}</span>
  17 + style="position: relative"
  18 + :style="{
  19 + top: option.configOption.y + 'px',
  20 + marginLeft: option.configOption.x + 'px',
  21 + color: option.configOption.textColor,
  22 + fontSize: option.configOption.fontSize + 'px'
  23 + }"
  24 + >{{ option.configOption.dataset }}</span
  25 + >
15 26 </n-grid-item>
16 27 <n-grid-item>
17   - <span style="position:relative" v-if="option.configOption.showRight"
18   - :style="{ top:option.configOption.yT+'px',marginLeft:option.configOption.xT+'px',color: option.configOption.textRightSizeColor, fontSize: option.configOption.textRightFontSize + 'px' }">{{
19   - newData
20   - }}</span>
  28 + <span
  29 + style="position: relative"
  30 + v-if="option.configOption.showRight"
  31 + :style="{
  32 + top: option.configOption.yT + 'px',
  33 + marginLeft: option.configOption.xT + 'px',
  34 + color: option.configOption.textRightSizeColor,
  35 + fontSize: option.configOption.textRightFontSize + 'px'
  36 + }"
  37 + >{{ newData }}</span
  38 + >
21 39 </n-grid-item>
22 40 </n-grid>
23 41 </div>
24 42 </template>
25 43 <script setup lang="ts">
26   -import {PropType, toRefs, shallowReactive, watch, onMounted, onUnmounted, ref} from 'vue'
27   -import {CreateComponentType} from '@/packages/index.d'
28   -import {useChartDataFetch} from '@/hooks'
29   -import {useChartEditStore} from '@/store/modules/chartEditStore/chartEditStore'
30   -import {option as configOption} from './config'
  44 +import { PropType, toRefs, shallowReactive, watch, onMounted, onUnmounted, ref } from 'vue'
  45 +import { CreateComponentType } from '@/packages/index.d'
  46 +import { useChartDataFetch } from '@/hooks'
  47 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  48 +import { option as configOption } from './config'
31 49
32 50 const props = defineProps({
33 51 chartConfig: {
... ... @@ -47,42 +65,40 @@ let nowData = ref('08:00:00')
47 65 let newData = ref('2021-2-3 08:00:00')
48 66
49 67 let timer: any = null
  68 +const { w, h } = toRefs(props.chartConfig.attr)
50 69
51 70 //修改默认宽高
52   -props.chartConfig.attr.w=1920
53   -props.chartConfig.attr.h=180
54   -
  71 +props.chartConfig.attr.w = 1920
  72 +props.chartConfig.attr.h = 100
55 73
56 74 watch(
57   - () => props.chartConfig.option,
58   - (newData: any) => {
59   - option.configOption = newData
60   - },
61   - {
62   - immediate: true,
63   - deep: false
64   - }
  75 + () => props.chartConfig.option,
  76 + (newData: any) => {
  77 + option.configOption = newData
  78 + },
  79 + {
  80 + immediate: true,
  81 + deep: false
  82 + }
65 83 )
66 84
67 85 useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
68 86 option.configOption = newData
69 87 })
70 88
71   -
72 89 //TODO待封装 这里和原作者时间通用获取当前时间代码一样
73 90 onMounted(() => {
74   -//格式化当前时间
  91 + //格式化当前时间
75 92 timer = setInterval(() => {
76   - const
77   - weeks = {
78   - "0": '星期日',
79   - "1": '星期一',
80   - "2": '星期二',
81   - "3": '星期三',
82   - "4": '星期四',
83   - "5": '星期五',
84   - "6": '星期六',
85   - } as any
  93 + const weeks = {
  94 + '0': '星期日',
  95 + '1': '星期一',
  96 + '2': '星期二',
  97 + '3': '星期三',
  98 + '4': '星期四',
  99 + '5': '星期五',
  100 + '6': '星期六'
  101 + } as any
86 102 const datetime = new Date()
87 103 const year = datetime.getFullYear()
88 104 const month = datetime.getMonth() + 1 < 10 ? '0' + (datetime.getMonth() + 1) : datetime.getMonth() + 1
... ... @@ -90,7 +106,7 @@ onMounted(() => {
90 106 const hh = datetime.getHours() // 时
91 107 const mm = datetime.getMinutes() // 分
92 108 const ss = datetime.getSeconds() // 分
93   - let weekIndex = datetime.getDay();
  109 + let weekIndex = datetime.getDay()
94 110 let time = ''
95 111 if (hh < 10) time += '0'
96 112 time += hh + ':'
... ... @@ -106,14 +122,15 @@ onMounted(() => {
106 122 onUnmounted(() => {
107 123 clearInterval(timer)
108 124 })
109   -
110 125 </script>
111 126
112 127 <style lang="scss" scoped>
113 128 @include go('text-box') {
  129 + width: v-bind('w+"px"');
  130 + height: v-bind('h+"px"');
114 131 display: flex;
115   - align-items: center;
116   - justify-content: center;
  132 + align-items: start;
  133 + justify-content: start;
117 134 .n-gradient-text {
118 135 white-space: initial;
119 136 }
... ...
  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
... ...
... ... @@ -208,8 +208,16 @@ defineExpose({
208 208 :disabled="true" />
209 209
210 210 </SettingItemBox>
211   -
212   - <SettingItemBox v-if="requestContentTypeRef === RequestContentTypeEnum.WEB_SOCKET">
  211 + <!--
  212 + /**
  213 + * ft 修改
  214 + * 修改后的代码在注释之间,并标注好源代码和修改后代码,方便回溯
  215 + * 源代码 无
  216 + * 修改后代码 新增一句:item-right-style="{ gridTemplateColumns: '7fr 1fr' }"
  217 + * 优化普通和websocket表格长度不一样样式问题
  218 + */
  219 + -->
  220 + <SettingItemBox v-if="requestContentTypeRef === RequestContentTypeEnum.WEB_SOCKET" :item-right-style="{ gridTemplateColumns: '7fr 1fr' }">
213 221 <NCard v-if="requestParamsTypeRef === RequestParamsTypeEnum.PARAMS" class="dynamic-form">
214 222 <NScrollbar style="max-height: 400px; box-sizing: border-box;">
215 223 <DynamicForm ref="socketDynamicFormEl" :paramsItemList="getSelectedInterfaceParams" />
... ...