Commit 1dde260d661dcc541f867486276421e8129de3eb

Authored by fengwotao
1 parent 1f241dd5

feat(packages/external): 新增单个摄像头

... ... @@ -13,11 +13,6 @@
13 13 </n-button>
14 14 </setting-item>
15 15 </setting-item-box>
16   - <setting-item-box name="排布">
17   - <setting-item>
18   - <n-select v-model:value="optionData.displayMode" size="small" :options="displayModeOptions"></n-select>
19   - </setting-item>
20   - </setting-item-box>
21 16 </CollapseItem>
22 17 </template>
23 18
... ... @@ -32,20 +27,4 @@ defineProps({
32 27 required: true
33 28 }
34 29 })
35   -
36   -// 旋转方式
37   -const displayModeOptions = [
38   - {
39   - value: 'singleGrid',
40   - label: '默认'
41   - },
42   - {
43   - value: 'fourGrid',
44   - label: '四宫格'
45   - },
46   - {
47   - value: 'nineGrid',
48   - label: '九宫格'
49   - }
50   -]
51 30 </script>
... ...
... ... @@ -8,7 +8,7 @@ export const CameraConfig: ConfigType = {
8 8 key,
9 9 chartKey,
10 10 conKey,
11   - title: '摄像头',
  11 + title: '多个摄像头',
12 12 category: ChatCategoryEnum.MORE,
13 13 categoryName: ChatCategoryEnumName.MORE,
14 14 package: EPackagesCategoryEnum.COMPOSES,
... ...
  1 +<template>
  2 + <video
  3 + crossOrigin="anonymous"
  4 + :id="`my-player${index}`"
  5 + ref="videoRef"
  6 + class="video-js my-video vjs-theme-city vjs-big-play-centered"
  7 + >
  8 + <source :src="sourceSrc" />
  9 + </video>
  10 +</template>
  11 +<script setup lang="ts">
  12 +import { onMounted, ref, onUnmounted, watch } from 'vue'
  13 +import videojs from 'video.js'
  14 +import type { VideoJsPlayerOptions } from 'video.js'
  15 +import 'video.js/dist/video-js.min.css'
  16 +
  17 +const props = defineProps({
  18 + sourceSrc: {
  19 + type: String
  20 + },
  21 + name: {
  22 + type: String
  23 + },
  24 + avatar: {
  25 + type: String
  26 + },
  27 + index: {
  28 + type: Number
  29 + }
  30 +})
  31 +
  32 +// video标签
  33 +const videoRef = ref<HTMLElement | null>(null)
  34 +
  35 +// video实例对象
  36 +let videoPlayer: videojs.Player | null = null
  37 +
  38 +//options配置
  39 +const options: VideoJsPlayerOptions = {
  40 + language: 'zh-CN', // 设置语言
  41 + controls: true, // 是否显示控制条
  42 + preload: 'auto', // 预加载
  43 + autoplay: true, // 是否自动播放
  44 + fluid: false, // 自适应宽高
  45 + poster: props?.avatar || '',
  46 + src: props?.sourceSrc || '', // 要嵌入的视频源的源 URL
  47 + muted: true,
  48 + userActions: {
  49 + hotkeys: true
  50 + }
  51 +}
  52 +
  53 +// 初始化videojs
  54 +const initVideo = () => {
  55 + if (videoRef.value) {
  56 + // 创建 video 实例
  57 + videoPlayer = videojs(videoRef.value, options)
  58 + }
  59 +}
  60 +
  61 +watch(
  62 + () => props.sourceSrc,
  63 + (newData: any) => {
  64 + // props.sourceSrc = newData
  65 + videoPlayer?.src(newData) as any
  66 + videoPlayer?.play()
  67 + },
  68 + {
  69 + immediate: true
  70 + }
  71 +)
  72 +
  73 +onMounted(() => {
  74 + initVideo()
  75 +})
  76 +
  77 +onUnmounted(() => {
  78 + handleVideoDispose()
  79 +})
  80 +
  81 +//播放
  82 +const handleVideoPlay = () => videoPlayer?.play()
  83 +
  84 +const handleVideoDispose = () => videoPlayer?.dispose() && videoPlayer?.pause()
  85 +//暂停
  86 +defineExpose({
  87 + handleVideoPlay,
  88 + handleVideoDispose
  89 +})
  90 +</script>
  91 +
  92 +<style lang="scss" scoped>
  93 +.my-video {
  94 + width: 100%;
  95 + height: 100%;
  96 +}
  97 +</style>
... ...
  1 +import CameraItem from './CameraItem.vue'
  2 +
  3 +export { CameraItem }
... ...
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { CreateComponentType } from '@/packages/index.d'
  3 +import { SingleCameraConfig } from './index'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +
  6 +export const option = {
  7 + dataset: [
  8 + {
  9 + url: ''
  10 + }
  11 + ] as any,
  12 + // 自动播放的间隔(ms)
  13 + interval: 5000,
  14 + autoplay: true,
  15 + effect: 'slide',
  16 + displayMode: 'singleGrid'
  17 +}
  18 +
  19 +export default class Config extends PublicConfigClass implements CreateComponentType {
  20 + public key = SingleCameraConfig.key
  21 + public chartConfig = cloneDeep(SingleCameraConfig)
  22 + public option = cloneDeep(option)
  23 +}
... ...
  1 +<template>
  2 + <CollapseItem name="播放器配置" :expanded="true">
  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-input-group>
  8 + </setting-item>
  9 + </setting-item-box>
  10 + </CollapseItem>
  11 +</template>
  12 +
  13 +<script setup lang="ts">
  14 +import { PropType } from 'vue'
  15 +import { option } from './config'
  16 +import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  17 +
  18 +defineProps({
  19 + optionData: {
  20 + type: Object as PropType<typeof option>,
  21 + required: true
  22 + }
  23 +})
  24 +
  25 +</script>
... ...
  1 +import { ChartFrameEnum, ConfigType } from '@/packages/index.d'
  2 +import { EPackagesCategoryEnum } from '@/packages/components/external/types'
  3 +import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
  4 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  5 +
  6 +const { key, chartKey, conKey } = useWidgetKey('SingleCamera')
  7 +export const SingleCameraConfig: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '单个摄像头',
  12 + category: ChatCategoryEnum.MORE,
  13 + categoryName: ChatCategoryEnumName.MORE,
  14 + package: EPackagesCategoryEnum.COMPOSES,
  15 + chartFrame: ChartFrameEnum.NAIVE_UI,
  16 + image: 'camera.png'
  17 +}
