2023年4月24日 修改直播,
This commit is contained in:
parent
69deb2409a
commit
531ed0f6d7
|
@ -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: '直播课堂',
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
],
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue