2023年5月15日 修改后台直播间,更改为新版,增加推流开关,课题开关

This commit is contained in:
bai 2023-05-15 14:08:47 +08:00
parent 554d769367
commit 705d30f85e
7 changed files with 744 additions and 114 deletions

View File

@ -1,64 +1,137 @@
<template>
<div style="width:100%;height: 100%;">
<a-row>
<a-col :span="3">
<a-menu
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
style="overflow: hidden;overflow-y:scroll"
:style="{ height: `calc(100vh - ${topWidth})`, borderRight: 0 }"
mode="inline"
>
<a-menu-item v-for="(item, index) of leftList" :key="index" @click="(e) => titleClick(e,item)" :title="`${item.jsmc}`">
{{ item.jsmc }}
</a-menu-item>
</a-menu>
</a-col>
<a-col :span="21">
<div>
<a-card :title="mainVideoCardBoxTitle" class="videoCardMain" style="width:100%">
<bVideo ref="mainVideo" videoId="mainVideo" :videoOption="{ autoplay: true }"/>
</a-card>
</div>
<div style="display: flex;flex-direction: row;flex-wrap: nowrap;overflow-x: scroll;">
<div v-for="(item,index) of calcOtherVideo()" class="videoMax">
<a-card :title="item?.xm" class="videoCardMain">
<!-- <bVideo :ref="el=> bVideoRefs[index]=el" :src="'http://127.0.0.1/live_hls/soures.m3u8'" type="application/x-mpegURL" :videoId="'other-'+item.id"/> -->
<!-- <bVideo :ref="el=> bVideoRefs[index]=el" :src="'http://bylwcs.nenu.edu.cn:8089/live_hls/123.m3u8'" type="application/x-mpegURL" :videoId="'other-'+item.id"/> -->
<!-- <bVideo :ref="el=> bVideoRefs[index]=el" :videoOption="{ autoplay: true, userActions: { click: bVideoClick } }" :src="'https://bylwcs.nenu.edu.cn:9553/live_hls/yfjxl101s_lbzj.m3u8'" type="application/x-mpegURL" :videoId="'other-'+item.id"/> -->
<bVideo :ref="el=> bVideoRefs[index]=el" :videoId="'other-'+item.id" :src="item.pullUrl" :videoOption="{ autoplay: true, userActions: { click: bVideoClick } }" @load-end="loadEnd"/>
<!-- <bVideo :ref="el=> bVideoRefs[index]=el" :videoId="'other-'+item.id" :src="'http://127.0.0.1/live_hls/soures.m3u8'" :videoOption="{ autoplay: true, userActions: { click: bVideoClick } }" @load-end="loadEnd"/> -->
</a-card>
</div>
</div>
</a-col>
</a-row>
<a-table :loading="loading" :data-source="leftList" :pagination="false" bordered size="middle" class="ant-table-striped">
<a-table-column title="教室" data-index="jsmc"/>
<a-table-column title="教师近景" align="center" data-index="child_教师定位">
<template #default="{ record }">
<span :class="record?.child['教师定位']?.isOnLine?'green':'red'">
<i class="fas fa-circle" />
</span>
</template>
</a-table-column>
<a-table-column title="教师全景" align="center" data-index="child_">
<template #default="{ record }">
<span :class="record?.child['录播主机']?.isOnLine?'green':'red'">
<i class="fas fa-circle"/>
</span>
</template>
</a-table-column>
<a-table-column title="学生全景" align="center" data-index="child_学生全景">
<template #default="{ record }">
<span :class="record?.child['学生全景']?.isOnLine?'green':'red'">
<i class="fas fa-circle"/>
</span>
</template>
</a-table-column>
<a-table-column title="PPT" align="center" data-index="child_PPT">
<template #default="{ record }">
<span :class="record?.child['PPT']?.isOnLine?'green':'red'">
<i class="fas fa-circle"/>
</span>
</template>
</a-table-column>
<a-table-column title="直播推流" align="center" data-index="child_直播推流">
<template #default="{ record }">
<span :class="record?.child['录播主机']?.isOnLine?'green':'red'">
<i class="fas fa-circle"/>
</span>
</template>
</a-table-column>
<a-table-column title="课堂上线" align="center" data-index="sfyx">
<template #default="{ text }">
<span :class="text == 0?'green':'red'">
<i class="fas fa-circle"/>
</span>
</template>
</a-table-column>
<a-table-column title="操作" data-index="action">
<template #default="{ record }">
<a @click="ylLive(record)">预览</a> |
<a v-if="!record?.child['录播主机']?.isOnLine" @click="changeLive(record,true)">开启推流 |</a>
<a v-else @click="changeLive(record,false)">关闭推流 |</a>
<a v-if="record.sfyx == 1" @click="changeKt(record,true)">课堂上线</a>
<a v-else-if="record.sfyx == 0" @click="changeKt(record,false)">课堂下线</a>
<!-- {{ record.id }} -->
</template>
</a-table-column>
</a-table>
</div>
<a-modal :visible="isShowAllLive" width="80%" style="top: 20px" title="直播" :ok-button-props="{ style: { display: 'none' } }" cancelText="关闭" @cancel="() => isShowAllLive = false">
<showAllLive ref="showAllLiveRef" :currentItem="currentItem"/>
</a-modal>
</template>
<script lang="ts" setup name="zhihuijiaoshiIndexPage">
import { defHttp } from '/@/utils/http/axios';
import { ref, onMounted } from 'vue';
import bVideo from '/@/views/site/common/video/videojs/video.vue';
import { ref, onMounted, Ref, watch } from 'vue';
import { nextTick } from 'vue';
import videojs from "video.js";
import { useMessage } from '/@/hooks/web/useMessage';
import showAllLive from './showAllLive.vue';
import { execAvyApi, getAvyCtrlLiveOpenOrCloseUrl } from "/@/views/site/utils/index";
const bVideoRefs = <any>ref([]);
const mainVideo = <any>ref();
const _document = window.document;
// const bVideoLeftRef = ref();
const leftList = <any>ref([]);
const currentItem = <any>ref({});
const topWidth = <any>ref('0');
const isfirst = <any>ref(false);
const mainVideoCardBoxTitle = <any>ref('');
// const _document:any = window.document;
const showAllLiveRef = ref();
const leftList:Ref<any> = ref([]);
const currentItem:Ref<any> = ref({});
// const topWidth:any = ref('0');
// const isfirst:any = ref(false);
const showAllLiveKey:Ref<string> = ref('showAllLiveKey');
const isShowAllLive:Ref<boolean> = ref(false);
const loading:Ref<boolean> = ref(false);
const { createMessage } = useMessage();
onMounted(() => {
list({ pageSize: -1, sfyx: '0' }).then(res => {
loadData();
});
enum Api {
list = '/jiaoshi/kcZhihuijiaoshi/list',
updateAllLive = '/jiaoshi/kcZhihuijiaoshi/updateAllLive'
}
/**
* 列表接口
* @param params
*/
const list = (params) => defHttp.get({ url: Api.list, params });
const updateAllLive = (params) => defHttp.get({ url: Api.updateAllLive, params });
function loadData(){
loading.value = true;
let getListAction:any = [];
let liveIsExist = (x) => {
return new Promise((resolve,reject) => {
videojs.xhr.get(x.pullUrl,(err, resp, body) => {
if(err){
reject(false);
x.isOnLine = false
}else{
resolve(true);
x.isOnLine = true
}
})
//
// defHttp.get({ url: x.pullUrl }, { isExternal: true, withToken: true }).then(res => {
// resolve(true);
// x.isOnLine = true;
// }).catch(eres => {
// reject(false);
// x.isOnLine = false;
// })
})
}
list({ pageSize: -1, changshang: '奥威亚' }).then(res => {
let list = (res?.records) ?? [];
//
let map = {};
list.forEach(x => {
let item = map[x.jsmc];
x.isOnLine = false;
if(item){
item.child[x.xm] = x;
}else{
@ -68,86 +141,103 @@ onMounted(() => {
...x,
child
};
item = map[x.jsmc];
}
});
leftList.value = Object.values(map);
loading.value = false;
nextTick(() => {
leftList.value.forEach(item => {
let child = item.child;
Object.values(child).forEach(item => {
let x:any = item;
// if(x.pullUrl == 'https://kczx.nenu.edu.cn:9553/live_hls/yfjxl101s_lbzj.m3u8')
getListAction.push(liveIsExist(x));
});
});
Promise.all(getListAction).then(resList => {
console.log(`🚀 ~ file: index.vue:104 ~ Promise.all ~ ress:`, resList);
// loading.value = false;
}).catch((e) => {
console.error(e);
// loading.value = false;
});
});
//
let mainDiv = <any>_document?.querySelector('.ant-layout .jeecg-default-layout-main > div');
topWidth.value =mainDiv?.style?.height?? '0';
// let mainDiv:any = _document?.querySelector('.ant-layout .jeecg-default-layout-main > div');
// topWidth.value =mainDiv?.style?.height?? '0';
});
});
enum Api {
list = '/jiaoshi/kcZhihuijiaoshi/list',
}
/**
* 列表接口
* @param params
*/
const list = (params) => defHttp.get({ url: Api.list, params });
const selectedKeys = ref<string[]>(['1']);
const openKeys = ref<string[]>(['sub1']);
/**
* 点击左侧菜单回调
* @param e
* @param item
*/
const titleClick = (e: Event, item: any) => {
//
isfirst.value = false;
currentItem.value = {};
//
function ylLive(record){
isShowAllLive.value = true
nextTick(() => {
currentItem.value = item;
});
};
/**
* 子页加载完成后回调
* @param player
*/
function loadEnd(player){
nextTick(() => {
if(!isfirst.value){
isfirst.value = true;
//
let one = <any>Object.values(calcOtherVideo())[0];
bVideoClick({ target: { playerId: 'other-'+ one.id} })
}
});
currentItem.value = record
})
}
/**
* 拆分对象过滤器
*/
function calcOtherVideo() :any{
if(!currentItem.value.child) return {};
let map = {};
Object.keys(currentItem.value.child).forEach(key => {
// if(key != '' && key.indexOf('') ==-1){
map[key] = currentItem.value.child[key];
// }
function changeLive(record, isEnable){
loading.value = true;
//record
let changeLiveEnd:any = [];
Object.values(record.child).forEach(x => {
let item:any = x;
changeLiveEnd.push(new Promise((resolve,reject) => {
videojs.xhr.get(getAvyCtrlLiveOpenOrCloseUrl(item.ip,item.user,item.mima,isEnable),(err, resp, body) => {
if(!err){
resolve(true);
}else{
reject(false);
}
})
}));
});
return map;
console.log('changeLiveEnd ->',changeLiveEnd);
Promise.all(changeLiveEnd).then(resList => {
console.log(`🚀 ----------------------------------------------------------🚀`);
console.log(`🚀 ~ file: index.vue:181 ~ Promise.all ~ resList:`, resList);
console.log(`🚀 ----------------------------------------------------------🚀`);
createMessage.info("操作成功!");
loadData();
}).catch(e => {
console.error(e);
createMessage.error("操作失败!");
loading.value = false;
});
// if(!err){
// createMessage.info("");
// loadData();
// }else{
// createMessage.error("");
// }
}
/**
* 点击时切换至大屏
* @param e
*/
function bVideoClick(e){
console.log(`bVideoClick: 点击切换至主界面`);
function changeKt(record, isEnable){
loading.value = true;
let ids:any = [];
Object.values(record.child).forEach(x => {
let item:any = x;
ids.push(item.id);
});
if(!ids) return;
updateAllLive({ ids: ids.join(','), sfyx: isEnable?0:1}).then(res => {
console.log(`🚀 ----------------------------------------------------🚀`);
console.log(`🚀 ~ file: index.vue:176 ~ updateAllLive ~ res:`, res);
console.log(`🚀 ----------------------------------------------------🚀`);
loadData();
// createMessage.
}).catch(e => {
console.error(e);
loading.value = false;
})
let mainVideo = <any> document.querySelector('#mainVideo');
let currentVideo = <any> document.querySelector('#'+e.target.playerId);
let src = currentVideo.player?.src();
mainVideo?.player?.src([{type:'application/x-mpegURL',src }])
}
</script>
@ -164,4 +254,10 @@ function bVideoClick(e){
video::-webkit-media-controls-timeline {
display: none;
}
.green {
color: green;
}
.red {
color: red;
}
</style>

View File

@ -0,0 +1,169 @@
<template>
<div style="width:100%;height: 100%;">
<a-row>
<a-col :span="3">
<a-menu
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
style="overflow: hidden;overflow-y:scroll"
:style="{ height: `calc(100vh - ${topWidth})`, borderRight: 0 }"
mode="inline"
>
<a-menu-item v-for="(item, index) of leftList" :key="index" @click="(e) => titleClick(e,item)" :title="`${item.jsmc}`">
{{ item.jsmc }}
</a-menu-item>
</a-menu>
</a-col>
<a-col :span="21">
<div>
<a-card :title="mainVideoCardBoxTitle" class="videoCardMain" style="width:100%">
<bVideo ref="mainVideo" videoId="mainVideo" :videoOption="{ autoplay: true }"/>
</a-card>
</div>
<div style="display: flex;flex-direction: row;flex-wrap: nowrap;overflow-x: scroll;">
<div v-for="(item,index) of calcOtherVideo()" class="videoMax" :key="index">
<a-card class="videoCardMain">
<template #title>
<span>{{ item?.xm }}</span>
<span style="padding-left: 1rem;" @click="execAvyApi(getAvyCtrlLiveOpenOrCloseUrl(item.ip,item.user,item.mima,true))">打开直播</span>
<span style="padding-left: 1rem;" @click="execAvyApi(getAvyCtrlLiveOpenOrCloseUrl(item.ip,item.user,item.mima,false))">关闭直播</span>
</template>
<bVideo :ref="el=> bVideoRefs[index]=el" :videoId="'other-'+item.id" :src="item.pullUrl" :videoOption="{ autoplay: true, userActions: { click: bVideoClick } }" @load-end="loadEnd"/>
</a-card>
</div>
</div>
</a-col>
</a-row>
</div>
</template>
<script lang="ts" setup name="zhihuijiaoshiIndexPage">
import { defHttp } from '/@/utils/http/axios';
import { ref, onMounted } from 'vue';
import bVideo from '/@/views/site/common/video/videojs/video.vue';
import { nextTick } from 'vue';
import { execAvyApi, getAvyCtrlLiveOpenOrCloseUrl } from "/@/views/site/utils/index";
const bVideoRefs:any = ref([]);
const mainVideo:any = ref();
const _document:any = window.document;
// const bVideoLeftRef = ref();
const leftList:any = ref([]);
const currentItem:any = ref({});
const topWidth:any = ref('0');
const isfirst:any = ref(false);
const mainVideoCardBoxTitle:any = ref('');
onMounted(() => {
list({ pageSize: -1, sfyx: '0' }).then(res => {
let list = (res?.records) ?? [];
//聚合
let map = {};
list.forEach(x => {
let item = map[x.jsmc];
if(item){
item.child[x.xm] = x;
}else{
let child = {};
child[x.xm] = x;
map[x.jsmc] = {
...x,
child
};
}
});
leftList.value = Object.values(map);
//计算左侧菜单高度
let mainDiv:any = _document?.querySelector('.ant-layout .jeecg-default-layout-main > div');
topWidth.value =mainDiv?.style?.height?? '0';
});
});
enum Api {
list = '/jiaoshi/kcZhihuijiaoshi/list',
}
/**
* 列表接口
* @param params
*/
const list = (params) => defHttp.get({ url: Api.list, params });
const selectedKeys = ref<string[]>(['1']);
const openKeys = ref<string[]>(['sub1']);
/**
* 点击左侧菜单回调
* @param e
* @param item
*/
const titleClick = (e: Event, item: any) => {
//初始化数据
isfirst.value = false;
currentItem.value = {};
//等一会,清空上一次的对象,
nextTick(() => {
currentItem.value = item;
});
};
/**
* 子页加载完成后回调
* @param player
*/
function loadEnd(player){
nextTick(() => {
if(!isfirst.value){
isfirst.value = true;
//播放第一个
let one:any = Object.values(calcOtherVideo())[0];
bVideoClick({ target: { playerId: 'other-'+ one.id} })
}
});
}
/**
* 拆分对象(过滤器)
*/
function calcOtherVideo() :any{
if(!currentItem.value.child) return {};
let map = {};
Object.keys(currentItem.value.child).forEach(key => {
// if(key != '录播主机' && key.indexOf('音频处理器') ==-1){
map[key] = currentItem.value.child[key];
// }
});
return map;
}
/**
* 点击时切换至大屏
* @param e
*/
function bVideoClick(e:any){
console.log(`bVideoClick: 点击切换至主界面`);
let mainVideo:any = document.querySelector('#mainVideo');
let currentVideo:any = document.querySelector('#'+e.target.playerId);
let src = currentVideo.player?.src();
mainVideo?.player?.src([{type:'application/x-mpegURL',src }])
}
</script>
<style lang="less" scoped>
.videoMax{
width: 25%;
}
.videoCardMain {
:deep(.ant-card-body) {
padding: 0;
}
}
/* 隐藏video 进度条 */
video::-webkit-media-controls-timeline {
display: none;
}

View File

@ -0,0 +1,226 @@
<template>
<div style="width:100%;height: 100%;">
<a-row>
<!-- <a-col :span="3"> -->
<!-- <a-menu
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
style="overflow: hidden;overflow-y:scroll"
:style="{ height: `calc(100vh - ${topWidth})`, borderRight: 0 }"
mode="inline"
>
<a-menu-item v-for="(item, index) of leftList" :key="index" @click="(e) => titleClick(e,item)" :title="`${item.jsmc}`">
{{ item.jsmc }}
</a-menu-item>
</a-menu> -->
<!-- </a-col> -->
<a-col :span="24">
<div>
<a-card :title="mainVideoCardBoxTitle" class="videoCardMain" style="width:100%">
<bVideo ref="mainVideo" videoId="mainVideo" :videoOption="{ autoplay: true }"/>
</a-card>
</div>
<div style="display: flex;flex-direction: row;flex-wrap: nowrap;overflow-x: scroll;">
<div v-for="(item,index) of calcOtherVideo()" class="videoMax" :key="index">
<a-card class="videoCardMain">
<template #title>
<span>{{ item?.xm }}</span>
<!-- <span style="padding-left: 1rem;" @click="execAvyApi(getAvyCtrlLiveOpenOrCloseUrl(item.ip,item.user,item.mima,true))">打开直播</span>
<span style="padding-left: 1rem;" @click="execAvyApi(getAvyCtrlLiveOpenOrCloseUrl(item.ip,item.user,item.mima,false))">关闭直播</span> -->
</template>
<bVideo :ref="el=> bVideoRefs[index]=el" :videoId="'other-'+item.id" :src="item.pullUrl" :videoOption="{ autoplay: true, userActions: { click: bVideoClick } }" @load-end="loadEnd"/>
</a-card>
</div>
</div>
</a-col>
</a-row>
</div>
</template>
<script lang="ts" setup name="zhihuijiaoshiIndexPage">
import { defHttp } from '/@/utils/http/axios';
import { ref, onMounted, watch } from 'vue';
import bVideo from '/@/views/site/common/video/videojs/video.vue';
import { nextTick } from 'vue';
import { execAvyApi, getAvyCtrlLiveOpenOrCloseUrl } from "/@/views/site/utils/index";
import { propTypes } from '/@/utils/propTypes';
const bVideoRefs:any = ref([]);
const mainVideo:any = ref();
// const _document:any = window.document;
// const bVideoLeftRef = ref();
// const leftList:any = ref([]);
// const currentItem:any = ref({});
// const topWidth:any = ref('0');
const isfirst:any = ref(false);
const isMainVideoShow:any = ref(false);
const mainVideoCardBoxTitle:any = ref('');
const currentItem:any = ref({});
const props = defineProps({
currentItem: propTypes.object.def({}),
isShowAllLive: propTypes.bool.def(true),
});
watch(() => props.currentItem, (v) => {
currentItem.value = {};
isMainVideoShow.value = false;
setTimeout(() => {
currentItem.value = v;
isMainVideoShow.value = true;
isfirst.value = false
}, 50);
// mainVideo.value.init();
// currentItem.value = v;
// console.log('???????',v);
//
})
// onMounted(() => {
// list({ pageSize: -1, sfyx: '0' }).then(res => {
// let list = (res?.records) ?? [];
// //
// let map = {};
// list.forEach(x => {
// let item = map[x.jsmc];
// if(item){
// item.child[x.xm] = x;
// }else{
// let child = {};
// child[x.xm] = x;
// map[x.jsmc] = {
// ...x,
// child
// };
// }
// });
// leftList.value = Object.values(map);
//
// let mainDiv:any = _document?.querySelector('.ant-layout .jeecg-default-layout-main > div');
// topWidth.value =mainDiv?.style?.height?? '0';
// });
// });
// enum Api {
// list = '/jiaoshi/kcZhihuijiaoshi/list',
// }
/**
* 列表接口
* @param params
*/
// const list = (params) => defHttp.get({ url: Api.list, params });
// const selectedKeys = ref<string[]>(['1']);
// const openKeys = ref<string[]>(['sub1']);
function init(){
// let { currentItem } = props;
//
}
// /**
// *
// * @param e
// * @param item
// */
// const playLive = ( item: any ) => {
// //
// isfirst.value = false;
// // let { currentItem } = props;
// currentItem.value = {};
// //
// nextTick(() => {
// currentItem.value = item;
// });
// };
// /**
// *
// * @param e
// * @param item
// */
// const titleClick = (e: Event, item: any) => {
// playLive(item);
// };
/**
* 子页加载完成后回调
* @param player
*/
function loadEnd(player){
nextTick(() => {
if(!isfirst.value){
isfirst.value = true;
//
let one:any = Object.values(calcOtherVideo())[0];
bVideoClick({ target: { playerId: 'other-'+ one.id} })
}
});
}
/**
* 拆分对象过滤器
*/
function calcOtherVideo() :any{
// let { currentItem } = props;
if(!currentItem.value.child) return {};
let map = {};
Object.keys(currentItem.value.child).forEach(key => {
// if(key != '' && key.indexOf('') ==-1){
// console.log('currentItem.value.child[key] ->',currentItem.value.child[key]);
if(currentItem.value.child[key]?.sfyx == 0){
map[key] = currentItem.value.child[key];
}
// }
});
return map;
}
/**
* 点击时切换至大屏
* @param e
*/
function bVideoClick(e:any){
console.log(`bVideoClick: 点击切换至主界面`);
let mainVideo:any = document.querySelector('#mainVideo');
let currentVideo:any = document.querySelector('#'+e.target.playerId);
let src = currentVideo.player?.src();
mainVideo?.player?.src([{type:'application/x-mpegURL',src }])
if(!mainVideo.player){
//
console.log('重新初始化');
mainVideo.value.init();
}
}
defineExpose({
// playLive,
init
})
</script>
<style lang="less" scoped>
.videoMax{
width: 25%;
}
.videoCardMain {
:deep(.ant-card-body) {
padding: 0;
}
}
/* 隐藏video 进度条 */
video::-webkit-media-controls-timeline {
display: none;
}
</style>

View File

@ -19,6 +19,23 @@ export function getDefOptions(object) {
caches: true,
// playbackRates: [1,2,3,4,5,8,10,20],
trechIrder: ['flash'],
// controlBar: {
// children: ['FastReplayButton', 'playToggle', 'FastForwardButton', 'volumePanel', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'seekToLive', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subsCapsButton', 'audioTrackButton', 'fullscreenToggle']
// ,
/*children: [
"iconPreviousItem",
"Button",
"playToggle", // 播放暂停
"volumePanel", // 音量
"volumeMenuButton",
"durationDisplay",
"timeDivider",
"currentTimeDisplay",
"progressControl",
"remainingTimeDisplay",
"fullscreenToggle", // 全屏
],*/
// },
// sources: [{
// // type: 'rtmp/flv',
// // src: 'rtmp://127.0.0.1:1935/live/soures',

View File

@ -24,6 +24,7 @@ import { getDefOptions } from '/@/views/site/common/video/videojs/util';
import videojs from "video.js";
import "video.js/dist/video-js.css";
import video_zhCN from 'video.js/dist/lang/zh-CN.json'
const props = defineProps({
videoId: propTypes.string.def('playerId'),
@ -46,8 +47,10 @@ function init(){
sources: [ { type: props.type, src: props.src, } ]
};
}
videojs.addLanguage('zh-CN', video_zhCN);
let playerMain = videojs(props.videoId, getDefOptions(Object.assign(option, props.videoOption)),() => {
console.log("加载完成!",playerMain,props.videoOption);
// console.log("",playerMain,props.videoOption);
emit('loadEnd',playerMain);
// playerMain.on('pause', function(...d) {
// console.log('',...d);
@ -56,8 +59,75 @@ function init(){
// ...so you can do here all the stuff you want while the video is playing
// });
playerMain.language('zh-CN');
// console.log('videojs ->',videojs);
});
player.value = playerMain;
playerMain.ready(function() {
// playerMain.controlBar.addChild('TitleBar', {
// // text: '退',
// el: videojs.createEl('button', {
// title: '退',
// className: 'vjs-icon-previous-item vjs-fast-replay-button vjs-control vjs-button',
// innerHTML: '<span aria-hidden="true" class="vjs-icon-placeholder"></span><span class="vjs-control-text" aria-live="polite">退</span>'
// }),
// clickHandler: function() {
// playerMain.currentTime(playerMain.currentTime() - 10);
// }
// });
// console.log('videojs ->',videojs);
// let buttonList:Array<String> = [];
let currentSources:any = playerMain.currentSources();
// currentSources?.forEach(x => {
// buttonList.push(`<option value ="" style="color: black;"></option>`);
// })
let currentSource = currentSources[0];
let _playerMain: any = playerMain;
let _videojs: any = videojs;
_playerMain.controlBar.addChild('Button', {
text: '选择清晰度',
el: _videojs.createEl('button', {
title: '选择清晰度',
className: 'vjs-control',
innerHTML: `
<select class="changeDefinitionBtn" style="-webkit-appearance: none;background-color: rgba(0,0,0,0);border-radius: 0px" data-url="${currentSource || ''}">
<option value ="" style="color: black;">原画</option>
<option value ="_hi" style="color: black;">高清</option>
<option value ="_mid" style="color: black;">流畅</option>
<option value="_low" style="color: black;">标清</option>
</select>
`
}),
clickHandler: function() {
let el:any = playerMain.el().querySelector('.changeDefinitionBtn');
let currentSources:any = playerMain.currentSources();
let oldUrl = currentSources[0]?.src;
if(el){
let suffix = el.options[el.options.selectedIndex].value;
let url = el.dataset.url;
if(url){
if(suffix){//
url = url.replaceAll('.m3u8','');
url += suffix + '.m3u8';
}
if(oldUrl != url){//
playerMain.src([{ type: 'application/x-mpegURL', src: url}]);
playerMain.play();
}
}
}
}
});
});
}
defineExpose({

View File

@ -42,7 +42,7 @@
</div>
<div style="height: 2rem;">&nbsp;</div>
<div v-show="item.isShow" :key="'other-div-'+index">
<bVideo :key="'other-'+index" :ref="el=> bVideoRefs['other-'+item.id] = el" :videoId="'other-'+item.id" :src="item.pullUrl" :videoOption="{ autoplay: true, controls: false }" @load-end="loadEnd"/>
<bVideo :key="'other-'+index" :ref="el=> bVideoRefs['other-'+item.id] = el" :videoId="'other-'+item.id" :src="'http://127.0.0.1/hls/a.m3u8'" :videoOption="{ autoplay: true, controls: false }" @load-end="loadEnd"/>
</div>
</div>
</a-card>
@ -153,13 +153,20 @@ function initVideo(key){
function changeLive(item:any){
let mainVideo = document.querySelector<any>('#mainVideo');
mainVideo?.player?.src([{ type:'application/x-mpegURL',src: item.pullUrl }])
mainVideo?.player?.src([{ type:'application/x-mpegURL',src: 'http://127.0.0.1/live_hls/a.m3u8' }])
mainVideoCardBoxTitle.value = item.jsmc+item.xm;
console.log(`🚀 --------------------------------------------------------------------------------🚀`);
console.log(`🚀 ~ file: viewPage.vue:164 ~ changeLive ~ mainVideo?.player:`, mainVideo?.player);
console.log(`🚀 --------------------------------------------------------------------------------🚀`);
let buttonEl = mainVideo?.player.el().querySelector('.changeDefinitionBtn');
buttonEl.dataset.url = 'http://127.0.0.1/live_hls/a.m3u8';
curentPlayerVideo.value = item;
}
function getSuibi(){
//
let param = {

View File

@ -1,5 +1,7 @@
import { defHttp } from '/@/utils/http/axios';
import { useUserStore } from '/@/store/modules/user';
import md5 from 'md5';
import { useMessage } from '/@/hooks/web/useMessage';
/**
@ -49,3 +51,46 @@ export const getSysConfig = ():any => {
const { sysConfigInfo } = useUserStore();
return sysConfigInfo??{};
}
export const getMd5Str = ( str:string ) :string => {
return md5(str);
}
export const get16BitStr = ( str:string ) :string => {
let val="";
for(let i = 0; i < str.length; i++){
if(val == "")
val = str.charCodeAt(i).toString(16);
else
// val += "," + str.charCodeAt(i).toString(16);
val += str.charCodeAt(i).toString(16);
}
return val;
}
export const getAvyCtrlBaseUrl = ( ip:string, user:string, pwd:string ) :string => {
//pam.push(`live_setParam_enable=`)
return `http://${ip}/cgi-bin/plat.cgi?action=9&user=${user}&pwsd=${getMd5Str(pwd)}&command=1`;
}
/**
* /
* @param ip
* @param user
* @param pwd
* @param isEnable
* @returns
*/
export const getAvyCtrlLiveOpenOrCloseUrl = ( ip:string, user:string, pwd:string, isEnable:boolean ) :string => {
let paramStr = `live_setParam_enable=${isEnable?1:0}`;
return `${getAvyCtrlBaseUrl(ip,user,pwd)}&data=${get16BitStr(paramStr)}`;
}
export const execAvyApi = (url:string, cellback?):void => {
// const { createMessage } = useMessage();
defHttp.get({ url }).then(res => {
cellback?cellback(res):null;
console.log('奥威亚返回内容',res);
// createMessage.success("操作成功");
})
}