... ...
  1 +<template>
  2 + <div class="banner-box" ref="root">
  3 + <n-grid x-gap="12" :y-gap="12" :cols="computedCols">
  4 + <n-gi v-for="(item, index) in option.dataset" :key="index + item">
  5 + <div class="camera-container">
  6 + <CameraItem
  7 + ref="cameraRef"
  8 + :name="item.name"
  9 + :avatar="item.avatar"
  10 + :key="item + index"
  11 + :sourceSrc="item.url"
  12 + :index="index"
  13 + />
  14 + </div>
  15 + </n-gi>
  16 + </n-grid>
  17 + </div>
  18 +</template>
  19 +<script setup lang="ts">
  20 +import { PropType, toRefs, watch, shallowReactive, ref, computed } from 'vue'
  21 +import { CreateComponentType } from '@/packages/index.d'
  22 +import 'video.js/dist/video-js.min.css'
  23 +import { option as configOption } from './config'
  24 +import { CameraItem } from './components'
  25 +
  26 +const props = defineProps({
  27 + chartConfig: {
  28 + type: Object as PropType<CreateComponentType>,
  29 + required: true
  30 + }
  31 +})
  32 +
  33 +const { h } = toRefs(props.chartConfig.attr)
  34 +
  35 +const responsiveComputeValue = ref(0)
  36 +
  37 +const option = shallowReactive({
  38 + dataset: configOption.dataset
  39 +})
  40 +
  41 +const computedCols = computed(() => {
  42 + if (option.dataset.length <= 1) return 1
  43 + if (option.dataset.length <= 4) return 2
  44 + return 3
  45 +})
  46 +
  47 +const cameraRef = ref<InstanceType<typeof CameraItem>>()
  48 +
  49 +const responsive = (value: number) => {
  50 + responsiveComputeValue.value = value
  51 + if (option.dataset.length <= 2) responsiveComputeValue.value = value
  52 + if (option.dataset.length > 2 && option.dataset.length <= 4) responsiveComputeValue.value = value / 2.03
  53 + if (option.dataset.length > 4 && option.dataset.length <= 9) responsiveComputeValue.value = value / 3.1
  54 +}
  55 +
  56 +watch(
  57 + () => props.chartConfig.option.dataset,
  58 + newData => {
  59 + option.dataset = newData
  60 + responsive(h.value)
  61 + },
  62 + {
  63 + immediate: true,
  64 + deep: true
  65 + }
  66 +)
  67 +
  68 +watch(
  69 + () => h.value,
  70 + newData => responsive(newData),
  71 + {
  72 + immediate: true
  73 + }
  74 +)
  75 +</script>
  76 +
  77 +<style lang="scss" scoped>
  78 +.banner-box {
  79 + .camera-container {
  80 + height: v-bind('`${responsiveComputeValue}px`');
  81 + }
  82 +}
  83 +</style>
... ...
... ... @@ -2,6 +2,7 @@ import { Title1Config } from './Title1/index'
2 2 import { Title2Config } from './Title2/index'
3 3 import { Title3Config } from './Title3/index'
4 4 import { CameraConfig } from './Camera/index'
  5 +import { SingleCameraConfig } from './SingleCamera/index'
5 6 import { ThreeDimensionalConfig } from './ThreeDimensional/index'
6 7
7   -export default [Title1Config, Title2Config, Title3Config, CameraConfig, ThreeDimensionalConfig]
  8 +export default [Title1Config, Title2Config, Title3Config, CameraConfig, SingleCameraConfig, ThreeDimensionalConfig]
... ...