feat: 新增直播功能及相关组件

实现以下功能:
1. 在首页展示直播信息,支持点击进入直播间。
2. 添加获取直播流的API调用,动态更新直播数据。
3. 优化直播视图组件,调整样式以提升用户体验。
4. 代码格式化和注释优化,提升可读性。
This commit is contained in:
yindongqi 2025-08-05 17:36:59 +08:00
parent d24052d24b
commit 0d5a7d6d5d
4 changed files with 7301 additions and 7598 deletions

View File

@ -23,6 +23,7 @@
"exif-js": "^2.3.0",
"font-awesome": "^4.7.0",
"mint-ui": "^2.2.13",
"qnweb-rtc": "^4.3.1",
"qrcodejs2": "^0.0.2",
"regenerator-runtime": "^0.14.1",
"simple-peer": "^9.11.1",

View File

@ -11,6 +11,15 @@
<img src="../../static/lead/8.png" class="img8" v-if="step == 8"/>
<img src="../../static/lead/9.png" class="img9" v-if="step == 9"/>
</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>
<div class="all">
<div class="top">
@ -47,8 +56,8 @@
<p class="kechenginfoR_bt">{{ item.name }}</p>
<p class="kechenginfoR_xbt">{{ item.description }}</p>
<div class="kechenginfoR_bot">
<div class="kechenginfoR_botL"><img src="../../static/img/yanjing.png" alt=""
class="yanjing">{{ item.page_view }}</div>
<div class="kechenginfoR_botL"><img src="../../static/img/yanjing.png" alt="" class="yanjing">{{
item.page_view }}</div>
<div class="kechenginfoR_botR" @click="goCourseDetail(item.id)">进入课程</div>
</div>
</div>
@ -72,7 +81,9 @@ export default {
return {
company: {},
course: [],
step: 0
step: 0,
haveLive: false,
liveData: [],
}
},
created() {
@ -80,6 +91,7 @@ export default {
mounted() {
this.getPageData();
this.getLiveStreams();
},
methods: {
goCourseDetail(id) {
@ -124,6 +136,22 @@ export default {
},
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() {
if (this.step == 9) {
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>

View File

@ -62,7 +62,7 @@
{{ loginInfo.member_realname }}_{{ loginInfo.member_passport }}
</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 v-for="(teacherAudio, index) in teacherAudioList" class="teacherAudio">
{{ teacherAudio.name }}
@ -192,7 +192,7 @@
/>
</svg>
</div>
</div>
</div> -->
</div>
<div class="menubar">
<div class="menubar-one">
@ -309,7 +309,7 @@ import { getStore } from "@/utils/storage";
import { mapState } from "vuex";
import { MessageBox } from "mint-ui";
import { v4 as uuidv4 } from "uuid";
QNRTC.setLogLevel(QNLogLevel.NONE);
// QNRTC.setLogLevel(QNLogLevel.NONE);
export default {
components: { Back },
data() {
@ -467,11 +467,16 @@ export default {
}
videoTracks[index].play(this.liveContent);
// 使 setTimeout
setTimeout(() => {
const videos = document.querySelectorAll(
"video.qnrtc-video-player.qnrtc-stream-player"
);
// controls
for (let i = 0; i < videos.length; i++) {
videos[i].controls = true;
//
videos[i].style.pointerEvents = "auto";
//
videos[i].disablePictureInPicture = true;
//
@ -486,6 +491,7 @@ export default {
this.isVisible = true;
}, 10000);
}
}, 100);
} else if (videoTracks[index].tag === "video") {
const teacherCameraElement = this.$refs.teacherCamera;
// <video>

14793
yarn.lock

File diff suppressed because it is too large Load Diff