feat: 新增直播功能及相关组件
实现以下功能: 1. 在首页展示直播信息,支持点击进入直播间。 2. 添加获取直播流的API调用,动态更新直播数据。 3. 优化直播视图组件,调整样式以提升用户体验。 4. 代码格式化和注释优化,提升可读性。
This commit is contained in:
parent
d24052d24b
commit
0d5a7d6d5d
@ -23,6 +23,7 @@
|
|||||||
"exif-js": "^2.3.0",
|
"exif-js": "^2.3.0",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"mint-ui": "^2.2.13",
|
"mint-ui": "^2.2.13",
|
||||||
|
"qnweb-rtc": "^4.3.1",
|
||||||
"qrcodejs2": "^0.0.2",
|
"qrcodejs2": "^0.0.2",
|
||||||
"regenerator-runtime": "^0.14.1",
|
"regenerator-runtime": "^0.14.1",
|
||||||
"simple-peer": "^9.11.1",
|
"simple-peer": "^9.11.1",
|
||||||
|
@ -11,6 +11,15 @@
|
|||||||
<img src="../../static/lead/8.png" class="img8" v-if="step == 8"/>
|
<img src="../../static/lead/8.png" class="img8" v-if="step == 8"/>
|
||||||
<img src="../../static/lead/9.png" class="img9" v-if="step == 9"/>
|
<img src="../../static/lead/9.png" class="img9" v-if="step == 9"/>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
<div class="cover" v-if="haveLive">
|
||||||
|
<div class="live_box" v-for="live in liveData" @click="goLive(live.room)">
|
||||||
|
<div>{{ live.title }}</div>
|
||||||
|
<br />
|
||||||
|
<div class="stream_info">
|
||||||
|
<p>開始時間:{{ live.start_time }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<common-top></common-top>
|
<common-top></common-top>
|
||||||
<div class="all">
|
<div class="all">
|
||||||
<div class="top">
|
<div class="top">
|
||||||
@ -47,8 +56,8 @@
|
|||||||
<p class="kechenginfoR_bt">{{ item.name }}</p>
|
<p class="kechenginfoR_bt">{{ item.name }}</p>
|
||||||
<p class="kechenginfoR_xbt">{{ item.description }}</p>
|
<p class="kechenginfoR_xbt">{{ item.description }}</p>
|
||||||
<div class="kechenginfoR_bot">
|
<div class="kechenginfoR_bot">
|
||||||
<div class="kechenginfoR_botL"><img src="../../static/img/yanjing.png" alt=""
|
<div class="kechenginfoR_botL"><img src="../../static/img/yanjing.png" alt="" class="yanjing">{{
|
||||||
class="yanjing">{{ item.page_view }}人</div>
|
item.page_view }}人</div>
|
||||||
<div class="kechenginfoR_botR" @click="goCourseDetail(item.id)">进入课程</div>
|
<div class="kechenginfoR_botR" @click="goCourseDetail(item.id)">进入课程</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -72,7 +81,9 @@ export default {
|
|||||||
return {
|
return {
|
||||||
company: {},
|
company: {},
|
||||||
course: [],
|
course: [],
|
||||||
step: 0
|
step: 0,
|
||||||
|
haveLive: false,
|
||||||
|
liveData: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -80,6 +91,7 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
|
|
||||||
this.getPageData();
|
this.getPageData();
|
||||||
|
this.getLiveStreams();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goCourseDetail(id) {
|
goCourseDetail(id) {
|
||||||
@ -124,6 +136,22 @@ export default {
|
|||||||
},
|
},
|
||||||
err => { })
|
err => { })
|
||||||
},
|
},
|
||||||
|
getLiveStreams() {
|
||||||
|
this.getData("/Membervideo/getLiveStreams", { token: getStore("token") }).then(
|
||||||
|
(data) => {
|
||||||
|
if (data.code == 1) {
|
||||||
|
if (data.data.length > 0) {
|
||||||
|
this.haveLive = true;
|
||||||
|
this.liveData = data.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(err) => {}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
goLive(room) {
|
||||||
|
this.$router.push({ path: "/liveview?roomName=" + room });
|
||||||
|
},
|
||||||
nextLead() {
|
nextLead() {
|
||||||
if (this.step == 9) {
|
if (this.step == 9) {
|
||||||
this.step = 0
|
this.step = 0
|
||||||
@ -295,4 +323,25 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cover {
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.live_box {
|
||||||
|
background-color: white;
|
||||||
|
width: 25rem;
|
||||||
|
box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
|
||||||
|
margin: 3rem;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
// display: flex;
|
||||||
|
// flex-direction: column;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
{{ loginInfo.member_realname }}_{{ loginInfo.member_passport }}
|
{{ loginInfo.member_realname }}_{{ loginInfo.member_passport }}
|
||||||
</div>
|
</div>
|
||||||
<div id="teacherCamera" class="teacherCamera" ref="teacherCamera"></div>
|
<div id="teacherCamera" class="teacherCamera" ref="teacherCamera"></div>
|
||||||
<div class="custom-controls" v-show="showControlBar">
|
<!-- <div class="custom-controls" v-show="showControlBar">
|
||||||
<div class="teacherAudioList" v-show="teacherAudioList.length > 0">
|
<div class="teacherAudioList" v-show="teacherAudioList.length > 0">
|
||||||
<div v-for="(teacherAudio, index) in teacherAudioList" class="teacherAudio">
|
<div v-for="(teacherAudio, index) in teacherAudioList" class="teacherAudio">
|
||||||
{{ teacherAudio.name }}
|
{{ teacherAudio.name }}
|
||||||
@ -192,7 +192,7 @@
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="menubar">
|
<div class="menubar">
|
||||||
<div class="menubar-one">
|
<div class="menubar-one">
|
||||||
@ -309,7 +309,7 @@ import { getStore } from "@/utils/storage";
|
|||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
import { MessageBox } from "mint-ui";
|
import { MessageBox } from "mint-ui";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
QNRTC.setLogLevel(QNLogLevel.NONE);
|
// QNRTC.setLogLevel(QNLogLevel.NONE);
|
||||||
export default {
|
export default {
|
||||||
components: { Back },
|
components: { Back },
|
||||||
data() {
|
data() {
|
||||||
@ -467,11 +467,16 @@ export default {
|
|||||||
}
|
}
|
||||||
videoTracks[index].play(this.liveContent);
|
videoTracks[index].play(this.liveContent);
|
||||||
|
|
||||||
|
// 使用 setTimeout 确保视频元素完全创建后再设置控件
|
||||||
|
setTimeout(() => {
|
||||||
const videos = document.querySelectorAll(
|
const videos = document.querySelectorAll(
|
||||||
"video.qnrtc-video-player.qnrtc-stream-player"
|
"video.qnrtc-video-player.qnrtc-stream-player"
|
||||||
);
|
);
|
||||||
// 遍历这些元素并添加 controls 属性
|
// 遍历这些元素并添加 controls 属性
|
||||||
for (let i = 0; i < videos.length; i++) {
|
for (let i = 0; i < videos.length; i++) {
|
||||||
|
videos[i].controls = true;
|
||||||
|
// 确保控件可见
|
||||||
|
videos[i].style.pointerEvents = "auto";
|
||||||
//关闭画中画
|
//关闭画中画
|
||||||
videos[i].disablePictureInPicture = true;
|
videos[i].disablePictureInPicture = true;
|
||||||
// 打破视频宽高比,全部填充
|
// 打破视频宽高比,全部填充
|
||||||
@ -486,6 +491,7 @@ export default {
|
|||||||
this.isVisible = true;
|
this.isVisible = true;
|
||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
|
}, 100);
|
||||||
} else if (videoTracks[index].tag === "video") {
|
} else if (videoTracks[index].tag === "video") {
|
||||||
const teacherCameraElement = this.$refs.teacherCamera;
|
const teacherCameraElement = this.$refs.teacherCamera;
|
||||||
// 获取所有子元素中的 <video> 标签
|
// 获取所有子元素中的 <video> 标签
|
||||||
|
Loading…
x
Reference in New Issue
Block a user