refactor(仪表板): 视频播放优化

This commit is contained in:
wangjiahao 2024-05-14 23:55:36 +08:00
parent c017d6bd15
commit ef6f7b6e2e
11 changed files with 313 additions and 32 deletions

View File

@ -50,8 +50,8 @@
"vue-router": "4.1.3",
"vue-types": "^5.0.2",
"vue-uuid": "^3.0.0",
"vue-video-player": "^6.0.0",
"vue3-ace-editor": "^2.2.2",
"vue3-video-play": "^1.3.2",
"vuedraggable": "^4.1.0",
"web-storage-cache": "^1.1.1",
"xss": "^1.0.14"

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -444,7 +444,7 @@ const initOpenHandler = newWindow => {
<component-group
is-label
themes="light"
:base-width="115"
:base-width="215"
icon-name="dv-media"
title="媒体"
>

View File

@ -230,7 +230,7 @@ eventBus.on('clearCanvas', clearCanvas)
<component-group is-label :base-width="115" icon-name="dv-text" title="文本">
<text-group></text-group>
</component-group>
<component-group is-label :base-width="115" icon-name="dv-media" title="媒体">
<component-group is-label :base-width="215" icon-name="dv-media" title="媒体">
<media-group></media-group>
</component-group>
<component-group is-label :base-width="115" icon-name="dv-more-com" title="更多">

View File

@ -54,6 +54,7 @@ const { icon, name, label, dragInfo, themes } = toRefs(props)
.drag-component {
border-radius: 4px;
width: 88px !important;
margin-right: 12px;
.icon-content {
width: 88px !important;
height: 64px !important;

View File

@ -50,11 +50,19 @@ const handleDragEnd = e => {
drag-info="Picture&Picture"
v-on:click="newComponent('Picture')"
></drag-component>
<drag-component
:themes="themes"
icon="icon-video"
label="视频"
drag-info="DeVideo&DeVideo"
v-on:click="newComponent('DeVideo')"
></drag-component>
</div>
</template>
<style lang="less" scoped>
.group {
padding: 12px 8px;
display: inline-flex;
}
</style>

View File

@ -8,6 +8,82 @@ export const commonStyle = {
opacity: 1
}
// 视频信息配置
export const VIDEO_LINKS_DE2 = {
videoType: 'web',
poster: null,
web: {
width: '100%', //播放器宽度
height: '100%', //播放器高度
color: '#409eff', //主题色
title: '', //视频名称
src: null, //视频源
muted: false, //静音
webFullScreen: false,
speedRate: ['0.75', '1.0', '1.25', '1.5', '2.0'], //播放倍速
autoPlay: true, //自动播放
loop: false, //循环播放
mirror: false, //镜像画面
lightOff: false, //关灯模式
volume: 0.3, //默认音量大小
control: true, //是否显示控制
controlBtns: ['audioTrack', 'quality', 'volume', 'fullScreen'] //显示所有按钮,
},
rtmp: {
sources: [
{
type: 'rtmp/mp4'
}
],
height: 300,
techOrder: ['flash'],
autoplay: false,
controls: true,
flash: {
hls: {
withCredentials: false
}
}
}
}
// 视频信息配置
export const VIDEO_LINKS = {
videoType: 'web',
web: {
autoplay: true,
height: 300,
muted: true,
loop: true,
controlBar: {
timeDivider: false,
durationDisplay: false,
remainingTimeDisplay: false,
currentTimeDisplay: false, // 当前时间
volumeControl: false, // 声音控制键
fullscreenToggle: false,
pause: false
},
sources: [{}]
},
rtmp: {
sources: [
{
type: 'rtmp/mp4'
}
],
height: 300,
techOrder: ['flash'],
autoplay: false,
controls: true,
flash: {
hls: {
withCredentials: false
}
}
}
}
// 超链接配置
export const HYPERLINKS = {
openMode: '_blank',
@ -77,7 +153,7 @@ export const commonAttr = {
maintainRadio: false, // 布局时保持宽高比例
aspectRatio: 1, // 锁定时的宽高比例
isShow: true, // 是否显示组件
collapseName: ['position', 'background', 'style', 'picture', 'frameLinks'], // 编辑组件时记录当前使用的是哪个折叠面板再次回来时恢复上次打开的折叠面板优化用户体验
collapseName: ['position', 'background', 'style', 'picture', 'frameLinks', 'videoLinks'], // 编辑组件时记录当前使用的是哪个折叠面板再次回来时恢复上次打开的折叠面板优化用户体验
linkage: {
duration: 0, // 过渡持续时间
data: [
@ -169,6 +245,7 @@ const list = [
width: 600,
height: 300
},
videoLinks: VIDEO_LINKS_DE2,
matrixStyle: {}
},
{

View File

@ -1,6 +1,15 @@
<template>
<div class="attr-list de-collapse-style">
<CommonAttr :element="curComponent"></CommonAttr>
<CommonAttr :themes="themes" :element="curComponent">
<el-collapse-item
:effect="themes"
title="链接信息"
name="videoLinks"
v-if="curComponent && curComponent.videoLinks"
>
<video-links :link-info="curComponent.videoLinks" :themes="themes"></video-links>
</el-collapse-item>
</CommonAttr>
</div>
</template>
@ -8,6 +17,15 @@
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import CommonAttr from '@/custom-component/common/CommonAttr.vue'
import { storeToRefs } from 'pinia'
import VideoLinks from '@/custom-component/de-video/VideoLinks.vue'
const dvMainStore = dvMainStoreWithOut()
const { curComponent } = storeToRefs(dvMainStore)
withDefaults(
defineProps<{
themes?: EditorTheme
}>(),
{
themes: 'dark'
}
)
</script>

View File

@ -1,26 +1,21 @@
<template>
<el-row ref="mainPlayer">
<div v-if="element.videoLinks[element.videoLinks.videoType].sources[0].src" class="player">
<video-player
v-if="state.showVideo"
ref="videoPlayer"
class="vjs-custom-skin"
:options="editMode === 'preview' ? state.pOption : playerOptions"
:playsinline="true"
/>
<div v-if="element.videoLinks[element.videoLinks.videoType].src" class="player">
<video-play v-bind="playerOptions" />
</div>
<div v-else class="info-class">
<span>{{ $t('panel.link_add_tips_pre') }}</span>
<span>{{ $t('panel.video_add_tips') }}</span>
<span>{{ t('visualization.video_add_tips') }}</span>
</div>
</el-row>
</template>
<script setup lang="ts">
import VideoPlayer from 'vue-video-player'
import 'video.js/dist/video-js.css'
import { computed, nextTick, reactive, toRefs, watch } from 'vue'
import { videoPlay } from 'vue3-video-play/lib/index' //
import 'vue3-video-play/dist/style.css' // css
import { computed, nextTick, reactive, toRefs, watch, onMounted, ref } from 'vue'
import { useEmitt } from '@/hooks/web/useEmitt'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const props = defineProps({
propValue: {
type: String,
@ -45,21 +40,24 @@ const props = defineProps({
}
})
const state = reactive({
pOption: {},
pOption: {
height: null
},
showVideo: true
})
const { element, h } = toRefs(props)
const moveFlag = computed(
() => element.value.optStatus.dragging || element.value.optStatus.resizing
)
const playerOptions = computed(() => {
const videoPlayerOptions = element.value.videoLinks[element.value.videoLinks.videoType]
videoPlayerOptions.height = h
return videoPlayerOptions
onMounted(() => {
useEmitt({
name: 'videoLinksChange-' + element.value.id,
callback: function () {
videoLinksChange()
}
})
})
const playerOptions = computed(() => element.value.videoLinks[element.value.videoLinks.videoType])
const videoLinksChange = () => {
state.showVideo = false
nextTick(() => {
@ -83,18 +81,25 @@ watch(
<style lang="less" scoped>
.info-class {
text-align: center;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.3);
background-color: rgba(255, 255, 255, 0.1);
font-size: 12px;
color: #9ea6b2;
}
.move-bg {
.player {
height: 100%;
width: 100%;
display: flex;
align-items: center;
background-color: #000000;
}
.d-player-state {
display: none;
}
</style>

View File

@ -0,0 +1,172 @@
<template>
<el-row>
<el-form ref="form" size="small" style="width: 100%">
<el-form-item :effect="themes" :label="t('visualization.auto_play')">
<el-switch
:effect="themes"
@change="onChange"
v-model="state.linkInfoTemp[state.linkInfoTemp.videoType].autoPlay"
size="mini"
/>
</el-form-item>
<el-form-item
v-if="state.linkInfoTemp.videoType === 'web'"
:label="t('visualization.play_frequency')"
:effect="themes"
>
<el-radio-group
:effect="themes"
@change="onChange"
v-model="state.linkInfoTemp[state.linkInfoTemp.videoType].loop"
>
<el-radio :effect="themes" :label="false">{{ t('visualization.play_once') }}</el-radio>
<el-radio :effect="themes" :label="true">{{ t('visualization.play_circle') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :effect="themes" :label="t('visualization.video_links')">
<el-input
:effect="themes"
@blur="onChange"
v-model="state.linkInfoTemp[state.linkInfoTemp.videoType].src"
/>
<span class="tips-class"> Tips:{{ t('visualization.video_tips') }} </span>
</el-form-item>
</el-form>
</el-row>
</template>
<script setup lang="ts">
import { reactive, ref, toRefs, watch, computed } from 'vue'
import { dvMainStoreWithOut } from '../../store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia/dist/pinia'
import { checkAddHttp, deepCopy } from '../../utils/utils'
import { snapshotStoreWithOut } from '../../store/modules/data-visualization/snapshot'
import { useI18n } from '../../hooks/web/useI18n'
import { useEmitt } from '@/hooks/web/useEmitt'
const dvMainStore = dvMainStoreWithOut()
const { curComponent, curActiveTabInner } = storeToRefs(dvMainStore)
const snapshotStore = snapshotStoreWithOut()
const emits = defineEmits(['close'])
const popover = ref(null)
const { t } = useI18n()
const props = defineProps({
themes: {
type: String,
required: true,
default: 'dark'
},
linkInfo: {
type: Object,
required: true
},
//
attrPosition: {
type: String,
required: false,
default: 'panel'
}
})
const { linkInfo, attrPosition } = toRefs(props)
const state = reactive({
linkInfoTemp: null,
componentType: null,
linkageActiveStatus: false,
editFilter: ['view', 'custom']
})
const init = () => {
state.linkInfoTemp = deepCopy(linkInfo.value)
}
const onChange = () => {
state.linkInfoTemp[state.linkInfoTemp.videoType].src = checkAddHttp(
state.linkInfoTemp[state.linkInfoTemp.videoType].src
)
if (attrPosition.value === 'panel') {
curComponent.value.videoLinks = state.linkInfoTemp
} else {
curActiveTabInner.value.videoLinks = state.linkInfoTemp
}
curComponent.value.videoLinks = state.linkInfoTemp
snapshotStore.recordSnapshotCache()
useEmitt().emitter.emit('videoLinksChange-' + curComponent.value.id)
}
const onBlur = () => {
state.linkInfoTemp.src = checkAddHttp(state.linkInfoTemp.src)
curComponent.value.frameLinks.src = state.linkInfoTemp.src
snapshotStore.recordSnapshotCache()
useEmitt().emitter.emit('frameLinksChange-' + curComponent.value.id)
}
init()
watch(
linkInfo.value,
() => {
init()
},
{ deep: true }
)
</script>
<style lang="less" scoped>
.slot-class {
color: white;
}
.bottom {
margin-top: 20px;
text-align: center;
}
.ellipsis-area {
margin-left: 10px;
margin-right: 10px;
overflow: hidden; /*超出部分隐藏*/
white-space: nowrap; /*不换行*/
text-overflow: ellipsis; /*超出部分文字以...显示*/
background-color: #f7f8fa;
color: #3d4d66;
font-size: 12px;
line-height: 24px;
height: 24px;
border-radius: 3px;
}
.select-filed {
margin-left: 10px;
margin-right: 10px;
overflow: hidden; /*超出部分隐藏*/
white-space: nowrap; /*不换行*/
text-overflow: ellipsis; /*超出部分文字以...显示*/
color: #3d4d66;
font-size: 12px;
line-height: 35px;
height: 35px;
border-radius: 3px;
}
.tips-class {
color: #909399;
font-size: 8px;
margin-left: 3px;
}
.hint-icon {
cursor: pointer;
font-size: 14px;
color: #646a73;
&.hint-icon--dark {
color: #a6a6a6;
}
}
.data-area-label {
display: flex;
flex-direction: row;
align-items: center;
}
</style>

View File

@ -2126,7 +2126,7 @@ export default {
play_circle: '循环播放',
video_links: '视频链接',
web_url: '网页地址',
video_add_tips: '添加视频信息...',
video_add_tips: '请在右侧添加视频信息...',
link_add_tips_pre: '请在右侧配置网页信息..',
web_add_tips_suf: '添加网页信息...',
panel_view_result_show: '图表结果',