Commit d8eba72c58f003e6e8824396724e134b2ac316cb
1 parent
78e283b6
feat(src/packages): 组合里单个摄像头新增封面上传
Showing
4 changed files
with
146 additions
and
17 deletions
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%; | ... | ... |
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> | ... | ... |