Commit d8eba72c58f003e6e8824396724e134b2ac316cb

Authored by fengwotao
1 parent 78e283b6

feat(src/packages): 组合里单个摄像头新增封面上传

1 1 <template>
2 2 <div class="videoPlay">
3   - <video crossOrigin="anonymous" ref="videoRef" class="video-js vjs-default-skin vjs-big-play-centered" controls>
  3 + <video
  4 + style="object-fit: cover"
  5 + :poster="poster"
  6 + crossOrigin="anonymous"
  7 + ref="videoRef"
  8 + class="video-js vjs-default-skin vjs-big-play-centered"
  9 + controls
  10 + >
4 11 <source :src="path" />
5 12 </video>
6 13 </div>
7 14 </template>
8 15 <script lang="ts" setup>
9   -import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
  16 +import { nextTick, onBeforeUnmount, onMounted, ref, watch, toRefs } from 'vue'
10 17 import videojs, { VideoJsPlayer } from 'video.js'
11 18 import type { VideoJsPlayerOptions } from 'video.js'
12 19 import 'video.js/dist/video-js.css'
... ... @@ -17,6 +24,7 @@ const props = withDefaults(
17 24 path: string
18 25 autoPlay?: boolean
19 26 h?: number
  27 + poster?: string
20 28 }>(),
21 29 { autoPlay: false }
22 30 )
... ... @@ -33,19 +41,22 @@ const initPlay = async () => {
33 41 controls: true,
34 42 autoplay: props.autoPlay,
35 43 src: props?.path,
  44 + poster: props?.poster,
36 45 language: 'zh-CN',
37   - techOrder: ['html5']
  46 + techOrder: ['html5'],
  47 + preload: 'none'
38 48 }
39 49 player = videojs(videoRef.value, options, () => {
40   - videojs.log('播放器已经准备好了!')
  50 + videojs.log('Video is reading')
41 51 if (props.autoPlay) {
42 52 player.play()
43 53 }
44 54 player.on('ended', () => {
45   - videojs.log('播放结束了!')
  55 + videojs.log('Play end')
46 56 })
47 57 player.on('error', () => {
48   - videojs.log('播放器解析出错!')
  58 + player.errorDisplay.close()
  59 + videojs.log('Play parse error')
49 60 })
50 61 })
51 62 }
... ... @@ -58,10 +69,10 @@ onMounted(() => {
58 69 watch(
59 70 () => props.path,
60 71 () => {
61   - player?.pause()
62   - player?.src(props.path)
63   - player?.load()
64   - if (props.path) {
  72 + if (props.path && props.autoPlay) {
  73 + player?.pause()
  74 + player?.load()
  75 + player?.src(props.path)
65 76 player?.play()
66 77 }
67 78 },
... ... @@ -74,11 +85,15 @@ onBeforeUnmount(() => {
74 85 player?.dispose()
75 86 })
76 87 </script>
  88 +<style>
  89 +.vjs-poster {
  90 + background-size: cover !important;
  91 +}
  92 +</style>
77 93 <style lang="scss" scoped>
78 94 .videoPlay {
79 95 flex: 1;
80 96 height: v-bind('`${h}px`');
81   -
82 97 .video-js {
83 98 height: 100%;
84 99 width: 100%;
... ...
... ... @@ -6,6 +6,7 @@ import cloneDeep from 'lodash/cloneDeep'
6 6 export const option = {
7 7 dataset: '',
8 8 autoplay: false,
  9 + poster: ''
9 10 }
10 11
11 12 export default class Config extends PublicConfigClass implements CreateComponentType {
... ...
1 1 <template>
2 2 <CollapseItem name="播放器配置" :expanded="true">
  3 + <setting-item-box name="上传图片" :alone="true">
  4 + <setting-item>
  5 + <n-card class="upload-box">
  6 + <n-upload
  7 + :show-file-list="false"
  8 + v-model:file-list="uploadFileListRef"
  9 + :customRequest="customRequest"
  10 + :onBeforeUpload="beforeUploadHandle"
  11 + >
  12 + <n-upload-dragger>
  13 + <img v-if="optionData.poster" class="upload-show" :src="optionData.poster" alt="背景" />
  14 + <div class="upload-img" v-show="!optionData.poster">
  15 + <img src="@/assets/images/canvas/noImage.png" />
  16 + <n-text class="upload-desc" depth="3">
  17 + 图片需小于 {{ backgroundImageSize }}M ,格式为 png/jpg/gif 的文件
  18 + </n-text>
  19 + </div>
  20 + </n-upload-dragger>
  21 + </n-upload>
  22 + </n-card>
  23 + </setting-item>
  24 + </setting-item-box>
3 25 <setting-item-box name="源地址" :alone="true">
4 26 <setting-item>
5 27 <n-input-group>
... ... @@ -16,14 +38,94 @@
16 38 </template>
17 39
18 40 <script setup lang="ts">
19   -import { PropType } from 'vue'
  41 +import { PropType, ref, nextTick } from 'vue'
20 42 import { option } from './config'
21 43 import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  44 +import { FileTypeEnum } from '@/enums/fileTypeEnum'
  45 +import { uploadFile } from '@/api/external/contentSave/content'
  46 +import { UploadCustomRequestOptions } from 'naive-ui'
  47 +import { backgroundImageSize } from '@/settings/designSetting'
  48 +import { fetchRouteParamsLocation } from '@/utils'
22 49
23   -defineProps({
  50 +const props = defineProps({
24 51 optionData: {
25 52 type: Object as PropType<typeof option>,
26 53 required: true
27 54 }
28 55 })
  56 +
  57 +const uploadFileListRef = ref()
  58 +
  59 +// 上传图片前置处理
  60 +// eslint-disable-next-line @typescript-eslint/ban-ts-comment
  61 +//@ts-ignore
  62 +const beforeUploadHandle = async ({ file }) => {
  63 + uploadFileListRef.value = []
  64 + const type = file.file.type
  65 + const size = file.file.size
  66 +
  67 + if (size > 1024 * 1024 * backgroundImageSize) {
  68 + window['$message'].warning(`图片超出 ${backgroundImageSize}M 限制,请重新上传!`)
  69 + return false
  70 + }
  71 + if (type !== FileTypeEnum.PNG && type !== FileTypeEnum.JPEG && type !== FileTypeEnum.GIF) {
  72 + window['$message'].warning('文件格式不符合,请重新上传!')
  73 + return false
  74 + }
  75 + return true
  76 +}
  77 +
  78 +// 自定义上传操作
  79 +const customRequest = (options: UploadCustomRequestOptions) => {
  80 + const { file } = options
  81 + nextTick(async () => {
  82 + if (file.file) {
  83 + // 修改名称
  84 + const newNameFile = new File([file.file], `${fetchRouteParamsLocation()}_index_background.png`, {
  85 + type: file.file.type
  86 + })
  87 + let uploadParams = new FormData()
  88 + uploadParams.append('file', newNameFile)
  89 + const uploadRes = await uploadFile(uploadParams)
  90 + if (uploadRes) {
  91 + props.optionData.poster = uploadRes?.fileStaticUri
  92 + window['$message'].success('添加图片成功!')
  93 + }
  94 + } else {
  95 + window['$message'].error('添加图片失败,请稍后重试!')
  96 + }
  97 + })
  98 +}
29 99 </script>
  100 +<style lang="scss" scoped>
  101 +$uploadHeight: 193px;
  102 +.upload-box {
  103 + cursor: pointer;
  104 + margin-bottom: 20px;
  105 + @include deep() {
  106 + .n-card__content {
  107 + padding: 0;
  108 + overflow: hidden;
  109 + }
  110 + .n-upload-dragger {
  111 + padding: 5px;
  112 + }
  113 + }
  114 + .upload-show {
  115 + width: -webkit-fill-available;
  116 + height: $uploadHeight;
  117 + border-radius: 5px;
  118 + }
  119 + .upload-img {
  120 + display: flex;
  121 + flex-direction: column;
  122 + align-items: center;
  123 + img {
  124 + height: 150px;
  125 + }
  126 + .upload-desc {
  127 + padding: 10px 0;
  128 + }
  129 + }
  130 +}
  131 +</style>
... ...
1 1 <template>
2 2 <div>
3   - <VideoPlay :h="h" :path="option.dataset" :autoPlay="autoplay" />
  3 + <VideoPlay :h="h" :path="option.dataset" :autoPlay="autoplay" :poster="option.poster" />
4 4 </div>
5 5 </template>
6 6 <script setup lang="ts">
... ... @@ -18,10 +18,11 @@ const props = defineProps({
18 18
19 19 const { h } = toRefs(props.chartConfig.attr)
20 20
21   -const { autoplay, dataset } = toRefs(props.chartConfig.option)
  21 +const { autoplay, dataset, poster } = toRefs(props.chartConfig.option)
22 22
23 23 const option = shallowReactive({
24   - dataset: configOption.dataset
  24 + dataset: configOption.dataset,
  25 + poster: configOption.poster
25 26 })
26 27
27 28 watch(
... ... @@ -30,7 +31,17 @@ watch(
30 31 option.dataset = newData
31 32 },
32 33 {
33   - immediate: true,
  34 + immediate: true
  35 + }
  36 +)
  37 +
  38 +watch(
  39 + () => poster?.value,
  40 + (newData: string) => {
  41 + option.poster = newData
  42 + },
  43 + {
  44 + immediate: true
34 45 }
35 46 )
36 47 </script>
... ...