前端项目开发
1. 首页显示全部课程
<template>
<div>
<Header></Header>
<div
style="width: 850PX;display: inline-block; margin:0px auto;">
<el-tabs v-model="activeName">
<el-tab-pane label="选课" name="allLesson">
<ul class="course-ul-pc">
<!-- 课程信息展示开始 -->
<li class="course-li" v-for="(course,index) in courseList" :key="index">
<!-- 课程封面图 -->
<img
src="course.courseImgUrl"
class="teacher-portrait hover-pointer"
/>
<!-- 课程文字信息 -->
<div class="content-main">
<!-- 课程标题 -->
<div class="content-title hover-pointer">
<div
class="p-title"
style="text-align:left;"
@click="gotoDetail"
>
<span>
{{course.courseName}}
</span>
</div>
<!-- 作者和职称 -->
<p class="p-title-buy text-overflow">
<span class="p-author-span">
{{course.teacher.teacherName}}
</span>
<span class="p-author-line" />
<span class="p-author-span">
{{course.teacher.position}}
</span>
</p>
<p></p>
<!-- 课程简单描述 -->
<p class="p-describe" style="text-align:left;">
{{course.brief}}
</p>
</div>
<!-- 课程前两个章节信息 -->
<ul class="content-course" style="text-align:left;">
<!-- 章节1 通常是第一章的前两节课-->
<li
class="content-course-lesson text-overflow"
style="width:300px"
v-for="(lesson,index) in course.courseSections[0].courseLessons.slice(0,2)"
:key="index"
>
<!-- 免费试看图标 -->
<img
src="@/assets/course-list/free-course.png"
class="free-label hover-pointer"
/>
<span class="theme-span hover-pointer">
{{lesson.theme}}
</span>
</li>
</ul>
<!-- 价格信息 -->
<div class="content-price" style="text-align:left;">
<p class="content-price-p">
<span class="content-price-orange-sm">¥</span>
<span class="content-price-orange">{{course.discounts}}</span>
<span class="current-price">
<span class="current-price-unite">¥</span>
{{course.price}}
</span>
<span class="activity-name">成就自己</span>
<span class="content-price-buy">{{course.sales}}人购买</span>
</p>
<div class="btn btn-green btn-offset">立即购买</div>
</div>
</div>
</li>
<!-- 课程信息结束 -->
</ul>
</el-tab-pane>
<el-tab-pane label="已购" name="hasPay">
<img
src="@/assets/course-list/no-login@2x.png"
class="no-data-icon"
/>
<div class="no-data-title">您还没有登录</div>
<div class="no-data-title">登录后即可查看已购课程</div>
<div class="btn btn-yellow btn-center">立即登录</div>
</el-tab-pane>
</el-tabs>
</div>
<Footer></Footer>
</div>
</template>
<script>
import Header from "./Header/Header"; //顶部登录条
import Footer from "./Footer/index"; //顶部登录条
export default {
name: "Index",
components: {
Header,
Footer,
},
data() {
return {
activeName: "allLesson",
courseList:[]// 选购课程信息
};
},
created() {
this.getCourseList();
},
methods: {
changeCourseTab(tabName) {
this.classSelect = tabName;
sessionStorage && sessionStorage.setItem("courseTab", tabName);
},
gotoDetail() {
this.$router.push({ name: "Course", params: { courseid: 1 } });
},
// 获取所有课程列表
getCourseList(){
return this.axios.get("http://localhost:8002/course/getAllCourse")
.then(res=>{
this.courseList=res.data;
console.log(res.data);
}).catch(err=>{
this.$message.error("获取失败");
});
}
},
};
</script>
<style lang="less" scoped>
@import "../assets/less/common.less";
p {
margin-top: 0;
}
li {
list-style: none;
}
flex {
display: flex;
}
.btn(@a, @b) {
background-color: @a;
color: @b;
border: 1px solid @a;
}
.course-ads {
margin-bottom: 20px;
cursor: pointer;
width: 100%;
max-height: 280px;
overflow: hidden;
img {
width: 100%;
border-radius: 2px;
}
}
.tab-container {
width: 100%;
height: 60px;
background: #ffffff;
border-bottom: 1px solid #ededed;
}
.vux-tab.course-tab {
box-sizing: border-box;
height: 60px;
width: 200px;
overflow: hidden;
font-size: 20px;
.vux-tab-container {
width: 260px;
}
.vux-tab-item {
cursor: pointer;
background: none;
line-height: 60px;
font-size: 20px;
}
.vux-tab-ink-bar {
bottom: -1px;
.vux-tab-bar-inner {
height: 2px;
}
}
}
.tab-container {
width: 100%;
height: 60px;
background: #ffffff;
border-bottom: 1px solid #ededed;
}
.course-ul {
padding: 0 20px;
}
.hover-pointer {
cursor: pointer;
}
.course-ul-pc .course-li {
padding: 30px 0 40px 0;
border-bottom: 1px solid #ededed;
position: relative;
&:last-child {
border-bottom: 0;
}
}
.current-price {
font-size: 12px;
color: #999;
font-weight: 600;
text-decoration: line-through;
}
.current-price-unite {
font-size: 12px;
margin-right: -4px;
}
.p-author-line {
content: "";
display: inline-block;
width: 1px;
height: 10px;
position: absolute;
background: #999;
margin-left: 5px;
top: 3px;
}
.teacher-portrait {
width: 121px;
height: 159px;
border-radius: 4px;
float: left;
}
.content-main {
line-height: 1.4;
margin-left: 141px;
position: relative;
height: 150px;
}
.content-main .p-title {
font-size: 20px;
color: #333;
font-family: PingFangSC-Medium, PingFang SC;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 350px;
}
.course-ul-pc .content-main .p-title-buy {
font-size: 12px;
color: #999;
display: inline-block;
margin-top: 6px;
position: relative;
float: right;
top: -28px;
font-weight: 400;
}
p {
margin-top: 0;
}
.course-ul-pc .p-author-line {
content: "";
display: inline-block;
width: 1px;
height: 10px;
position: absolute;
background: #999;
margin-left: 5px;
top: 3px;
}
.text-overflow {
word-wrap: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.course-ul-pc .content-main .p-describe {
font-size: 14px;
margin-top: 5px;
color: #333;
word-wrap: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.course-ul-pc .content-main .p-author-span:not(:first-child) {
margin-left: 18px;
}
.course-ul-pc .content-main .content-course {
font-size: 14px;
padding-top: 25px;
color: #666;
}
ol,
ul {
margin: 0;
padding: 0;
list-style: none;
}
* {
-webkit-tap-highlight-color: transparent;
}
.course-ul-pc .content-main .content-course-lesson {
display: inline-block;
width: 304px;
margin: 2px 40px 6px 0;
}
.course-ul-pc .content-main .content-course .free-label {
width: 50px;
height: 16px;
margin: 1px 5px 0 0;
}
.course-ul-pc .content-main .content-course-lesson:nth-child(2n) {
margin-right: 0;
}
.course-ul-pc .content-main .content-course-lesson {
display: inline-block;
width: 304px;
margin: 2px 40px 6px 0;
}
.course-ul-pc .content-main .content-price {
height: 28px;
line-height: 28px;
position: absolute;
width: 100%;
bottom: -4px;
}
.course-ul-pc .content-main .content-price-p {
font-size: 0;
}
.course-ul-pc .content-main .content-price-orange-sm {
color: #ff7452;
font-size: 14px;
}
.content-course {
font-size: 14px;
padding-top: 25px;
color: #666;
}
.content-course.free-label {
width: 50px;
height: 16px;
margin: 1px 5px 0 0;
}
.content-course-lesson {
display: inline-block;
width: 304px;
margin: 2px 40px 6px 0;
}
.content-course-lesson:nth-child(2n) {
margin-right: 0;
}
.disabled-word {
color: #999;
cursor: default;
}
.theme-span :hover {
color: #0abf89;
}
.content-price-p {
font-size: 0;
}
.content-price-orange {
color: #ff7452;
font-size: 20px;
}
.content-price-buy {
font-size: 14px;
color: #999;
margin-left: 20px;
transform: translate(8px, -2px);
display: inline-block;
}
.content-price-grey {
color: #999;
font-size: 12px;
margin-left: 5px;
}
.content-price-buyed {
color: #999;
font-size: 14px;
}
.content-price {
height: 28px;
line-height: 28px;
position: absolute;
width: 100%;
bottom: -4px;
}
.activity-name {
font-size: 12px;
line-height: 14px;
color: rgba(255, 255, 255, 1);
padding: 2px 4px;
background: linear-gradient(
180deg,
rgba(255, 137, 110, 1) 0%,
rgba(255, 123, 92, 1) 100%
);
border-radius: 2px;
display: inline-block;
transform: translate(6px, -3px);
}
.p-title {
font-size: 20px;
color: #333;
font-family: PingFangSC-Medium, PingFang SC;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 350px;
}
.p-title-dec {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
.p-title-buy {
// .font(12px);
font-size: 12px;
color: #999;
display: inline-block;
margin-top: 6px;
position: relative;
// .fr;
top: -28px;
font-weight: normal;
}
.companion-reading {
background: rgba(0, 179, 138, 0.06);
border-radius: 2px;
font-family: PingFangSC-Regular;
font-size: 12px;
color: #00b38a;
display: inline-block;
padding: 0 8px;
height: 22px;
line-height: 22px;
margin-left: 10px;
vertical-align: text-bottom;
position: relative;
.triangle {
position: absolute;
top: 12px;
left: -3px;
width: 0;
height: 0;
content: "";
border: 5px solid;
border-color: transparent transparent white white;
transform: rotate(45deg);
box-shadow: -2px 2px 2px rgba(0, 0, 0, 0.08);
}
}
.companion-tip {
display: none;
position: absolute;
font-family: HiraginoSansGB-W3;
font-size: 14px;
color: #777777;
background: #ffffff;
border: 1px solid #e3ebe9;
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.08);
border-radius: 3px;
line-height: 29px;
top: -7px;
word-break: keep-all;
left: 80px;
padding: 0 10px;
width: 200px;
z-index: 2;
}
.companion-reading:hover .companion-tip {
display: inline-block;
}
.companion-reading:hover .companion-tip {
display: block;
}
.p-describe {
// .font(14px);
font-size: 14px;
margin-top: 5px;
color: #333;
// .text-overflow;
}
.p-author + p {
margin-top: 0;
}
.p-author {
margin: 10px 0 5px 0;
// .font(12px);
font-size: 12px;
color: #999;
position: relative;
.p-author-line {
content: "";
display: inline-block;
width: 1px;
height: 10px;
position: absolute;
background: #999;
margin-left: 5px;
top: 3px;
}
}
.p-author-span:not(:first-child) {
margin-left: 18px;
}
.course-ul-container {
width: 850px;
display: inline-block;
float: left;
}
.course-ul {
padding: 0 20px;
}
.course-ul-pc {
width: 790px;
background-color: #fff;
padding: 0 30px;
// .fl;
}
.tag-icon {
width: 57px;
height: 18px;
position: absolute;
top: 30px;
left: 0;
}
.more-icon {
width: 10px;
height: 10px;
vertical-align: middle;
}
.btn {
width: 94px;
height: 34px;
text-align: center;
line-height: 34px;
cursor: pointer;
border-radius: 3px;
font-size: 14px;
box-sizing: content-box;
&-green {
.btn(#00b38a, #fff);
&:hover {
background: #00a57f;
border-color: #00a57f;
}
}
&-yellow {
.btn(#fcd766, #fff);
&:hover {
background: #fcd766;
border-color: #fcd766;
}
}
&-white {
.btn(#fff, #00b38a);
border: 1px solid #00b38a;
&:hover {
color: #fff;
border-color: #00b38a;
background-color: #00b38a;
}
}
&-offset {
position: absolute;
right: 0;
top: -4px;
}
}
.btn-center {
margin: 10px auto;
}
.no-data-title {
font-size: 20px;
color: #333;
font-weight: 500;
}
</style>
2. 登录
<template> <div class="header-pc-wrap"> <!-- 登录框 开始--> <el-dialog style="width:800px;margin:0px auto;" title="" :visible.sync="dialogFormVisible" > <el-form> <el-form-item> <h1 style="font-size:30px;color:#00B38A">拉勾</h1> </el-form-item> <el-form-item> <el-input v-model="phone" placeholder="请输入常用手机号..." ></el-input> </el-form-item> <el-form-item> <el-input v-model="password" placeholder="请输入密码..."></el-input> </el-form-item> </el-form> <el-button style="width:100%;margin:0px auto;background-color: #00B38A;font-size:20px" type="primary" @click="login" >确 定</el-button > <p></p> <!-- 微信登录图标 --> <img @click="goToLoginWX" src="http://www.lgstatic.com/lg-passport-fed/static/pc/modules/common/img/icon-wechat@2x_68c86d1.png" alt="" /> </el-dialog> <!-- 登录框 结束--> <!-- 顶部登录条 --> <div class="wrap-box"> <div @click="toToIndex" class="edu-icon"></div> <div @click="toToIndex" class="text">拉勾教育</div> <div class="right-var-wrap" v-if="!isLogin"> <div class="login-handler" @click="goToLogin">登录 | 注册</div> </div> <div class="right-var-wrap" v-if="isLogin"> <div :class="{ 'tip-icon': true, 'has-new-message': isHasNewMessage }" @click="toToNotic" > <i class="el-icon-bell"></i> </div> <img :src="userDTO.content.portrait" class="avatar-wrap" /> <div class="bar-wrap"> <ul class="account-bar"> <li class="user_dropdown" data-lg-tj-track-code="index_user"> <span class="unick">{{ userDTO.content.name }}</span> <i /> <ul style=""> <li @click="goToSetting"> 账号设置 </li> <li @click="logout"> 退出 </li> </ul> </li> </ul> </div> </div> </div> </div> </template> <script> export default { name: "Header", props: {}, data() { return { isLogin: false, // 登录状态,true:已登录,false:未登录 userDTO: null, // 用来保存登录的用户信息 isHasNewMessage: false, // 是否有新的推送消息 dialogFormVisible: false, // 是否显示登录框,true:显示,false:隐藏 phone: "", // 双向绑定表单 手机号 password: "", // 双向绑定表单 密码 }; }, computed: {}, watch: {}, mounted() {}, created() { // 当刷新页面,组件创建成功之后,立刻检测本地储存中是否存在用户对象 this.userDTO = JSON.parse(localStorage.getItem("user")); if (this.userDTO != null) { this.isLogin = true; // 已登录 } }, methods: { goToSetting() { this.$router.push("/setting"); // 跳转个人设置页面 }, goToLogin() { this.dialogFormVisible = true; // 显示登录框 }, goToLoginWX() { alert("微信登录"); }, toToIndex() { this.$router.push("/"); //回到首页 }, toToNotic() {}, login() { return this.axios .get("http://localhost:8002/user/login", { params: { phone: this.phone, password: this.password, }, }) .then((res) => { console.log(res.data); this.dialogFormVisible = false; //关闭登录框 this.userDTO = res.data; // 保存返回数据中的用户对象信息 this.isLogin = true; // 更新登录状态 localStorage.setItem("user", JSON.stringify(this.userDTO)); // 将登录成功的对象信息保存到本地储存中 }) .catch((err) => { this.$message.error("登录失败"); }); }, logout() { // 登出 localStorage.setItem("user", null); // 将登录成功的对象信息保存到本地储存中 this.isLogin = false; // 更新登录状态 alert("谢谢使用,再见!"); }, }, }; </script> <style lang="less" scoped> .header-pc-wrap { width: 100%; height: 40px; background: rgba(35, 39, 43, 1); } .wrap-box { width: 1200px; height: 100%; margin: 0 auto; } .edu-icon { float: left; width: 24px; height: 24px; background: url("./static/img/Icon@2x.png") no-repeat; background-size: 100% 100%; margin-top: 8px; } .text { font-size: 16px; font-weight: 500; color: rgba(255, 255, 255, 1); line-height: 40px; float: left; margin-left: 6px; } .login-handler { font-size: 12px; font-weight: 500; color: rgba(255, 255, 255, 1); line-height: 40px; float: left; cursor: pointer; } .right-var-wrap { float: right; font-size: 0; text-align: right; } .tip-icon, .avatar-wrap, .bar-wrap { display: inline-block; vertical-align: top; } .tip-icon { font-size: 16px; line-height: 40px; margin-right: 26px; color: #818895; cursor: pointer; &:hover { color: #fff; } &.has-new-message { position: relative; &:after { content: " "; display: inline-block; position: absolute; top: 50%; width: 6px; height: 6px; border-radius: 3px; background: red; right: 0; margin-top: -7px; } } } .user_dropdown { position: relative; cursor: pointer; font-size: 14px; text-align: center; &:hover { .unick { color: #fff; } i { -webkit-transform: rotate(180deg); -moz-transform: rotate(180deg); -ms-transform: rotate(180deg); -o-transform: rotate(180deg); transform: rotate(180deg); animation-fill-mode: forwards; border-color: #fff transparent transparent; } > ul { display: block; position: absolute; top: 40px; width: 100%; min-width: 80px; line-height: 30px; background-color: #32373e; z-index: 1000; list-style: none; margin: 0px; padding: 0px; > li { width: 100%; height: 30px; &:hover { background-color: #25282d; color: #fff; } } } } .unick { display: block; height: 40px; line-height: 40px; font-size: 14px; color: #afb5c0; max-width: 96px; margin: 0 9px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; word-wrap: normal; &:hover { color: #fff; } } > i { position: absolute; top: 17px; right: 0; font-size: 0; height: 0; width: 0; border-width: 5px 4px 0; border-style: solid dashed; border-color: #afb5c0 transparent transparent; overflow: hidden; -webkit-transition: all 0.4s ease 0s; -moz-transition: all 0.4s ease 0s; -ms-transition: all 0.4s ease 0s; -o-transition: all 0.4s ease 0s; transition: all 0.4s ease 0s; } > ul { display: none; color: #afb5c0; } } .avatar-wrap { width: 24px; height: 24px; margin-top: 8px; border-radius: 50%; } </style>
3. 已购课程
<template> <div> <Header></Header> <div style="width: 850PX;display: inline-block; margin:0px auto;"> <el-tabs v-model="activeName"> <el-tab-pane label="选课" name="allLesson"> <ul class="course-ul-pc"> <!-- 课程信息展示开始 --> <li class="course-li" v-for="(course, index) in courseList" :key="index" > <!-- 课程封面图 --> <img src="course.courseImgUrl" class="teacher-portrait hover-pointer" /> <!-- 课程文字信息 --> <div class="content-main"> <!-- 课程标题 --> <div class="content-title hover-pointer"> <div class="p-title" style="text-align:left;" @click="gotoDetail" > <span> {{ course.courseName }} </span> </div> <!-- 作者和职称 --> <p class="p-title-buy text-overflow"> <span class="p-author-span"> {{ course.teacher.teacherName }} </span> <span class="p-author-line" /> <span class="p-author-span"> {{ course.teacher.position }} </span> </p> <p></p> <!-- 课程简单描述 --> <p class="p-describe" style="text-align:left;"> {{ course.brief }} </p> </div> <!-- 课程前两个章节信息 --> <ul class="content-course" style="text-align:left;"> <!-- 章节1 通常是第一章的前两节课--> <li class="content-course-lesson text-overflow" style="width:300px" v-for="(lesson, index) in course.courseSections[0].courseLessons.slice( 0, 2 )" :key="index" > <!-- 免费试看图标 --> <img src="@/assets/course-list/free-course.png" class="free-label hover-pointer" /> <span class="theme-span hover-pointer"> {{ lesson.theme }} </span> </li> </ul> <!-- 价格信息 --> <div class="content-price" style="text-align:left;"> <p class="content-price-p"> <span class="content-price-orange-sm">¥</span> <span class="content-price-orange">{{ course.discounts }}</span> <span class="current-price"> <span class="current-price-unite">¥</span> {{ course.price }} </span> <span class="activity-name">成就自己</span> <span class="content-price-buy" >{{ course.sales }}人购买</span > </p> <div class="btn btn-green btn-offset">立即购买</div> </div> </div> </li> <!-- 课程信息结束 --> </ul> </el-tab-pane> <el-tab-pane label="已购" name="hasPay"> <div v-if="!isLogin"> <img src="@/assets/course-list/no-login@2x.png" class="no-data-icon" /> <div class="no-data-title">您还没有登录</div> <div class="no-data-title">登录后即可查看已购课程</div> <div class="btn btn-yellow btn-center">立即登录</div> </div> <div v-if="isLogin"> <ul class="course-ul-pc"> <!-- 课程信息展示开始 --> <li class="course-li" v-for="(course, index) in myCourseList" :key="index" > <!-- 课程封面图 --> <img src="course.courseImgUrl" class="teacher-portrait hover-pointer" /> <!-- 课程文字信息 --> <div class="content-main"> <!-- 课程标题 --> <div class="content-title hover-pointer"> <div class="p-title" style="text-align:left;" @click="gotoDetail" > <span> {{ course.courseName }} </span> </div> <!-- 作者和职称 --> <p class="p-title-buy text-overflow"> <span class="p-author-span"> {{ course.teacher.teacherName }} </span> <span class="p-author-line" /> <span class="p-author-span"> {{ course.teacher.position }} </span> </p> <p></p> <!-- 课程简单描述 --> <p class="p-describe" style="text-align:left;"> {{ course.brief }} </p> </div> <!-- 课程前两个章节信息 --> <ul class="content-course" style="text-align:left;"> <!-- 章节1 通常是第一章的前两节课--> <li class="content-course-lesson text-overflow" style="width:300px" v-for="(lesson, index) in course.courseSections[0].courseLessons.slice( 0, 2 )" :key="index" > <!-- 免费试看图标 --> <img src="@/assets/course-list/free-course.png" class="free-label hover-pointer" /> <span class="theme-span hover-pointer"> {{ lesson.theme }} </span> </li> </ul> <!-- 价格信息 --> <div class="content-price" style="text-align:left;"> <p class="content-price-p"> <span class="content-price-orange-sm">¥</span> <span class="content-price-orange">{{ course.discounts }}</span> <span class="current-price"> <span class="current-price-unite">¥</span> {{ course.price }} </span> <span class="activity-name">成就自己</span> <span class="content-price-buy" >{{ course.sales }}人购买</span > </p> <div class="btn btn-yellow btn-offset">开始学习</div> </div> </div> </li> <!-- 课程信息结束 --> </ul> </div> </el-tab-pane> </el-tabs> </div> <Footer></Footer> </div> </template> <script> import Header from "./Header/Header"; //顶部登录条 import Footer from "./Footer/index"; //顶部登录条 export default { name: "Index", components: { Header, Footer, }, data() { return { activeName: "allLesson", courseList: [], // 选购课程信息 isLogin: false, //登录状态 user:null,// 登录的用户对象 myCourseList:[]// 已登录用户购买的课程集合 }; }, created() { this.getCourseList();//当组件创建完毕,就调用获取课程的方法 this.user=JSON.parse(localStorage.getItem("user")); if(this.user!=null){ this.isLogin=true;// 改变登录状态 this.getMyCourseList();//查询已经用户购买过的课程列表 } }, methods: { changeCourseTab(tabName) { this.classSelect = tabName; sessionStorage && sessionStorage.setItem("courseTab", tabName); }, gotoDetail() { this.$router.push({ name: "Course", params: { courseid: 1 } }); }, // 获取所有课程列表 getCourseList() { return this.axios .get("http://localhost:8002/course/getAllCourse") .then((res) => { this.courseList = res.data; console.log(res.data); }) .catch((err) => { this.$message.error("获取失败"); }); }, getMyCourseList() { return this.axios .get("http://localhost:8002/course/getCourseByUserId/"+this.user.content.id) .then((res) => { this.myCourseList = res.data; console.log(res.data); }) .catch((err) => { this.$message.error("获取失败"); }); }, }, }; </script> <style lang="less" scoped> @import "../assets/less/common.less"; p { margin-top: 0; } li { list-style: none; } flex { display: flex; } .btn(@a, @b) { background-color: @a; color: @b; border: 1px solid @a; } .course-ads { margin-bottom: 20px; cursor: pointer; width: 100%; max-height: 280px; overflow: hidden; img { width: 100%; border-radius: 2px; } } .tab-container { width: 100%; height: 60px; background: #ffffff; border-bottom: 1px solid #ededed; } .vux-tab.course-tab { box-sizing: border-box; height: 60px; width: 200px; overflow: hidden; font-size: 20px; .vux-tab-container { width: 260px; } .vux-tab-item { cursor: pointer; background: none; line-height: 60px; font-size: 20px; } .vux-tab-ink-bar { bottom: -1px; .vux-tab-bar-inner { height: 2px; } } } .tab-container { width: 100%; height: 60px; background: #ffffff; border-bottom: 1px solid #ededed; } .course-ul { padding: 0 20px; } .hover-pointer { cursor: pointer; } .course-ul-pc .course-li { padding: 30px 0 40px 0; border-bottom: 1px solid #ededed; position: relative; &:last-child { border-bottom: 0; } } .current-price { font-size: 12px; color: #999; font-weight: 600; text-decoration: line-through; } .current-price-unite { font-size: 12px; margin-right: -4px; } .p-author-line { content: ""; display: inline-block; width: 1px; height: 10px; position: absolute; background: #999; margin-left: 5px; top: 3px; } .teacher-portrait { width: 121px; height: 159px; border-radius: 4px; float: left; } .content-main { line-height: 1.4; margin-left: 141px; position: relative; height: 150px; } .content-main .p-title { font-size: 20px; color: #333; font-family: PingFangSC-Medium, PingFang SC; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 350px; } .course-ul-pc .content-main .p-title-buy { font-size: 12px; color: #999; display: inline-block; margin-top: 6px; position: relative; float: right; top: -28px; font-weight: 400; } p { margin-top: 0; } .course-ul-pc .p-author-line { content: ""; display: inline-block; width: 1px; height: 10px; position: absolute; background: #999; margin-left: 5px; top: 3px; } .text-overflow { word-wrap: normal; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } .course-ul-pc .content-main .p-describe { font-size: 14px; margin-top: 5px; color: #333; word-wrap: normal; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } .course-ul-pc .content-main .p-author-span:not(:first-child) { margin-left: 18px; } .course-ul-pc .content-main .content-course { font-size: 14px; padding-top: 25px; color: #666; } ol, ul { margin: 0; padding: 0; list-style: none; } * { -webkit-tap-highlight-color: transparent; } .course-ul-pc .content-main .content-course-lesson { display: inline-block; width: 304px; margin: 2px 40px 6px 0; } .course-ul-pc .content-main .content-course .free-label { width: 50px; height: 16px; margin: 1px 5px 0 0; } .course-ul-pc .content-main .content-course-lesson:nth-child(2n) { margin-right: 0; } .course-ul-pc .content-main .content-course-lesson { display: inline-block; width: 304px; margin: 2px 40px 6px 0; } .course-ul-pc .content-main .content-price { height: 28px; line-height: 28px; position: absolute; width: 100%; bottom: -4px; } .course-ul-pc .content-main .content-price-p { font-size: 0; } .course-ul-pc .content-main .content-price-orange-sm { color: #ff7452; font-size: 14px; } .content-course { font-size: 14px; padding-top: 25px; color: #666; } .content-course.free-label { width: 50px; height: 16px; margin: 1px 5px 0 0; } .content-course-lesson { display: inline-block; width: 304px; margin: 2px 40px 6px 0; } .content-course-lesson:nth-child(2n) { margin-right: 0; } .disabled-word { color: #999; cursor: default; } .theme-span :hover { color: #0abf89; } .content-price-p { font-size: 0; } .content-price-orange { color: #ff7452; font-size: 20px; } .content-price-buy { font-size: 14px; color: #999; margin-left: 20px; transform: translate(8px, -2px); display: inline-block; } .content-price-grey { color: #999; font-size: 12px; margin-left: 5px; } .content-price-buyed { color: #999; font-size: 14px; } .content-price { height: 28px; line-height: 28px; position: absolute; width: 100%; bottom: -4px; } .activity-name { font-size: 12px; line-height: 14px; color: rgba(255, 255, 255, 1); padding: 2px 4px; background: linear-gradient( 180deg, rgba(255, 137, 110, 1) 0%, rgba(255, 123, 92, 1) 100% ); border-radius: 2px; display: inline-block; transform: translate(6px, -3px); } .p-title { font-size: 20px; color: #333; font-family: PingFangSC-Medium, PingFang SC; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 350px; } .p-title-dec { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; } .p-title-buy { // .font(12px); font-size: 12px; color: #999; display: inline-block; margin-top: 6px; position: relative; // .fr; top: -28px; font-weight: normal; } .companion-reading { background: rgba(0, 179, 138, 0.06); border-radius: 2px; font-family: PingFangSC-Regular; font-size: 12px; color: #00b38a; display: inline-block; padding: 0 8px; height: 22px; line-height: 22px; margin-left: 10px; vertical-align: text-bottom; position: relative; .triangle { position: absolute; top: 12px; left: -3px; width: 0; height: 0; content: ""; border: 5px solid; border-color: transparent transparent white white; transform: rotate(45deg); box-shadow: -2px 2px 2px rgba(0, 0, 0, 0.08); } } .companion-tip { display: none; position: absolute; font-family: HiraginoSansGB-W3; font-size: 14px; color: #777777; background: #ffffff; border: 1px solid #e3ebe9; box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.08); border-radius: 3px; line-height: 29px; top: -7px; word-break: keep-all; left: 80px; padding: 0 10px; width: 200px; z-index: 2; } .companion-reading:hover .companion-tip { display: inline-block; } .companion-reading:hover .companion-tip { display: block; } .p-describe { // .font(14px); font-size: 14px; margin-top: 5px; color: #333; // .text-overflow; } .p-author + p { margin-top: 0; } .p-author { margin: 10px 0 5px 0; // .font(12px); font-size: 12px; color: #999; position: relative; .p-author-line { content: ""; display: inline-block; width: 1px; height: 10px; position: absolute; background: #999; margin-left: 5px; top: 3px; } } .p-author-span:not(:first-child) { margin-left: 18px; } .course-ul-container { width: 850px; display: inline-block; float: left; } .course-ul { padding: 0 20px; } .course-ul-pc { width: 790px; background-color: #fff; padding: 0 30px; // .fl; } .tag-icon { width: 57px; height: 18px; position: absolute; top: 30px; left: 0; } .more-icon { width: 10px; height: 10px; vertical-align: middle; } .btn { width: 94px; height: 34px; text-align: center; line-height: 34px; cursor: pointer; border-radius: 3px; font-size: 14px; box-sizing: content-box; &-green { .btn(#00b38a, #fff); &:hover { background: #00a57f; border-color: #00a57f; } } &-yellow { .btn(#fcd766, #fff); &:hover { background: #fcd766; border-color: #fcd766; } } &-white { .btn(#fff, #00b38a); border: 1px solid #00b38a; &:hover { color: #fff; border-color: #00b38a; background-color: #00b38a; } } &-offset { position: absolute; right: 0; top: -4px; } } .btn-center { margin: 10px auto; } .no-data-title { font-size: 20px; color: #333; font-weight: 500; } </style>
4. 课程详情
- 基本信息,课程信息描述,总课时
Index.vue @click="gotoDetail(course)" gotoDetail(course) { // 传入页面地址 页面参数应该是course this.$router.push({ name: "Course", params: {course:course } }); },Course.vue <!-- 课程详情 --> <div style="position: relative;">
<div class="intro"><div class="intro-content"><imgclass="course-img":src="course.courseImgUrl"alt="课程图片"/><div class="conent-wrap"><div class="name" style="text-align:left;">{{course.courseName}}</div><div class="des text-omit" style="text-align:left;">{{course.brief}}</div><div class="title"><div class="teacher-name text-omit">{{course.teacher.teacherName}}<span class="line"></span>{{course.teacher.position}}</div></div><div class="lesson-info"><div class="boook-icon backgroun-img-set"></div><div class="time">{{totalLesson}}讲 / {{course.totalDuration}}课时</div><div class="person-icon backgroun-img-set"></div><div class="person">{{course.sales}}人已购买</div></div></div></div></div></div><div class="public-class-container is-pc"><el-tabs v-model="activeName"><el-tab-pane label="课程信息" name="intro"><div v-html="course.courseDescription" class="content-p pc-background"></div></el-tab-pane>data() { return { activeName: "intro", course:null, totalLesson:0,//总课时 }; }, created(){ // 获取上一个页面传递的参数 this.course= this.$route.params.course; let x=0; for(let i=0;i<this.course.courseSections.length;i++){ let section=this.course.courseSections[i]; for(let j=0;j<section.courseLessons.length;j++){ x++; } } this.totalLesson=x; }
- 章节目录显示
<!-- 目录框 --> <el-tab-pane label="目录" name="directory"> <div class="class-menu-contaniner list-page-container more-sections more-sections-padding" > <!-- 章 开始 --> <div v-for="(section, index) in course.courseSections" :key="index"> <div class="section-name single-line" > {{ section.sectionName }} </div> <div class="class-menu-block"> <div v-for="(lesson, index) in section.courseLessons" :key="index" class="class-level-one over-ellipsis" @click="watchCourse(1)" > <div class="text-wrap"> <div class="content">{{ lesson.theme }}</div> <div class="item-status-wrap item-status-wrap-list" > <div class="item-status test-watch">试看</div> </div> </div> </div> </div> </div> </div> </el-tab-pane>
- 全部留言
<script> data() { return { activeName: "intro", course:null, totalLessons:0, // 本门课程的总节数 commentList:null, // 所有留言 }; }, created(){ this.course = this.$route.params.course; // 从路由中获得参数对象赋值给本组件的参 数 // 计算多少节课要讲 let x = 0; for(let i = 0; i< this.course.courseSections.length; i++){ let section = this.course.courseSections[i]; //每一章 for( let j = 0; j<section.courseLessons.length ; j++){ x++; }} t his.totalLessons = x; // 获得所有留言 this.getComment(); }, methods: { //播放视频 watchCourse(index) { alert("观看第【" + index + "】节课程视频!"); }, buy(courseid) { alert("购买第【" + courseid + "】门课程成功,加油!"); }, getComment(){ return this.axios .get("http://localhost:8002/course/comment/getCourseCommentList/"+this.course.id +"/1/20") .then((result) => { //console.log(result); this.commentList = result.data; }).catch( (error)=>{ this.$message.error("获取留言信息失败!"); } ); } } </script> <!-- 留言板 开始--> <div class="message"> <div class="message-topic"> <div class="message-topic-title normal-font">精选留言</div> </div> <div> <div class="message-edit"> <textarea rows="20" style="border:0px;resize: none;" contenteditable="true" placeholder="分享学习心得、思考感悟或者给自己一个小鼓励吧!" class="edit-div pcStyle" ></textarea> <div class="message-edit-count"> <span class="message-edit-count-cur">0</span> <span class="message-edit-count-max">/2000</span> </div> </div> <div class="message-edit-footer flex"> <button class="message-edit-btn disableBg" @click="saveComment">发表留言 </button> </div> </div> <!-- 留言 开始 --> <div class="message-list" v-for="(comment , index) in commentList" :key="index"><div class="message-list-title"> <div class="message-list-title-left"> <div class="message-list-title-left-name">{{comment.userName}}</div> <div class="message-list-title-left-tag"></div> </div> <div class="message-list-title-right"> <img class="message-list-title-right-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAKlBMV EVHcExnZ2dzc3NmZmZqampmZmZmZmZnZ2dnZ2dnZ2dmZmZoaGhmZmZmZmZl+8SAAAAADXRSTlMA/AbsF tilbj5YwSqJPyESoQAAAZxJREFUOMt1lTtLA1EQha8xRhPTBEmhuKCCoNgoIlYLMcRKBG0sxIUgCDaBS DohEO0FEbQyIBZaBazERvAPWCwxPnP+i3tnrlGTmVPswn73NXNm7hrzq9m9kZ2ckTUUABifkOEBrK7li R7BMRFOA/uFc+BUgnV8mFisEW5IsIFi9FzBuwR91KJnAm8S9EIbxSBeBRZHk86MrBQJWjymJUC3nlugS yk+SQyhANfxos+s4krfM0DZvmbw2cuSCHNGi3PAfUygXYiU79ryyw1ibf0xZ9intBsz6SBadx24iiZXz 8kPxCiTtYdLPzKTVFkkLQAZO/VikwYW/x/wHohcT/MiPQE8W9frxJrlbpiw4xvA0vbNmWyhj2Nrhmy+B 7nEyTsN0rIaJAc0SDWqwX7rhAYfMa/Dui0bDZbwZAwUGNjWUWActnUUyN2hwDTaOkxRaSiwj6pRhjHKg TazSkWlwBK1jgIpBwrkHCgwyZ0oQ86BAjkHCjziG0KE8YBvCA/5KacOm6sgrHFAotouT6J23bkkLbsND jM9yt7yP+IbQYga5De+eBMAAAAASUVORK5CYII=" alt=""> <div class="message-list-title-right-praise">{{comment.likeCount}}</div> </div> </div> <div class="message-list-content"> {{comment.comment}} </div> </div> <!-- 留言 结束 --> </div> <!-- 留言板 结束-->
- 章节状态
<script> import Header from "./Header/Header"; //顶部登录条 import Footer from "./Footer/index"; //顶部登录条 export default { name: "Course", components: { Header, Footer, }, data() { return { activeName: "intro", course:null, totalLessons:0, // 本门课程的总节数 commentList:null, // 所有留言 isLogin:false, // false 未登录 myCourseList:[], // 我购买过的课程列表 isBuy:false, // false 未购买 user:null, // 登录的用户 }; }, created(){this.course = this.$route.params.course; // 从路由中获得参数对象赋值给本组件的参 数 // 检测是否登录 this.user = JSON.parse( localStorage.getItem("user") ); if( this.user != null ){ this.isLogin = true; // 已登录 this.getMyCourseList(); // 调用查询我购买的课程方法 } / / 计算多少节课要讲,略。。。 // 获得所有留言,略。。。 }, methods: { //章节,课程索引,文件播放地址 watchCourse(i,index,file) { if(i==1 && (index==0||index==1)){ alert("观看第【" + index + "】节课程视频!"+file); this.$router.push({name: "videoDetail",params: { file: file }}); }else{ if(!this.isLogin){ alert("请先登录!"); }else{ if(!this.isBuy){ alert("请购买解锁才能观看本视频!"); }else{ alert("观看第【" + index + "】节课程视频!"+file); this.$router.push({name: "videoDetail",params: { file: file }}); } } } }, buy(courseid) { alert("购买第【" + courseid + "】门课程成功,加油!"); }, getComment(){ // 获取全部留言,省略。。。 }, saveComment(){}, getMyCourseList(){ return this.axios .get("http://localhost:8002/course/getCourseByUserId/"+this.user.content.id) .then((result) => { console.log("获得我的课程"); console.log(result); this.myCourseList = result.data; // 检查我是否购买过本门课程 console.log(this.myCourseList.length); for(let i = 0; i< this.myCourseList.length ; i++){ if(this.myCourseList[i].id == this.course.id){ this.isBuy = true;//标记购买过本次课程 break; } } }).catch( (error)=>{ this.$message.error("获取课程信息失败!");} ); } }, }; </script> <el-tab-pane label="目录" name="directory"> <div class="class-menu-contaniner list-page-container more-sections moresections-padding"> <!-- 第一章 开始 --> <div v-for="section in course.courseSections.slice(0,1)" > <div class="section-name single-line"> {{section.sectionName}} </div> <div class="class-menu-block"> <!-- 每节课 开始 --> <div class="class-level-one over-ellipsis" @click="watchCourse(1,i,lesson.courseMedia.fileEdk)" v-for="(lesson , i) in section.courseLessons" :key="i"> <div class="text-wrap"> <div class="content">{{lesson.theme}}</div> <div class="item-status-wrap item-status-wrap-list"> <!--第一章,前两节--> <div v-if="i == 0 || i==1"> <!--未登录,试看--> <div v-if="!isLogin" class="item-status test-watch">试看</div> <!--已登录,未购买,试看--> <div v-else-if="isLogin && !isBuy" class="item-status test-watch"> 试看</div> <!--已登录,已购买,播放--> <div v-else class="item-status test-watch">播放</div> </div> <!--第一章,除了前两节后面的--> <div v-if="i != 0 && i!=1"> <!--未登录,锁--> <div v-if="!isLogin" class="item-status lock"></div> <!--已登录,未购买,锁--> <div v-else-if="isLogin && !isBuy" class="item-status lock"></div> <!--已登录,已购买,播放--> <div v-else class="item-status test-watch">播放</div> </div> </div> </div> </div> <!-- 每节课 结束 --> </div> </div> <!-- 第一章 结束 --> <!-- 其余章 开始 --> <div v-for="section in course.courseSections.slice(1,course.courseSections.length)" > <div class="section-name single-line"> {{section.sectionName}} </div> <div class="class-menu-block"> <!-- 每节课 开始 --> <div class="class-level-one over-ellipsis" @click="watchCourse(2,j,lesson.courseMedia.fileEdk)" v-for="(lesson , j) in section.courseLessons" > <div class="text-wrap"> <div class="content">{{lesson.theme}}</div> <div class="item-status-wrap item-status-wrap-list"> <!--已登录,已购买,播放--> <div v-if="isLogin&&isBuy" class="item-status test-watch">播放</div> <!--未登录,锁--> <div v-else-if="!isLogin" class="item-status lock"></div> <!--已登录,未购买,锁--> <div v-if="isLogin && !isBuy" class="item-status lock"></div> </div> </div> </div> <!-- 每节课 结束 --> </div> </div> <!-- 其余章 结束 --> </div> </el-tab-pane>
- 视频播放
data() { return { myvideo: null, // 播放器对象 isplay: false, //是否在播放 nowTime: "00:00", //当前播放时间 totalTime: "00:00", //总时长 course:null,//课程信息 lessonid:0,//课时ID }; }, created() { // 接收课程课时 this.course= this.$route.params.course; this.lessonid=this.$route.params.lessonid; }, // 初始播放的视频 initPlay(){ for(let i=0;i<this.course.courseSections.length;i++){ let section=this.course.courseSections[i]; for(let j=0;j<section.courseLessons.length;j++){ let lesson=section.courseLessons[j]; if(lesson.courseMedia!=null){if(this.lessonid==lesson.courseMedia.lessonId){ this.myvideo.src=lesson.courseMedia.fileEdk; return; }} } } }
5. 播放页
- 显示
created() { // 获取用户登录信息 this.user = JSON.parse(localStorage.getItem("user")); // 如果用户不为空,说明登录 if (this.user != null) { this.isLogin = true; } // 接收课程课时 this.course = this.$route.params.course; this.lessonid = this.$route.params.lessonid; this.isBuy=this.$route.params.isBuy; console.log(this.isBuy); }, // 初始播放的视频 initPlay() { for (let i = 0; i < this.course.courseSections.length; i++) { let section = this.course.courseSections[i]; for (let j = 0; j < section.courseLessons.length; j++) { let lesson = section.courseLessons[j]; if (lesson.courseMedia != null) { if (this.lessonid == lesson.courseMedia.lessonId) { this.myvideo.src = lesson.courseMedia.fileEdk; this.lessonName = lesson.theme; return; } } } } }, <!-- 章节目录 --> <div class="detail-part-content-pc calc detail-part-content"> <div class="content-fold"> <div class="content-fold-img"></div> </div> <div class="content-container"> <div v-for="(section, index) in course.courseSections" :key="index" > <!-- 第一章节课时信息 --> <div v-if="index<1"> <div class="content-label"> <div class="content-label-title single-line"> {{ section.sectionName }} </div> <img class="arrow-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII=" alt="" /> </div> <div class="content-sections" v-for="(lesson, index) in section.courseLessons" :key="index" > <!-- 前两节视频 --> <div v-if="index < 2"> <!-- 未播放的视频 --> <div class="content-section" @click="playLesson"> <div class="section-item clearfix"> <span class="kw-icon-video section-type-icon fl" ><i class="el-icon-video-play"></i ></span> <span class="section-dec need-update">{{ lesson.theme }}</span> <!-- 课时状态 --> <!-- 如果未登录,可以试看前两节课时 --> <span v-if="!isLogin" class="section-status-icon pause-play">试看</span> <!-- 如果登录,且没有购买可以试看前两节课时 --> <span v-else-if="isLogin&&!isBuy" class="section-status-icon pause-play">试看</span> <!-- 如果登录,且购买, 可以播放前两节课时 --> <span v-else class="section-status-icon pause-play">可播放</span> </div> <div class="section-duration"> <span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span> <span v-else>时长:暂无视频</span> </div> </div> </div> <!-- 其余课时视频 --> <div v-else> <!-- 未播放的视频 --> <div class="content-section" @click="playLesson"> <div class="section-item clearfix"> <span class="kw-icon-video section-type-icon fl" ><i class="el-icon-video-play"></i ></span> <span class="section-dec need-update">{{ lesson.theme }}</span> <!-- 课时状态 --> <!-- 如果未登录,可以试看前两节课时 --> <span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,且没有购买可以试看前两节课时 --> <span v-else-if="isLogin &&!isBuy" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,且购买, 可以播放前两节课时 --> <span v-else class="section-status-icon pause-play">可播放</span> </div> <div class="section-duration"> <span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span> <span v-else>时长:暂无视频</span> </div> </div> </div> <!-- 正在播放的视频 <div class="content-section content-section-choose" style=" color: #00b38a;" @click="playLesson" > <div class="section-item clearfix"> <span class="kw-icon-video section-type-icon fl" ><i class="el-icon-video-play"></i ></span> <span class="section-dec">2.起步</span> <span class="section-status-icon pause-play"></span> </div> <div class="section-duration"> <span>时长:0</span> </div> </div> --> </div> </div> <!-- 其余章节 --> <div v-else> <div class="content-label"> <div class="content-label-title single-line"> {{ section.sectionName }} </div> <img class="arrow-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII=" alt="" /> </div> <div class="content-sections" v-for="(lesson, index) in section.courseLessons" :key="index" > <!-- 其余课时视频 --> <div > <!-- 未播放的视频 --> <div class="content-section" @click="playLesson"> <div class="section-item clearfix"> <span class="kw-icon-video section-type-icon fl" ><i class="el-icon-video-play"></i ></span> <span class="section-dec need-update">{{ lesson.theme }}</span> <!-- 课时状态 --> <!-- 如果未登录,可以试看前两节课时 --> <span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,且没有购买可以试看前两节课时 --> <span v-else-if="isLogin && !isBuy" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,且购买, 可以播放前两节课时 --> <span v-else class="section-status-icon pause-play">可播放</span> </div> <div class="section-duration"> <span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span> <span v-else>时长:暂无视频</span> </div> </div> </div> <!-- 正在播放的视频 <div class="content-section content-section-choose" style=" color: #00b38a;" @click="playLesson" > <div class="section-item clearfix"> <span class="kw-icon-video section-type-icon fl" ><i class="el-icon-video-play"></i ></span> <span class="section-dec">2.起步</span> <span class="section-status-icon pause-play"></span> </div> <div class="section-duration"> <span>时长:0</span> </div> </div> --> </div> </div> </div> </div> </div>
- 当前视频高亮突出
<div class="content-container"> <div v-for="(section, index) in course.courseSections" :key="index" > <!-- 第一章节课时信息 --> <div v-if="index<1"> <div class="content-label"> <div class="content-label-title single-line"> {{ section.sectionName }} </div> <img class="arrow-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII=" alt="" /> </div> <div class="content-sections" v-for="(lesson, index) in section.courseLessons" :key="index" > <!-- 前两节视频 --> <div v-if="index < 2"> <!-- 未播放的视频 --> <div :class="{ 'content-section content-section-choose':lesson.id==lessonid, 'content-section':lesson.id!=lessonid }" @click="playLesson"> <div class="section-item clearfix"> <span :class="{ 'kw-icon-video section-type-icon fl lv':lesson.id==lessonid, 'kw-icon-video section-type-icon fl':lesson.id!=lessonid }" ><i class="el-icon-video-play"></i ></span> <span :class="{ 'section-dec lv':lesson.id==lessonid, 'section-dec ':lesson.id!=lessonid }" >{{ lesson.theme }}</span> <!-- 课时状态 --> <span v-if="lesson.id!=lessonid"> <!-- 如果未登录,可以试看前两节课时 --> <span v-if="!isLogin" class="section-status-icon pause-play">试看</span> <!-- 如果登录,且没有购买可以试看前两节课时 --> <span v-else-if="isLogin&&!isBuy" class="section-status-icon pause-play">试看</span> <!-- 如果登录,且购买, 可以播放前两节课时 --> <span v-else class="section-status-icon pause-play">可播放</span> </span> <span v-else class="section-status-icon pause-play"></span> </div> <div class="section-duration"> <span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span> <span v-else>时长:暂无视频</span> </div> </div> </div> <!-- 其余课时视频 --> <div v-else> <!-- 未播放的视频 --> <div :class="{ 'content-section content-section-choose':lesson.id==lessonid, 'content-section':lesson.id!=lessonid }" @click="playLesson"> <div class="section-item clearfix"> <span :class="{ 'kw-icon-video section-type-icon fl lv':lesson.id==lessonid, 'kw-icon-video section-type-icon fl':lesson.id!=lessonid }" ><i class="el-icon-video-play"></i ></span> <span :class="{ 'section-dec lv':lesson.id==lessonid, 'section-dec ':lesson.id!=lessonid }" >{{ lesson.theme }}</span> <!-- 课时状态 --> <!-- 如果未登录,锁--> <span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,锁 --> <span v-else-if="isLogin &&!isBuy" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,且购买, 可以播放前两节课时 --> <span> <span v-if="lesson.id==lessonid" class="section-status-icon pause-play"></span> <span v-else class="section-status-icon pause-play">可播放</span> </span> </div> <div class="section-duration"> <span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span> <span v-else>时长:暂无视频</span> </div> </div> </div> </div> </div> <!-- 其余章节 --> <div v-else> <div class="content-label"> <div class="content-label-title single-line"> {{ section.sectionName }} </div> <img class="arrow-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII=" alt="" /> </div> <div class="content-sections" v-for="(lesson, index) in section.courseLessons" :key="index" > <!-- 其余课时视频 --> <div > <!-- 未播放的视频 --> <div :class="{ 'content-section content-section-choose':lesson.id==lessonid, 'content-section':lesson.id!=lessonid }" @click="playLesson"> <div class="section-item clearfix"> <span :class="{ 'kw-icon-video section-type-icon fl lv':lesson.id==lessonid, 'kw-icon-video section-type-icon fl':lesson.id!=lessonid }" ><i class="el-icon-video-play"></i ></span> <span :class="{ 'section-dec lv':lesson.id==lessonid, 'section-dec ':lesson.id!=lessonid }">{{ lesson.theme }}</span> <!-- 课时状态 --> <!-- 如果未登录,可以试看前两节课时 --> <span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,且没有购买可以试看前两节课时 --> <span v-else-if="isLogin && !isBuy" class="section-status-icon pause-play">未解锁</span> <!-- 如果登录,且购买, 可以播放前两节课时 --> <span> <span v-if="lesson.id==lessonid" class="section-status-icon pause-play"></span> <span v-else class="section-status-icon pause-play">可播放</span> </span> </div> <div class="section-duration"> <span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span> <span v-else>时长:暂无视频</span> </div> </div> </div> </div> </div> </div> </div>
- 点击课标题切换视频并播放
<template>
<div id="videoDetail">
<div class="detail-container">
<div class="left-container top-container">
<nav class="nav">
<div class="nav-back" @click="goBack">
<span class="kw-icon-back"> < </span>
<span style=""> 返回</span>
</div>
<!-- 播放导航页显示 -->
<span style="position:absolute;left:80px;">
{{ course.courseName }} >{{ lessonName }}
</span>
</nav>
<!-- 视频播放键 -->
<div class="video-content calc">
<div class="video-container">
<div
id="player-video-vontainer"
class="player-container video-container"
>
<div
style="min-width:750px;min-height:550px;"
class="video"
@click="play"
>
<video
style="width: 100%; height: 100%;"
id="myvideo"
src="https://video.pearvideo.com/mp4/adshort/20200901/cont-1693694-15359233_adpkg-ad_hd.mp4"
@canplay="getInit"
@timeupdate="handlerNowTime"
/>
<!-- <div class="controls">
<div class="con_left"> -->
<!-- 播放 -->
<!-- <i
:class="{
'el-icon-video-play': !isplay,
'el-icon-video-pause': isplay,
}"
@click="play"
style="font-size:40px"
></i>
<span>{{ nowTime }}/{{ totalTime }}</span>
</div>
<div class="con_right"> -->
<!-- 音量 -->
<!-- <i
class="el-icon-headset"
@click="play"
style="font-size:40px"
></i> --> -->
<!-- 全屏 -->
<!-- <i
class="el-icon-monitor"
@click="play"
style="font-size:40px"
></i>
</div>
</div> -->
</div>
</div>
</div>
</div>
</div>
<!-- 右侧视频导航栏 -->
<div class="right-container bottom-container">
<div style="height: 100%;">
<div class="detail-part-content-title">课程目录</div>
<div class="study-percent-tip">
<div class="week-progress">
<img
class="video-book"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAYAAACohjseAAADHUlEQVRoQ+2a30sUURTHv3dMS60Xg8AIQV+ChCBmJqInqXAx6iXah6CghzCkiMz8C3qJfllRhNJDEEWwEUFFJBW9KMbMEAkWvbjgg0FRYO76o92dE1Ma686d8c4y7rrDncfdc+85n3t+zL1zD0PEHxZxPkjASvewsAd1XW8lohNE1A6gCcD6EsOnAEwwxgYZY3cNwxgT0b8sYDwer0kmk9eIqAuAIjJpCWRsxtid5ubmc4lE4refPl9AB258fPwlgD0lMLoYFW9bWlo6/CB9ATVNu0VEp4rRXKoxjLHbpmme9tLnCejknG3bo6soLL0YbEVRtnvlpCegpml9RHSWM2sGwCvG2KSIl4ioU0SuUIYxNpD/GxFtBhADUM2RvW6aZjdPjyegqqpOldpWMCijKEqbYRjDokarqkqisvlylmW5bNN1fbdt2+84kJ8sy2oNCjjNeRU8tyzrYBCDwwR09Kqq+gzAgQIbUpZlbQgK6Fp5J2xM0zxZTkBN0/p5Yc/zuGOnX4hKQBFPhh2i0oMFqx5qiNJIx5acbV8CoY1AjY6uXWd+iDjaJTNycyN33IUHqZkX7+frCv9c8RxcgPtIRA35ysMGvPgojafDcy74FQfMDsceEtGRQs3RARyKTS6GpYgH69b9y46ZOf4+wCtEy+bBzFA711KeB/fuqEH3ofq/gH1P0njzwX3iqUjApk1V6I3XQ9+6dDtpfMngciKNiW+5/86vKMC11QzH22txbF8t1lTxi2o2B9x/PYt7g7OYzxAqBvD8wDR6DtejsUHsY8DXnzauPk7jSid3a4lVl4NFvQR9BknAldrJeFVR6cGAKyBDVIbowgrwznF+J3qZgwFzzUtc5qDMQZmD/M+GssjIIiO2ArKKyioqq6isomLVokgpWWQCFJlAF6CletH39P/C0Jhzi77kKeoCNNAVdikAR5NZdN2YQs52xXfwK+ygTQj7d9Ycra5irlufIlPNNez7VA4jnzM8ODDGgjchRL6NxFnCSDcCOYCRb+VahIxsM15+pke2nTKsKliueZbtFy2XYWHplYBhrWS55vkDgsoDZgBZavwAAAAASUVORK5CYII="
alt=""
/>
<span class="progress-label">{{ course.courseName }}</span>
</div>
</div>
<!-- 章节目录 -->
<div class="detail-part-content-pc calc detail-part-content">
<div class="content-fold">
<div class="content-fold-img"></div>
</div>
<div class="content-container">
<div
v-for="(section, index) in course.courseSections"
:key="index"
>
<!-- 第一章节课时信息 -->
<div v-if="index<1">
<div class="content-label">
<div class="content-label-title single-line">
{{ section.sectionName }}
</div>
<img
class="arrow-icon"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII="
alt=""
/>
</div>
<div
class="content-sections"
v-for="(lesson, index) in section.courseLessons"
:key="index"
>
<!-- 前两节视频 -->
<div v-if="index < 2">
<!-- 未播放的视频 -->
<div :class="{
'content-section content-section-choose':lesson.id==lessonid,
'content-section':lesson.id!=lessonid
}" @click="playLesson(index, lesson, 1)">
<div class="section-item clearfix">
<span :class="{
'kw-icon-video section-type-icon fl lv':lesson.id==lessonid,
'kw-icon-video section-type-icon fl':lesson.id!=lessonid
}"
><i class="el-icon-video-play"></i
></span>
<span :class="{
'section-dec lv':lesson.id==lessonid,
'section-dec ':lesson.id!=lessonid
}"
>{{
lesson.theme
}}</span>
<!-- 课时状态 -->
<span v-if="lesson.id!=lessonid">
<!-- 如果未登录,可以试看前两节课时 -->
<span v-if="!isLogin" class="section-status-icon pause-play">试看</span>
<!-- 如果登录,且没有购买可以试看前两节课时 -->
<span v-else-if="isLogin&&!isBuy" class="section-status-icon pause-play">试看</span>
<!-- 如果登录,且购买, 可以播放前两节课时 -->
<span v-else class="section-status-icon pause-play">可播放</span>
</span>
<span v-else class="section-status-icon pause-play"></span>
</div>
<div class="section-duration">
<span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span>
<span v-else>时长:暂无视频</span>
</div>
</div>
</div>
<!-- 其余课时视频 -->
<div v-else>
<!-- 未播放的视频 -->
<div :class="{
'content-section content-section-choose':lesson.id==lessonid,
'content-section':lesson.id!=lessonid
}" @click="playLesson(index, lesson, 1)">
<div class="section-item clearfix">
<span :class="{
'kw-icon-video section-type-icon fl lv':lesson.id==lessonid,
'kw-icon-video section-type-icon fl':lesson.id!=lessonid
}"
><i class="el-icon-video-play"></i
></span>
<span :class="{
'section-dec lv':lesson.id==lessonid,
'section-dec ':lesson.id!=lessonid
}"
>{{
lesson.theme
}}</span>
<!-- 课时状态 -->
<!-- 如果未登录,锁-->
<span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span>
<!-- 如果登录,锁 -->
<span v-else-if="isLogin &&!isBuy" class="section-status-icon pause-play">未解锁</span>
<!-- 如果登录,且购买, 可以播放前两节课时 -->
<span>
<span v-if="lesson.id==lessonid" class="section-status-icon pause-play"></span>
<span v-else class="section-status-icon pause-play">可播放</span>
</span>
</div>
<div class="section-duration">
<span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span>
<span v-else>时长:暂无视频</span>
</div>
</div>
</div>
</div>
</div>
<!-- 其余章节 -->
<div v-else>
<div class="content-label">
<div class="content-label-title single-line">
{{ section.sectionName }}
</div>
<img
class="arrow-icon"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAgwWyMeGgBsFrrQAAAFVJREFUKM9jYBiugMUBQ0i8EF2EsbxcAF1ReXkhuqJiczRl4uVGyqjKgIoUmFCVARUxMKAoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII="
alt=""
/>
</div>
<div
class="content-sections"
v-for="(lesson, index) in section.courseLessons"
:key="index"
>
<!-- 其余课时视频 -->
<div >
<!-- 未播放的视频 -->
<div :class="{
'content-section content-section-choose':lesson.id==lessonid,
'content-section':lesson.id!=lessonid
}" @click="playLesson(index, lesson, 2)">
<div class="section-item clearfix">
<span :class="{
'kw-icon-video section-type-icon fl lv':lesson.id==lessonid,
'kw-icon-video section-type-icon fl':lesson.id!=lessonid
}"
><i class="el-icon-video-play"></i
></span>
<span :class="{
'section-dec lv':lesson.id==lessonid,
'section-dec ':lesson.id!=lessonid
}">{{
lesson.theme
}}</span>
<!-- 课时状态 -->
<!-- 如果未登录,可以试看前两节课时 -->
<span v-if="!isLogin" class="section-status-icon pause-play">未解锁</span>
<!-- 如果登录,且没有购买可以试看前两节课时 -->
<span v-else-if="isLogin && !isBuy" class="section-status-icon pause-play">未解锁</span>
<!-- 如果登录,且购买, 可以播放前两节课时 -->
<span>
<span v-if="lesson.id==lessonid" class="section-status-icon pause-play"></span>
<span v-else class="section-status-icon pause-play">可播放</span>
</span>
</div>
<div class="section-duration">
<span v-if="lesson.courseMedia!=null">时长:{{lesson.courseMedia.duration}}</span>
<span v-else>时长:暂无视频</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "videoDetail",
components: {},
data() {
return {
myvideo: null, // 播放器对象
isplay: false, //是否在播放
nowTime: "00:00", //当前播放时间
totalTime: "00:00", //总时长
course: null, //课程信息
lessonid: 0, //课时ID
lessonName: "", //课时名称
isLogin: false, //是否登录
isBuy: false, //是否购买
};
},
computed: {},
created() {
// 获取用户登录信息
this.user = JSON.parse(localStorage.getItem("user"));
// 如果用户不为空,说明登录
if (this.user != null) {
this.isLogin = true;
}
// 接收课程课时
this.course = this.$route.params.course;
this.lessonid = this.$route.params.lessonid;
this.isBuy=this.$route.params.isBuy;
console.log(this.isBuy);
},
mounted() {
this.myvideo = document.getElementById("myvideo");
//初始化控制视频模板
this.myvideo.controls=true;
this.initPlay();// 初始化播放的视频
},
methods: {
play() {
this.isplay = !this.isplay;
if (this.isplay) {
this.myvideo.play();
} else {
this.myvideo.pause();
}
},
// 获取视频的时间是秒为单位,格式化城00:00的格式
formatTime(time) {
let mm = Math.floor((time % 3600) / 60);
let ss = Math.floor(time % 60);
mm = mm < 10 ? "0" + mm : mm;
ss = ss < 10 ? "0" + ss : ss;
return `${mm}:${ss}`;
},
//获取初始化信息
getInit() {
if (!this.myvideo) {
//获取失败,显示0
this.totalTime = this.formatTime(0);
} else {
//获取视频总时长
this.totalTime = this.formatTime(this.myvideo.duration);
}
},
//播放时显示当前播放时间和总时长
handlerNowTime() {
if (!this.myvideo) {
this.nowTime = `${this.formatTime(0)}`;
}
this.nowTime = this.formatTime(this.myvideo.currentTime || 0);
},
//返回
goBack() {
this.$router.push({ name: "Course" ,params:{
course:this.course
}});
},
//播放课程
playLesson(index, lesson, status) {
// status是否是第一章节
if (status == 1 && index < 2) {
this.playVideo(lesson);
}
// 是否是免费试看的章节
else {
//不是免费试看的章节
// 先登录
if (!this.isLogin) {
this.$message.warning("请登录账号");
} else {
// 查看该章节是否被购买
if (!this.isBuy) {
this.$message.warning("请先购买");
} else {
this.playVideo(lesson);
}
}
}
},
// 播放
playVideo(lesson){
// 判断是否有视频
if(lesson.courseMedia==null){
this.$message.error("暂无视频源");
}
else{
// 视频ID
this.lessonid=lesson.id;
// 视频地址
this.myvideo.src=lesson.courseMedia.fileEdk;
this.myvideo.play();
// 视频切换状态
this.isplay=true;
}
},
// 初始播放的视频
initPlay() {
for (let i = 0; i < this.course.courseSections.length; i++) {
let section = this.course.courseSections[i];
for (let j = 0; j < section.courseLessons.length; j++) {
let lesson = section.courseLessons[j];
if (lesson.courseMedia != null) {
if (this.lessonid == lesson.courseMedia.lessonId) {
this.myvideo.src = lesson.courseMedia.fileEdk;
this.myvideo.play();
this.isplay=true;
this.lessonName = lesson.theme;
return;
}
}
}
}
},
},
};
</script>
<style lang="less">
.lv{
color: #00b38a;
}
.video {
position: relative;
video {
width: 100%;
height: 100%;
}
.controls {
width: 100%;
height: 40px;
position: absolute;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: space-between;
align-items: center;
span {
padding: 0 5px;
color: #fff;
}
}
}
.detail-container {
height: 100%;
}
* {
-webkit-tap-highlight-color: transparent;
}
* {
margin: 0;
padding: 0;
}
div {
display: block;
}
.left-container {
margin-right: 380px;
-webkit-transition: margin-right 0.3s ease 0s;
transition: margin-right 0.3s ease 0s;
height: 100%;
overflow-y: auto;
}
.left-container .nav {
height: 60px;
line-height: 60px;
background: #32373e;
font-size: 14px;
font-weight: 400;
color: #fff;
padding-left: 80px;
position: relative;
}
.left-container .video-content {
position: relative;
background: #272c30;
overflow-x: hidden;
}
.calc {
height: calc(100% - 60px);
}
.left-container .nav-back {
position: absolute;
top: 1px;
left: 10px;
cursor: pointer;
&:hover {
color: #00b38a;
}
}
[class*=" kw-icon-"],
[class^="kw-icon-"] {
font-family: kw-icon !important;
speak: none;
font-style: normal;
font-weight: 400;
-webkit-font-feature-settings: normal;
font-feature-settings: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.video-container {
position: relative;
height: 100%;
background: #272c30;
}
.right-container {
position: absolute;
top: 0;
right: 0;
width: 380px;
height: 100%;
background-color: #32373e;
-webkit-transition: right 0.3s ease 0s;
transition: right 0.3s ease 0s;
}
.detail-part-content-title {
height: 60px;
line-height: 60px;
background: #40464d;
font-size: 18px;
font-weight: 500;
color: #fff;
padding-left: 20px;
position: relative;
z-index: 10;
text-align: left;
}
.study-percent-tip {
display: none;
}
img {
border: 0;
vertical-align: top;
display: inline-block;
}
.detail-part-content-pc .content-fold {
position: absolute;
left: -24px;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
width: 24px;
height: 100px;
background-color: rgba(50, 55, 62, 0.7);
border-radius: 8px 0 0 8px;
z-index: 1;
}
.detail-part-content-pc .content-fold-img {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkBAMAAAATLoWrAAAAGFBMV…AoAyliYEBRBlaEqiwcpAikrBShKglCqyFUMcEYCgwjBAAAeaoQrHtg6QoAAAAASUVORK5CYII=)
no-repeat;
width: 18px;
height: 18px;
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%) rotate(90deg);
transform: translate(-50%, -50%) rotate(90deg);
background-size: contain;
-webkit-transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
}
.detail-part-content-pc .content-label {
position: relative;
height: 60px;
line-height: 60px;
font-size: 14px;
font-weight: 400;
color: #fff;
padding: 0 10px;
background: #2b3035;
border-radius: 4px;
margin-top: 10px;
text-align: left;
text-indent: 10px;
}
.detail-part-content-pc .content-label-title {
width: 310px;
height: 60px;
}
.single-line {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.detail-part-content-pc .arrow-icon {
width: 18px;
height: 18px;
position: absolute;
top: 21px;
right: 10px;
-webkit-transition: all 0.3s ease;
transition: all 0.3s ease;
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
img {
border: 0;
vertical-align: top;
display: inline-block;
}
.detail-part-content-pc .content-sections {
-webkit-transition: all 1s ease;
transition: all 1s ease;
}
.detail-part-content-pc .content-section {
padding: 15px 10px;
color: #fff;
font-size: 14px;
min-height: 40px;
border-bottom: 1px solid #272c30;
font-family: none;
opacity: 0.7;
}
.detail-part-content-pc .section-item {
position: relative;
text-align: left;
}
.detail-part-content-pc .section-type-icon {
font-size: 16px;
vertical-align: middle;
margin: 4px 10px 0 0;
}
.fl {
float: left;
}
.detail-part-content-pc .need-update {
color: #989b9e;
}
.detail-part-content-pc .section-dec {
max-width: 270px;
display: inline-block;
vertical-align: bottom;
word-break: break-all;
}
.detail-part-content-pc .section-status-icon {
font-size: 12px;
position: absolute;
right: 0;
top: 1px;
color: #989b9e;
}
.detail-part-content-pc .section-duration {
font-size: 12px;
margin-top: 4px;
padding-left: 26px;
color: hsla(0, 0%, 100%, 0.7);
text-align: left;
}
.detail-part-content-pc .content-section-choose .pause-play {
width: 18px;
height: 18px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAFoCAYAAABaAKtEAAAEPUlEQVR4Xu1dPW8TQRB9ZwLBTkF+AeIf0CMK6JAiGyr+A10UyU6gOmhCYomvAokCRAOFm0S6CEVponQUSCDRgpQCCYmCLwWRKIkPXcBRvN7zzk42x+5l3ObueWbu3tuZ2VkngqNP5AgHBQEt3B/HyPY3AA9Rb00Os364RQKUxa4/Rsl82hdYdowECGoI2MF2AtSJT6Fa21JpUxBpLTRGLDIHa3iMOveqqO7MAtEa6s0FUUhggIwibHzxT+bXkeIZGq07vXeLt4o4EbbMBCdAopBm4cm5IjTNTtMIiw/OYDvdwvWp3yErpCRauqfH1KP2O6D7AvXpdpmEzZlCvno0it3NTckh7YXSd4XUrKBUJ4dzjYpirI7YWW3hCpnMxahErzHRWhYZyenWOMnYnAmbM6DV+DQ2allC0dec8p39FiRVLxXXzMGzj9FqPIKNsYvo7nzC1Zsf9DJi/mIgp861t4gFpLuJBJS0nwNYQb35cs9LPhChoUmzSIA0XXf7PJsUbMqbXZJS1MJVe9IWGyP/c8i95bk6o2Zn7ipIDZI9RXKstAcicY2SHguQeVus2BhZyIZkbPbB8l1ql+5ewG765WBuSHVyuIywO6MUGclMXGpPopu+RaO1JsXx8SqOpcqmcnTgOt/1iO2YOoDiDEjVoyMXNiepHylhp0qtM4vUatzYq83bXS9p18+ZsDkDkp0atpCUQWrjuILzo2dRHf2JK1NfQ20f6p4hqcxSb9RV1Cwgdh9StYgNlCh71HwgaWgaG5psETmytEYsMjfrnMUoaV9Sd2Co2AVtiuvYn6393a0bh6+ySQpJSUYFyLf2obOnRuWDsRYRoAKFjZIfkUpRSloTKBCFIiTXBAglnRhP4hpQ+yXTPvbiXYYqm8V+i1DZb/iyLArjKMwe18Ye900FsfqQkoz6loxaUEK99NjISLgxWpg9d/g+JKkxTo2RcRfiyIB6M+wVLB+cDjefX8vLs9NoDo3mzP6frV3j79QQ+pCkp0ZNj42uhQkkE+NUtg1cVxbxN77Z1AiVAKi3TT/+YxOX4+yo2d+PtWv7wpbeRn06dgAUzaLevOUASPnhEr5rtkCikP+xx0Yl8UBRY3GjpMf2weKtIsncNVTSj5iYed/7yn4gdc4x7/iikf1hkpak2eKaeV2jxEhySHva/7uDx37N14UGFMZRmBI3NDPXluYX0Y0SNJpP9asIhf3OpJY0NEixKNAWK1tEZNqHErrQFDKcH5wwLkcU0voptX4ppDOp9Q+IJP4UmpPeIwEqcydCMzfJE39jcaxG0X370LrHRvjlCv/YLxaZN8WlymarNo/9xrSGbU9hCTt7tkZ1jQ0UbupnfPyFu6aevWHNH/kntZ3OCVTXd4aPMVKCTar7/SethYXHVtjCiNGbJyfx+fuE3U4N+7CgM4oIkO4/fNiPw5L0yL9gW3BLvdQ/PfoDa+yS8O1qaS0AAAAASUVORK5CYII=)
no-repeat;
background-size: cover;
background-position: 0 0;
color: #00b38a;
}
.detail-part-content-pc .content-section:last-of-type {
border-bottom: none;
margin-bottom: 25px;
}
.detail-part-content-pc .content-section:hover {
background: #2b3035;
cursor: pointer;
}
.detail-part-content-pc .content-section-choose{
color: #00b38a;
}
.detail-part-content-pc .content-section-choose .section-status-icon{
color: #00b38a;
}
.kw-icon-video:before {
// content: "\E903";
}
.detail-part-content-pc .content-section {
padding: 15px 10px;
color: #fff;
font-size: 14px;
min-height: 40px;
border-bottom: 1px solid #272c30;
font-family: none;
opacity: 0.7;
}
</style>
6. 留言点赞
- 后端修改
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="mapper.CourseCommentDao"> <resultMap type="entity.CourseComment" id="CourseCommentMap"> <result property="id" column="cc_id" jdbcType="VARCHAR"/> <result property="courseId" column="course_id" jdbcType="INTEGER"/> <result property="sectionId" column="section_id" jdbcType="INTEGER"/> <result property="lessonId" column="lesson_id" jdbcType="INTEGER"/> <result property="userId" column="cc_user_id" jdbcType="INTEGER"/> <result property="userName" column="user_name" jdbcType="VARCHAR"/> <result property="parentId" column="parent_id" jdbcType="INTEGER"/> <result property="isTop" column="is_top" jdbcType="VARCHAR"/> <result property="comment" column="comment" jdbcType="VARCHAR"/> <result property="likeCount" column="like_count" jdbcType="INTEGER"/> <result property="isReply" column="is_reply" jdbcType="VARCHAR"/> <result property="type" column="type" jdbcType="INTEGER"/> <result property="status" column="status" jdbcType="INTEGER"/> <result property="createTime" column="cc_create_time" jdbcType="TIMESTAMP"/> <result property="updateTime" column="cc_update_time" jdbcType="TIMESTAMP"/> <result property="isDel" column="cc_is_del" jdbcType="VARCHAR"/> <result property="lastOperator" column="last_operator" jdbcType="INTEGER"/> <result property="isNotify" column="is_notify" jdbcType="VARCHAR"/> <result property="markBelong" column="mark_belong" jdbcType="VARCHAR"/> <result property="replied" column="replied" jdbcType="VARCHAR"/> <collection property="favoriteRecordList" ofType="entity.CourseCommentFavoriteRecord"> <result property="id" column="ccfr_id" jdbcType="INTEGER"/> <result property="userId" column="ccfr_user_id" jdbcType="INTEGER"/> <result property="commentId" column="comment_id" jdbcType="INTEGER"/> <result property="isDel" column="ccfr_is_del" jdbcType="VARCHAR"/> <result property="createTime" column="ccfr_create_time" jdbcType="TIMESTAMP"/> <result property="updateTime" column="ccfr_update_time" jdbcType="TIMESTAMP"/> </collection> </resultMap> <insert id="saveCourseComment"> -- `parent_id` int(11) DEFAULT NULL COMMENT '父级评论id', -- `is_top` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否置顶:0不置顶,1置顶', -- `like_count` int(11) NOT NULL DEFAULT '0' COMMENT '点赞数', -- `is_reply` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否回复留言:0普通留言,1回复留言', -- `type` int(1) NOT NULL COMMENT '留言类型:0用户留言,1讲师留言,2运营马甲 3讲师回复 4小编回复 5官方客服回复', -- `status` int(1) NOT NULL COMMENT '留言状态:0待审核,1审核通过,2审核不通过,3已删除', -- `is_del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',0未删除 1已删除 -- `is_notify` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否发送了通知,1表示未发出,0表示已发出', -- `mark_belong` tinyint(1) DEFAULT '0' COMMENT '标记归属', -- `replied` tinyint(1) DEFAULT '0' COMMENT '回复状态 0 未回复 1 已回复', insert into course_comment(course_id,section_id,lesson_id,user_id,user_name,parent_id,is_top,comment,like_count,is_reply,type,status,create_time,update_time,is_del,last_operator,is_notify,mark_belong,replied) values (#{courseId},#{sectionId},#{lessonId},#{userId},#{userName},#{parentId},0,#{comment},0,0,#{type},0,sysdate(),sysdate(),0,#{lastOperator},1,0,0) </insert> <select id="getCourseCommentList" resultMap="CourseCommentMap"> select cc.id cc_id, cc.course_id, cc.section_id, cc.lesson_id, cc.user_id cc_user_id, cc.user_name, cc.parent_id, cc.is_top, cc.comment, cc.like_count, cc.is_reply, cc.type, cc.status, cc.create_time cc_create_time, cc.update_time cc_update_time, cc.is_del cc_is_del, cc.last_operator, cc.is_notify, cc.mark_belong, cc.replied, ccfr.id ccfr_id, ccfr.user_id ccfr_user_id, ccfr.comment_id, ccfr.is_del ccfr_is_del, ccfr.create_time ccfr_create_time, ccfr.update_time ccfr_update_time from course_comment cc left join (select * from course_comment_favorite_record where is_del=0) ccfr on cc.id=ccfr.comment_id where cc.course_id= #{courseId} and cc.is_del= 0 order by cc.is_top desc,cc.like_count desc,cc.create_time desc limit #{offset},#{pageSize} </select> <!--查看某个用户的某条留言是否存在点赞信息--> <select id="existsFavourite" resultType="int"> select count(*) from course_comment_favorite_record where user_id=#{userId} and comment_id=#{commentId} </select> <!--没有点赞信息,保存点赞信息--> <insert id="saveCommentFavourite"> insert into course_comment_favorite_record (user_id, comment_id, is_del, create_time, update_time) values (#{userId},#{commentId},0,sysdate(),sysdate()) </insert> <!--修改点赞的状态,0表示点赞,1表示取消赞--> <update id="updateCommentFavourite"> update course_comment_favorite_record set is_del=#{isDel} where comment_id=#{commentId} and user_id=#{userId} </update> <!--点赞之后,赞的数量+1;取消赞之后,赞的数量-1--> <update id="updateCommentLikeCount"> update course_comment set like_count =like_count+ #{x} where id=#{commentId} </update> </mapper>
@Test public void getComment(){ List<CourseComment> list = courseCommentDao.getCourseCommentList(7, 0, 20); for(CourseComment comment : list){ System.out.println("【"+comment.getUserName()+"】"+"留言:" + comment.getComment()); for(CourseCommentFavoriteRecord fr: comment.getFavoriteRecordList()){ System.out.println("--->" + fr.getUserId()); } } }
package controller; import com.alibaba.dubbo.config.annotation.Reference; import course.service.CourseCommentService; import entity.CourseComment; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.UnsupportedEncodingException; import java.util.List; /** * 课程留言表(CourseComment)表控制层 * * @author rf * @since 2021-08-08 15:24:35 */ @RestController @CrossOrigin(origins = "*") @RequestMapping("/course/comment") public class CourseCommentController { @Reference private CourseCommentService courseCommentService; @RequestMapping("/saveCourseComment") public CourseComment saveCourseComment(Integer courseId,Integer userId,String username,String comment) throws UnsupportedEncodingException { username = new String( username.getBytes("ISO-8859-1"),"UTF-8" ); comment = new String( comment.getBytes("ISO-8859-1"),"UTF-8" ); CourseComment courseComment = new CourseComment(); courseComment.setCourseId(courseId); // 课程编号 courseComment.setSectionId(0); // 章节编号,保留版本 courseComment.setLessonId(0);// 小节编号,保留版本 courseComment.setUserId(userId); // 用户编号 courseComment.setUserName(username); // 用户昵称 courseComment.setParentId(0); //没有父id,保留版本 courseComment.setComment(comment);// 留言内容 courseComment.setType(0); // 0用户留言,保留版本 courseComment.setLastOperator(userId); //最后操作的用户编号 Integer i = courseCommentService.saveCourseComment(courseComment); System.out.println(i); return courseComment; } @RequestMapping("/getCourseCommentList/{courseid}/{pageIndex}/{pageSize}") public List<CourseComment> getCommentsByCourseId(@PathVariable("courseid") Integer courseid, @PathVariable("pageIndex")Integer pageIndex,@PathVariable("pageSize")Integer pageSize){ int offset=(pageIndex-1)*pageSize; List<CourseComment> list = courseCommentService.getCourseCommentList(courseid, offset, pageSize); return list; } // 点赞 @RequestMapping("/saveFavorite/{commentid}/{userid}") public Integer saveFavorite(@PathVariable("commentid") Integer commentid,@PathVariable("userid") Integer userid){ Integer integer = courseCommentService.saveFavorite(userid,commentid); return integer; } // 取消赞 @RequestMapping("/cancelFavorite/{commentid}/{userid}") public Integer cancelFavorite(@PathVariable("commentid") Integer commentid,@PathVariable("userid") Integer userid){ Integer integer = courseCommentService.cancelFavorite(userid, commentid); return integer; } }
- 前端样式显示、点赞取消赞、发表留言
<template> <div> <Header></Header> <div style="background: #eee;"> <!-- 面包屑导航 --> <div class="nav-wrap"> <p class="nav-p-pc" style="margin-top:-25px;text-align:left;"> <a href="#">课程列表</a> <span class="sharp-content">></span> <span class="nav-sec">{{ course.courseName }}</span> </p> </div> <!-- 课程详情 --> <div class="container"> <div style="height: 100%;"> <div class="weui-tab content-wrapper"> <div id="vux_view_box_body" class="weui-tab__panel vux-fix-safari-overflow-scrolling" > <div style="position: relative;"> <div class="intro"> <div class="intro-content"> <img class="course-img" :src="course.courseImgUrl" alt="课程图片" /> <div class="conent-wrap"> <div class="name" style="text-align:left;"> {{ course.courseName }} </div> <div class="des text-omit" style="text-align:left;"> {{ course.brief }} </div> <div class="title"> <div class="teacher-name text-omit"> {{ course.teacher.teacherName }} <span class="line"></span> {{ course.teacher.position }} </div> </div> <div class="lesson-info"> <div class="boook-icon backgroun-img-set"></div> <div class="time"> {{ totalLesson }}讲 / {{ course.totalDuration }}课时 </div> <div class="person-icon backgroun-img-set"></div> <div class="person">{{ course.sales }}人已购买</div> </div> </div> </div> </div> </div> <!-- 课程信息 --> <div class="public-class-container is-pc"> <el-tabs v-model="activeName"> <el-tab-pane label="课程信息" name="intro"> <div v-html="course.courseDescription" class="content-p pc-background" ></div> <!-- 留言板 --> <!-- 留言板 开始--> <div class="message"> <div class="message-topic"> <div class="message-topic-title normal-font"> 精选留言 </div> </div> <div> <div class="message-edit"> <textarea rows="20" style="border:0px;resize: none;" contenteditable="true" placeholder="分享学习心得、思考感悟或者给自己一个小鼓励吧!" class="edit-div pcStyle" v-model="comment" ></textarea> <div class="message-edit-count"> <span class="message-edit-count-cur">0</span> <span class="message-edit-count-max">/2000</span> </div> </div> <div class="message-edit-footer flex"> <button class="message-edit-btn disableBg" @click="saveComment"> 发表留言 </button> </div> </div> <!-- 显示留言 --> <!-- 留言 开始 --> <div class="message-list" v-for="(comment, index) in commentList" :key="index" > <div class="message-list-title"> <div class="message-list-title-left"> <div class="message-list-title-left-name"> {{ comment.userName }} </div> <div class="message-list-title-left-tag"></div> </div> <!-- 没有点过赞 --> <div v-if=" JSON.stringify( comment.favoriteRecordList ).indexOf(user.content.id) < 0 " @click="zan(comment)" > <div class="message-list-title-right"> <!-- 未点赞图标 --> <img class="message-list-title-right-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAKlBMVEVHcExnZ2dzc3NmZmZqampmZmZmZmZnZ2dnZ2dnZ2dmZmZoaGhmZmZmZmZl+8SAAAAADXRSTlMA/AbsFtilbj5YwSqJPyESoQAAAZxJREFUOMt1lTtLA1EQha8xRhPTBEmhuKCCoNgoIlYLMcRKBG0sxIUgCDaBSDohEO0FEbQyIBZaBazERvAPWCwxPnP+i3tnrlGTmVPswn73NXNm7hrzq9m9kZ2ckTUUABifkOEBrK7liR7BMRFOA/uFc+BUgnV8mFisEW5IsIFi9FzBuwR91KJnAm8S9EIbxSBeBRZHk86MrBQJWjymJUC3nlugSyk+SQyhANfxos+s4krfM0DZvmbw2cuSCHNGi3PAfUygXYiU79ryyw1ibf0xZ9intBsz6SBadx24iiZXz8kPxCiTtYdLPzKTVFkkLQAZO/VikwYW/x/wHohcT/MiPQE8W9frxJrlbpiw4xvA0vbNmWyhj2Nrhmy+B7nEyTsN0rIaJAc0SDWqwX7rhAYfMa/Dui0bDZbwZAwUGNjWUWActnUUyN2hwDTaOkxRaSiwj6pRhjHKgTazSkWlwBK1jgIpBwrkHCgwyZ0oQ86BAjkHCjziG0KE8YBvCA/5KacOm6sgrHFAotouT6J23bkkLbsNDjM9yt7yP+IbQYga5De+eBMAAAAASUVORK5CYII=" alt="" /> <div class="message-list-title-right-praise"> {{ comment.likeCount }} </div> </div> </div> <!-- 点过赞 --> <div v-else @click="cancelzan(comment)"> <!-- 点赞图标 --> <div class="message-list-title-right"> <img class="message-list-title-right-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4BAMAAABaqCYtAAAAJFBMVEVHcEwAuI4AtIsAtIsAtIoAtYwAtIsAtYwAtowAx5kAtIsAs4qd4c1kAAAAC3RSTlMAGMfz3VGnbTYIhXtDq8EAAAETSURBVDjLldWhb8JAFAbwg8CGhGSGzNQtULNkWUioWbJkpmYKAQaBITPLLKZysmLz+xfolUL6/XM72msh9N2X8ImaX17vrq+vVeqU39XTuK/kdEMA01jGDY4ZyYWFIRPxp0S8u+8KeBJ+WDxIGFrMJbQm7qhVYSJgr8JUwNsKtYDtCiHgPavcsDVDstsuyDk7NeYDk6G8pM3bWXNawQUijWq8QyPPpQy+50ET9bF09go5pus3cMV0feFEc2DfieZRBU7Up7fjSkwZZgz3DA8MHxl6DP8YRgxjgokimDHcMdwyfGG4ZPjJMCKoY4KJIpgz3DHcMvQYFuPpk/005t1mffHlOs/ETvxXAA0Ul3oQHsp/xD93wxfHcC4VkwAAAABJRU5ErkJggg==" alt="" /> <div class="message-list-title-right-praise"> {{ comment.likeCount }} </div> </div> </div> </div> <div class="message-list-content"> {{ comment.comment }} </div> </div> <!-- 留言 结束 --> </div> <!-- 留言板 结束--> </el-tab-pane> <!-- 目录框 --> <el-tab-pane label="目录" name="directory"> <div class="class-menu-contaniner list-page-container more-sections more-sections-padding" > <!-- 章 开始 --> <div v-for="(section, index) in course.courseSections" :key="index" > <div class="section-name single-line"> {{ section.sectionName }} </div> <!-- 第一章节课时信息 --> <div v-if="index < 1"> <div class="class-menu-block"> <div v-for="(lesson, index) in section.courseLessons" :key="index" class="class-level-one over-ellipsis" @click="watchCourse(index, lesson, 1)" > <!-- 前两节课时 --> <div class="text-wrap"> <div class="content">{{ lesson.theme }}</div> <div class="item-status-wrap item-status-wrap-list" > <!-- 前两节课时 --> <div v-if="index < 2"> <!-- 如果未登录,可以试看前两节课时 --> <div v-if="!isLogin" class="item-status test-watch" > 试看 </div> <!-- 如果登录,且没有购买可以试看前两节课时 --> <div v-else-if="isLogin && !isBuy" class="item-status test-watch" > 试看 </div> <!-- 如果登录,且购买, 可以播放前两节课时 --> <div v-else class="item-status test-watch"> 播放 </div> </div> <!-- 其余课时 --> <div v-else> <!-- 如果未登录,加锁 --> <div v-if="!isLogin" class="item-status lock" ></div> <!-- 如果登录,且没有购买加锁 --> <div v-else-if="isLogin && !isBuy" class="item-status lock" ></div> <!-- 如果登录,且购买, 可以播放 --> <div v-else class="item-status test-watch"> 播放 </div> </div> </div> </div> </div> </div> </div> <!-- 其余章节课时信息 --> <div v-else> <div class="class-menu-block"> <div v-for="(lesson, index) in section.courseLessons" :key="index" class="class-level-one over-ellipsis" @click="watchCourse(index, lesson, 2)" > <div class="text-wrap"> <div class="content">{{ lesson.theme }}</div> <div class="item-status-wrap item-status-wrap-list" > <!-- 其余课时 --> <!-- 如果未登录,加锁 --> <div v-if="!isLogin" class="item-status lock" ></div> <!-- 如果登录,且没有购买加锁 --> <div v-else-if="isLogin && !isBuy" class="item-status lock" ></div> <!-- 如果登录,且购买, 可以播放 --> <div v-else class="item-status test-watch"> 播放 </div> </div> </div> </div> </div> </div> </div> </div> </el-tab-pane> </el-tabs> <div class="tab-fix-wrap"></div> <div></div> </div> </div> </div> </div> <!-- 底部购买 --> <div class="public-class-footer" slot="bottom" style="border:1px solid #eee; height:60px; text-align:left;" > <span class="product-descript" style="font-size:.347rem" >成就自己</span > <span class="current-price" style="font-size:28px"> <span class="current-price-unite" style="font-size:.347rem"> ¥</span >{{ course.discounts }} </span> <span class="current-price price"> <span class="current-price-unite">¥</span> {{ course.price }} </span> <button @click="buy(7)" type="button" class="weui-btn purchase-button weui-btn_mini weui-btn_primary" style="width:155px;height:45px;font-size:17px;" > 立即购买 <!-- ::after --> </button> </div> </div> </div> <Footer></Footer> </div> </template> <script> import Header from "./Header/Header"; //顶部登录条 import Footer from "./Footer/index"; //顶部登录条 export default { name: "Course", components: { Header, Footer, }, data() { return { activeName: "intro", course: null, totalLesson: 0, //总课时 commentList: null, // 留言列表 isLogin: false, //是否登录 user: null, //用户 isBuy: false, //是否购买 myCourseList: [], //已经购买的课程信息 comment:null,//发表的留言信息 }; }, created() { // 获取用户登录信息 this.user = JSON.parse(localStorage.getItem("user")); // 如果用户不为空,说明登录 if (this.user != null) { this.isLogin = true; // 获取已购课程信息 this.getMyCourseList(); } // 获取上一个页面传递的参数 this.course = this.$route.params.course; // 获取总课时数 let x = 0; for (let i = 0; i < this.course.courseSections.length; i++) { let section = this.course.courseSections[i]; for (let j = 0; j < section.courseLessons.length; j++) { x++; } } this.totalLesson = x; // 获取留言信息 this.getCommentList(); }, methods: { watchCourse(index, lesson, status) { // status是否是第一章节 if (status == 1 && index < 2) { // status是第一章节且是免费试看的章节 if (lesson.courseMedia == null) { // 是否有视频 this.$message.error("视频暂未上传"); } else { this.$message.success("观看第【" + lesson.id + "】节课程视频!"); this.$router.push({ name: "videoDetail", params: { course: this.course, lessonid: lesson.id, isBuy: this.isBuy, }, }); } } // 是否是免费试看的章节 else { //不是免费试看的章节 // 先登录 if (!this.isLogin) { this.$message.warning("请登录账号"); } else { // 查看该章节是否被购买 if (!this.isBuy) { this.$message.warning("请先购买"); } else { // 该章节购买 if (lesson.courseMedia == null) { // 是否有视频 this.$message.error("视频暂未上传"); } else { this.$message.success("观看第【" + lesson.id + "】节课程视频!"); this.$router.push({ name: "videoDetail", params: { course: this.course, lessonid: lesson.id, isBuy: this.isBuy, }, }); } } } } }, buy(courseid) { alert("购买第【" + courseid + "】门课程成功,加油!"); }, // 获取留言列表 getCommentList() { return this.axios .get( " http://localhost:8002/course/comment/getCourseCommentList/" + this.course.id + "/1/20" ) .then((res) => { this.commentList = res.data; console.log(this.commentList); }) .catch((err) => { this.$message.error("获取留言信息失败"); }); }, //获取已购买的课程信息 getMyCourseList() { return this.axios .get( "http://localhost:8002/course/getCourseByUserId/" + this.user.content.id ) .then((res) => { this.myCourseList = res.data; // 遍历课程,如果有已经购买的课程,isbuy值为true for (let i = 0; i < this.myCourseList.length; i++) { if (this.course.id == this.myCourseList[i].id) { this.isBuy = true; break; } } }) .catch((err) => { this.$message.error("获取已购课程失败"); }); }, // 点赞 zan(comment){ return this.axios .get( "http://localhost:8002/course/comment/saveFavorite/"+comment.id+"/" +this.user.content.id ) .then((res) => { this.getCommentList(); }) .catch((err) => { this.$message.error("点赞失败"); }); }, // 取消赞 cancelzan(comment){ return this.axios .get( "http://localhost:8002/course/comment/cancelFavorite/"+comment.id+"/" + this.user.content.id ) .then((res) => { this.getCommentList(); }) .catch((err) => { this.$message.error("取消点赞失败"); }); }, // 保存留言 saveComment(){ return this.axios .get( "http://localhost:8002/course/comment/saveCourseComment",{params:{ courseId:this.course.id, userId:this.user.content.id, username:this.user.content.name, comment:this.comment }} ) .then((res) => { this.getCommentList(); this.comment=null; }) .catch((err) => { this.$message.error("保存留言失败"); }); } }, }; </script> <style scoped> .message-edit-emojilist { position: absolute; top: 30px; left: 0; width: 415px; height: 180px; padding: 18px 10px; border: 1px solid #e2ebe8; box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.08); background: #fff; border-radius: 5px; z-index: 9; margin-bottom: 1.067rem; } .message-edit-emoji { font-size: 14px; color: #666; } .message-edit-footer { display: -webkit-box; display: -webkit-flex; display: flex; -webkit-flex-wrap: wrap; flex-wrap: wrap; -webkit-box-pack: justify; -webkit-justify-content: space-between; justify-content: space-between; margin-top: 20px; position: relative; } .message-edit-count-cur { margin-right: -5px; } .message-edit-count { position: absolute; bottom: 5px; right: 10px; font-size: 14px; text-align: right; -webkit-box-flex: 1; -webkit-flex: 1; flex: 1; color: #ccc; } .pcStyle { box-sizing: border-box; position: relative; line-height: 30px; margin-top: 6px; height: 100%; } .edit-div { width: 100%; line-height: 1.267rem; margin-top: 0.267rem; word-break: break-all; outline: none; color: #666; -webkit-user-select: text; user-select: text; text-align: left; font-size: 0.427rem; caret-color: #00b38a; border-bottom: 4px solid #fff; overflow: hidden; overflow-y: auto; } .message-edit { font-size: 16px; position: relative; padding: 0 14px 34px; height: 190px; border: 1px solid #ebebeb; border-radius: 4px; box-sizing: border-box; margin-top: 10px; } .message-topic { display: -webkit-box; display: -webkit-flex; display: flex; } .message-topic .normal-font { font-weight: 400; } * { margin: 0; padding: 0; } div { display: block; } .nav-wrap { padding-top: 40px; height: 50px; background: #fff; } .nav-p-pc { font-size: 16px; margin: 17px auto; vertical-align: top; width: 750px; } .nav-p-pc a:active, .nav-p-pc a:link, .nav-p-pc a:visited { color: #666; } .nav-p-pc .sharp-content { color: #666; margin-left: 5px; } .nav-p-pc .nav-sec { margin-left: 5px; color: #999; } .container { width: 750px; margin: 0 auto; } .intro-content { overflow: hidden; padding: 30px; position: relative; min-height: 133px; } .intro { background: #5b5d6e; font-family: PingFangSC-Regular; } .weui-tab__panel { box-sizing: border-box; height: 100%; padding-bottom: 1.333rem; overflow: auto; -webkit-overflow-scrolling: touch; } .content-wrapper { box-sizing: border-box; min-height: 100%; } .weui-tab { position: relative; height: 100%; } .conent-wrap { float: left; max-width: 450px; position: relative; } .name { font-family: PingFangSC-Medium; font-size: 20px; color: #fff; font-weight: 700; margin-bottom: 53px; } .text-omit { word-wrap: normal; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } .des { font-size: 14px; color: #fff; position: absolute; width: 450px; top: 36px; left: 0; } .title { font-size: 12px; line-height: 12px; color: #fff; overflow: hidden; margin-bottom: 13px; font-weight: 400; font-family: PingFangSC-Regular; } .teacher-name { float: left; } .line { width: 1px; height: 8px; opacity: 0.5; display: inline-block; background: #fff; margin-left: 10px; margin-right: 10px; } .lesson-info { overflow: hidden; font-family: PingFangSC-Regular; font-size: 12px; line-height: 20px; color: #fff; font-weight: 400; } .boook-icon[data-v-dd02a830] { width: 18px; height: 18px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAAXNSR…gip3QVDYmQv3MNonYRxetQvIHgUR3EkqN76xV++qd/7MATlNn5zIhsuCEAAAAASUVORK5CYII=); float: left; } .backgroun-img-set { background-repeat: no-repeat; background-size: 100% 100%; } .time { margin-left: 8px; float: left; } .person-icon { width: 18px; height: 18px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAAXNSR…JiFjKvv30ew3xoAZneN6xkDKPekFmAr5bL5fWApqD/vx34B1s5dQzzKE5bAAAAAElFTkSuQmCC); margin-left: 30px; float: left; } .backgroun-img-set { background-repeat: no-repeat; background-size: 100% 100%; } .person { margin-left: 4px; float: left; } .content-right { position: absolute; top: 118px; right: 40px; } .button-wrap { font-family: PingFangSC-Medium; font-size: 14px; color: #fff; height: 34px; padding: 0 22px; border: 1px solid hsla(0, 0%, 88%, 0.5); border-radius: 2px; line-height: 34px; font-weight: 700; cursor: pointer; position: relative; float: right; } .small-arrows { width: 10px; height: 10px; background-repeat: no-repeat; background-size: 100% 100%; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR…Myh+5soGuoF47UNoy6yQboOuombFBkAQ2lXtaje+zT1EIAsuukPgcISt4AAAAASUVORK5CYII=); top: 12px; right: 12px; position: absolute; } .pc-background, .public-class-container { background: #fff; min-height: calc(100vh - 4.4rem); content: "viewport-units-buggyfill; min-height: calc(100vh - 4.4rem)"; } .course-img { width: 102px; max-height: 133px; overflow: hidden; box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.1); border-radius: 2px; float: left; margin-right: 20px; } img { border: 0; vertical-align: top; display: inline-block; } .content-p { font-size: 0.873rem; color: #666; letter-spacing: 0; text-align: justify; line-height: 1.1rem; } .pc-background, .public-class-container { background: #fff; min-height: calc(100vh - 4.4rem); content: "viewport-units-buggyfill; min-height: calc(100vh - 4.4rem)"; } .pc-background { padding: 20px; } .public-class-footer { height: 1.733rem; width: 100%; line-height: 55px; position: fixed; bottom: 0; left: 0; right: 0; z-index: 2; padding: 0 0.4rem; border-top: 1px solid #eee; background: #fff; box-sizing: border-box; max-width: 750px; margin: 0 auto; } .public-class-footer { position: fixed; } .public-class-footer .product-descript { font-size: 0.347rem; color: #333; } .public-class-footer .current-price { font-size: 0.533rem; color: #ff7452; } .public-class-footer .current-price.price { color: #999; text-decoration: line-through; padding-left: 0.027rem; font-size: 0.16rem; } .public-class-footer .current-price { font-size: 0.533rem; color: #ff7452; } .public-class-footer .purchase-button { width: 4.8rem; height: 1.2rem; text-align: center; display: inline-block; font-size: 0.427rem; color: #fff; border: none; position: absolute; right: 0.267rem; top: 0.267rem; cursor: pointer; } .public-class-footer .current-price-unite { font-size: 0.347rem; margin-right: -0.133rem; } button { -webkit-appearance: button; text-rendering: auto; color: buttontext; letter-spacing: normal; word-spacing: normal; text-transform: none; text-indent: 0px; text-shadow: none; display: inline-block; text-align: center; align-items: flex-start; cursor: default; background-color: buttonface; box-sizing: border-box; margin: 0em; font: 400 13.3333px Arial; padding: 1px 6px; border-width: 2px; border-style: outset; border-color: buttonface; border-image: initial; } button, input, optgroup, select, textarea { margin: 0; padding: 0; border: 1px solid #ededed; border-radius: 0; font-family: Hiragino Sans GB, Microsoft Yahei, SimSun, Arial, Helvetica Neue, Helvetica; } .weui-btn { position: relative; display: block; margin-left: auto; margin-right: auto; padding-left: 0.373rem; padding-right: 0.373rem; box-sizing: border-box; font-size: 0.48rem; text-align: center; text-decoration: none; color: #fff; line-height: 2.33333333; border-radius: 4px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); overflow: hidden; } .weui-btn_primary { background-color: #00b38a; } .weui-btn_mini { display: inline-block; padding: 0 1.32em; line-height: 2.3; font-size: 0.347rem; } button.weui-btn, input.weui-btn { width: 100%; border-width: 0; outline: 0; -webkit-appearance: none; } .public-class-footer .purchase-button { width: 4.8rem; height: 1.2rem; text-align: center; display: inline-block; font-size: 0.427rem; color: #fff; border: none; position: absolute; right: 0.267rem; top: 0.267rem; cursor: pointer; } .class-menu-contaniner.more-sections-padding { padding-bottom: 3.04rem; } .class-menu-contaniner.more-sections { padding: 0 20px 50px 30px; } .class-menu-contaniner.list-page-container { padding: 20px 15px; background: #fff; } .class-menu-contaniner { background: #f6f6f6; } div { box-sizing: border-box; } .section-name { font-size: 18px; color: #333; font-weight: 700; padding: 30px 0 20px; max-width: 540px; font-family: PingFangSC-Regular; } .single-line { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; margin: 0px; text-align: left; line-height: 18px; } .class-menu-contaniner.more-sections .class-menu-block { background: #fbfbfb; font-size: 0.187rem; color: #333; } .class-menu-block { font-family: PingFangSC-Regular; font-size: 16px; font-weight: 400; } .class-menu-contaniner .more-sections .class-level-one { padding-left: 20px; font-size: 14px; min-height: auto; } .class-menu-contaniner .list-page-container .class-level-one { border-right: none; font-size: 16px; color: #333; padding-left: 15px; min-height: 62px; cursor: pointer; } .class-menu-contaniner .class-level-one { /* border:1px solid red; */ font-size: 14px; color: #666; position: relative; width: 100%; /* min-height: 90px; */ line-height: 50px; height: 50px; padding-left: 30px; border-right: 1px solid #ededed; cursor: pointer; } .class-level-one:hover { background: rgba(207, 198, 196, 0.534); } .class-menu-contaniner .over-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .class-menu-contaniner .class-level-one:first-child .text-wrap { border-top: none; } .class-menu-contaniner.list-page-container .class-level-one .text-wrap .content { width: 600px; word-break: break-all; white-space: normal; text-align: left; float: left; } .class-menu-contaniner.more-sections .class-level-one .item-status-wrap-list { top: 15px; } .class-menu-contaniner .class-level-one .item-status.lock { width: 20px; height: 20px; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAolJREFUWAntlztLA0EQx01ihIAW2om2VilCHoWN8dB0FpYi2PoNxMbaRvwGaieopaBWKlErIQ9SWNkqdlpoZSDxP5edY+9uk3snAbOwmd2d1y+zucvu2NioBatALJh7x7tWq6222+0N9GIsFpujVYzfMX5Ev8jlcnd+8wQCrNfrC61W6wgwy70AAPkQj8e3s9nsay87lc43YLVaXULAS8BNqwJb1wD5hbX1fD7/ZNX1msd7KbvpqHLQGXBI3kY/wtpiKpWaok5jWiMdxRFf5FL40pKrNu7KymIktpUr9wH1FipzbzF7xvwZlT6HPEWfJUjyxVhDd9U8bzE9EEhyS9FFdUoKOFNyQK5g4RaAej78HktuHxzPW4wkG1L2Yyc4shU2x+xnicHLSukHsMiRkOiEx05StsXYiOHk5xkQ26q/5ygwHoYXpwSsl23lGKzvJj0D4ttPcrB0Ov3DYycp28oxnPw8AzoFDFs/9IDK10yj0ZhvNpsHqIaGPht2VbrEo/dpOZlM7mYymTe2sQEKuAYMZtioz/ITkGDsQNq2WFRuUHBUixnBoNdF9Ven6Rp8JBKJNZxAbngepaxUKmuIfyVyaJzLVkEojN9cv+AIplAoXDOUzKAClOwGPxwBBt2D0CuIo9U++jfJoHDkHzogYu6I/9qdoQQE3ASBsQwKGUUFgzKZ/EeApnL4mIReQZyWf4mDpQ8mk0vogIh+CDg6aR+aMvmcqA4LPkN13HCD28OIeigtigqGAsZBRoBcCb9SVUG6G+hNHCJ5Gqm05DIYVA9JGSSbguYKjpGCdQle5nVbBelWBeUnGwxA0qWJGPRmA6TbFN2qoD1DN0rdMY/0k3KdyTe6SLP9m+B/vKTQX63cZOIAAAAASUVORK5CYII=) no-repeat; background-size: 100% 100%; margin-right: 14px; float: right; line-height: 20px; position: relative; top: 13px; right: 10px; } .class-menu-contaniner .class-level-one .item-status.test-watch { width: 46px; height: 20px; border: 1px solid rgba(0, 179, 138, 0.5); border-radius: 2px; font-size: 12px; text-align: center; display: table-cell; vertical-align: middle; color: #00b38a; line-height: 20px; position: relative; top: 13px; right: -25px; } .message { padding: 20px 20px 1.733rem; background: #fff; font-family: PingFangSC-Regular, PingFang SC; font-size: 16px; } .message-edit-emoji-icon { width: 20px; height: 20px; } img { border: 0; vertical-align: top; display: inline-block; } .disableBg { background: #ccc; } .message-edit-btn { background: #00b38a; color: #fff; font-size: 14px; width: 107px; height: 40px; line-height: 40px; border: none; border-radius: 4px; } .message-edit-emojilist em { margin-top: -29px; color: #e2ebe8; font-style: normal; } .message-edit-emojilist-tip { display: block; width: 30px; height: 16px; font-size: 12px; overflow: hidden; position: relative; margin-left: 15px; } em, i { font-style: normal; } .emoji-icon { margin: 8px; } .emoji_1f600 { background: url(https://www.lgstatic.com/mds-pipline-fed/instantMessaging/common/img/emojiSprite.8c9eba9b.png) -108px -36px no-repeat; background-size: 216px auto; } [class*=" emoji_"], [class^="emoji_"] { height: 18px; width: 18px; display: inline-block; } .message-list { color: #333; padding: 20px 0 30px; } .message-list-title-left, .message-list-title { display: -webkit-box; display: -webkit-flex; display: flex; } .message-list-title-left { -webkit-box-flex: 1; -webkit-flex: 1; flex: 1; -webkit-box-align: center; -webkit-align-items: center; align-items: center; text-align: left; } .message-list-title-left-name { font-size: 0.373rem; margin-right: 0.133rem; font-weight: 700; } .message-list-title-left-tag { min-width: 26px; height: 16px; line-height: 16px; padding: 1px 5px; text-align: center; border-radius: 1px; font-size: 10px; border-radius: 2px; color: #fff; } .message-list-title-right { overflow: hidden; display: -webkit-box; display: -webkit-flex; display: flex; -webkit-box-align: center; -webkit-align-items: center; align-items: center; } .message-list-title-right-icon { width: 14px; height: 14px; margin-right: 4px; } img { border: 0; vertical-align: top; display: inline-block; } .message-list-title-right-praise { height: 10px; font-size: 14px; font-family: PingFangSC-Regular, PingFang SC; font-weight: 400; color: #666; line-height: 13px; } .message-list-content { color: #666; font-size: 16px; margin-top: 10px; word-wrap: break-word; word-break: break-all; overflow: hidden; line-height: 30px; text-align: left; } .pointer { cursor: pointer; } .message-delete { color: #999; font-size: 14px; display: -webkit-box; display: -webkit-flex; display: flex; -webkit-box-align: center; -webkit-align-items: center; align-items: center; padding-top: 8px; position: relative; width: 50px; } .message-delete-icon { width: 14px; height: 14px; margin-right: 5px; } </style>
浙公网安备 33010602011771号