2023年4月24日 修改直播,

This commit is contained in:
bai 2023-04-24 22:40:50 +08:00
parent 69deb2409a
commit 531ed0f6d7
8 changed files with 229 additions and 89 deletions

View File

@ -101,6 +101,15 @@ const site: AppRouteModule = {
title: '直播video.js',
}
},
{
path: 'liveRoom',
name: 'studentLive3u8BroadcastRoom',
component: () => import('/@/views/site/common/video/videojs/viewPage.vue'),
meta: {
title: '直播课堂',
}
},
],
};

View File

@ -1,7 +1,7 @@
<template>
<div style="width:100%;height: 100%;">
<a-row>
<a-col :span="4">
<a-col :span="3">
<a-menu
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
@ -9,24 +9,25 @@
: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.xm}`">
{{ item.jsmc }}-{{ item.xm }}
<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="20">
<a-col :span="21">
<div>
<a-card :title="mainVideoCardBoxTitle" class="videoCardMain" style="width:100%">
<bVideo ref="mainVideo" videoId="mainVideo"></bVideo>
<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" style="width: 300px" class="videoCardMain">
<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" :videoOption="{ autoPlay: true, userActions: { click: bVideoClick } }" :src="'http://127.0.0.1/live_hls/soures.m3u8'" type="application/x-mpegURL" :videoId="'other-'+item.id"/> -->
<bVideo :ref="el=> bVideoRefs[index]=el" :videoOption="{ autoPlay: true, userActions: { click: bVideoClick } }" :src="item.pullUrl" 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" :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>
@ -48,6 +49,7 @@ const _document = window.document;
const leftList = <any>ref([]);
const currentItem = <any>ref({});
const topWidth = <any>ref('0');
const isfirst = <any>ref(false);
const mainVideoCardBoxTitle = <any>ref('');
onMounted(() => {
@ -95,20 +97,31 @@ const openKeys = ref<string[]>(['sub1']);
* @param item
*/
const titleClick = (e: Event, item: any) => {
console.log('titleClick ->', e, item);
//
isfirst.value = false;
currentItem.value = {};
//
nextTick(() => {
currentItem.value = item;
nextTick(() => {
//
let one = <any>Object.values(calcOtherVideo())[0];
bVideoClick({ target: { playerId: 'other-'+ one.id} })
});
// playerVideo(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} })
}
});
}
/**
* 拆分对象过滤器
*/
@ -129,7 +142,6 @@ function calcOtherVideo() :any{
*/
function bVideoClick(e){
console.log(`bVideoClick: 点击切换至主界面`);
console.log('e =>',e);
let mainVideo = <any> document.querySelector('#mainVideo');
let currentVideo = <any> document.querySelector('#'+e.target.playerId);
@ -141,7 +153,7 @@ function bVideoClick(e){
</script>
<style lang="less" scoped>
.videoMax{
width: 300px;
width: 25%;
}
.videoCardMain {
:deep(.ant-card-body) {

View File

@ -19,7 +19,7 @@
{{ projectName }}
<RouterLink hidden target='_blank' :to="{path:'/site/liveView',query:{ url: 'rtsp://176.139.87.16/axis-media/media.amp' }}">直播测试页rtsp</RouterLink>
<RouterLink hidden target='_blank' :to="{path:'/site/liveFlvView',query:{ url: 'rtsp://176.139.87.16/axis-media/media.amp' }}">直播测试页flv</RouterLink>
<RouterLink hidden target='_blank' :to="{path:'/site/livem3u8View',query:{ url: 'rtsp://176.139.87.16/axis-media/media.amp' }}">直播测试页m3u8</RouterLink>
<RouterLink hidden target='_blank' :to="{path:'/site/livem3u8View',query:{ url: 'https://bylwcs.nenu.edu.cn:9553/live_hls/yfjxl101s_lbzj.m3u8' }}">直播测试页m3u8</RouterLink>
</span>
<span class="topRight">
<a-dropdown>

View File

@ -1,75 +1,34 @@
<template>
<!-- <div @click="onPlay2">点击开始播放(连接)直播2</div> -->
<!-- <div>{{ route.query.url }}</div> -->
<video
id="my-player"
class="video-js"
controls
preload="auto"
poster="//vjs.zencdn.net/v/oceans.png"
>
<!-- <source src="//vjs.zencdn.net/v/oceans.mp4" type="video/mp4"/>
<source src="//vjs.zencdn.net/v/oceans.webm" type="video/webm"/>
<source src="//vjs.zencdn.net/v/oceans.ogv" type="video/ogg"/> -->
<!-- <source src="http://127.0.0.1/live_hls/soures.m3u8" type="video/mp4"/> -->
<!-- <source src="http://127.0.0.1/live_hls/soures.m3u8" type="rtmp/flv"/> -->
<p class="vjs-no-js">
要观看此视频请启用JavaScript并考虑升级web浏览器
<a href="https://videojs.com/html5-video-support/" target="_blank">
支持HTML5视频
</a>
</p>
</video>
<div style="width: 100%;height: 100%;">
<bVideo ref="mainVideo" videoId="main" :videoOption="{ autoplay: false }" @lode-end="lodeEnd"/>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount} from 'vue';
import { ref, onMounted, nextTick } from 'vue';
import bVideo from '/@/views/site/common/video/videojs/video.vue';
import { useRoute } from 'vue-router'
import videojs from "video.js";
import "video.js/dist/video-js.css";
// import bVideo from '/@/views/site/common/webRTC/video.vue';
// const bVideoRef = ref();
// const mainVideo = ref();
const route = useRoute();
// //webRtc
// onBeforeUnmount(() => {
// bVideoRef.value.closeWebRtcStreamerFn();
// })
// onMounted(() => {
// if(route.query.url){
// bVideoRef.value.connectFn(route.query.url);
// }
// nextTick(() => {
// if(route.query.url){
// console.log('mainVideo.value.player =>',mainVideo.value.player);
// mainVideo.value.player.src([{ type: 'application/x-mpegURL', src: route.query.url}])
// }
// })
// })
onMounted(() => {
function lodeEnd(player){
if(route.query.url){
var player = videojs('my-player',{
autoplay: true,
controls: true,
muted: true,
preload: 'auto',
language: 'zh-CN',
playbackRates: [1,2,3,4,5,8,10,20],
trechIrder: ['flash'],
sources: [{
// type: 'rtmp/flv',
// src: 'rtmp://127.0.0.1:1935/live/soures',
type: route.query.type??'application/x-mpegURL',
src: route.query.url??'http://127.0.0.1/live_hls/soures.m3u8',
}],
flash: {
swf: 'https://cnd.bootcdn.net/ajax/libs/videojs-swf/5.4.2/video-js.swf',
}
},() => {
console.log("加载完成!");
nextTick(() => {
player.src([{ type: 'application/x-mpegURL', src: route.query.url}]);
player.play();
});
}
}
})
</script>
<style lang="less" scoped>

View File

@ -6,7 +6,7 @@ export function getDefOptions(object) {
// const windowObj = <any>window;
// const WebRtcStreamer = windowObj.WebRtcStreamer;
let o = {
autoplay: true,
autoplay: false,
controls: true,
muted: true,
errorDisplay: false,

View File

@ -20,7 +20,8 @@
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount} from 'vue';
import { propTypes } from '/@/utils/propTypes';
import { getDefOptions } from './util.ts';
import { getDefOptions } from '/@/views/site/common/video/videojs/util';
import videojs from "video.js";
import "video.js/dist/video-js.css";
@ -33,18 +34,25 @@ const props = defineProps({
});
const player = ref();
const emit = defineEmits(['loadEnd']);
onMounted(() => {
let sources = [ { type: props.type, src: props.src, } ];
let playerMain = <any> videojs(props.videoId, getDefOptions(Object.assign({ sources },props.videoOption)),() => {
let option = {};
if(props.src){
option = {
sources: [ { type: props.type, src: props.src, } ]
};
}
let playerMain = <any> videojs(props.videoId, getDefOptions(Object.assign(option, props.videoOption)),() => {
console.log("加载完成!",playerMain,props.videoOption);
playerMain.on('pause', function(...d) {
console.log('点击了??',...d);
emit('loadEnd',playerMain);
// playerMain.on('pause', function(...d) {
// console.log('',...d);
// myAwesomePlayer.play();
// ...so you can do here all the stuff you want while the video is playing
});
// });
});
player.value = playerMain;

View File

@ -0,0 +1,144 @@
<template>
<div style="width:100%;height: 100%;" v-if="!isError">
<a-row>
<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 tableData" class="videoMax">
<a-card :title="item?.xm" class="videoCardMain">
<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-'+index" :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>
</div>
<div v-else style="height: 100%;display: flex;justify-content: center;align-items: center;">
<a-empty>
<template #description>
<span>
没有找到直播间
</span>
</template>
<!-- <a-button type="primary" @="">关闭</a-button> -->
</a-empty>
</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 { useRoute } from 'vue-router'
const bVideoRefs = <any>ref([]);
const mainVideo = <any>ref();
const currentItem = <any>ref({});
const isfirst = <any>ref(false);
const mainVideoCardBoxTitle = <any>ref('');
const tableData = ref<Recordable>([])
const isError = ref(false);
const route = useRoute();
onMounted(() => {
if(route.query.id){
//ID
list({ pageSize: -1, sfyx: '0', jsbh: route.query.id }).then(res => {
let list = (res?.records) ?? [];
tableData.value = list;
nextTick(() => {
})
});
}else{
isError.value = true;
}
// 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 });
/**
* 子页加载完成后回调
* @param player
*/
function loadEnd(player){
nextTick(() => {
if(!isfirst.value){
isfirst.value = true;
//
bVideoClick({ target: { playerId: player.id() } })
}
});
}
/**
* 点击时切换至大屏
* @param e
*/
function bVideoClick(e){
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;
}
</style>

View File

@ -35,11 +35,11 @@
<div style="height: 60px;">
{{ item.skdd }}
</div>
</a-col>
</a-col>
<a-col :span="24" v-if="listType == 1">
<a-row style="text-align: center;">
<a-col :span="8">
<a-button type="primary" class="yyyClass" disabled >听课</a-button>
<a-button type="primary" class="yyyClass" @click="toLivePage(item)">听课</a-button>
</a-col>
<a-col :span="8">
<a-button type="primary" class="yyClass" @click="funpingjia(item)" >评价</a-button>
@ -73,12 +73,14 @@ import { useMessage } from '/@/hooks/web/useMessage';
import KcErrorreportIndexModal from '/@/views/kc/kcErrorreport/components/KcErrorreportIndexModal.vue'
import { getUserId } from '/@/views/site/utils/index';
import addModalPage from '/@/views/site/tingKeZuJi/components/addModal.vue';
import { useRouter } from 'vue-router'
//
import { useUserStore } from '/@/store/modules/user';
const userStore = useUserStore();
const kcErrorreportIndexModal = ref();
const tingKeZuJiAddModal = ref();
const route = useRouter();
const emit = defineEmits(['setTotal']);
@ -91,7 +93,7 @@ const list = (params) => defHttp.get({ url: '/ktgl/kcKetangbiao/getKclblist', pa
const props = defineProps({
queryParam:{type:Object}
});
//
watch(() => props.queryParam, async (newRow, oldRow) => {
var newRowa = ref<any>({});
@ -142,6 +144,12 @@ function handleBaocuo(item) {
kcErrorreportIndexModal.value.add(item);
}
function toLivePage(item){
// route.push({ path:'/site/liveRoom',query:{ id: item.jsbh } })
let routeData = route.resolve({ path:'/site/liveRoom',query:{ id: item.jsbh } });
window.open(routeData.href, '_blank');
};
enum Api {
list = '/kcYuyue/kcYuyue/list',
save='/kcYuyue/kcYuyue/add',