提交 dc6a4b8d 编写于 作者: guangjun.yang's avatar guangjun.yang

Merge branch 'dev-coursedetail-0817' of...

Merge branch 'dev-coursedetail-0817' of http://192.168.110.53/com.pica.cloud.education.frontend/pica-professional-exam into dev-coursedetail-0817

* 'dev-coursedetail-0817' of http://192.168.110.53/com.pica.cloud.education.frontend/pica-professional-exam:
  排查冲突
  逻辑对接

# Conflicts:
#	src/store/modules/user.js
...@@ -2674,12 +2674,14 @@ ...@@ -2674,12 +2674,14 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
...@@ -2694,17 +2696,20 @@ ...@@ -2694,17 +2696,20 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
...@@ -2821,7 +2826,8 @@ ...@@ -2821,7 +2826,8 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
...@@ -2833,6 +2839,7 @@ ...@@ -2833,6 +2839,7 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
...@@ -2847,6 +2854,7 @@ ...@@ -2847,6 +2854,7 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
...@@ -2854,12 +2862,14 @@ ...@@ -2854,12 +2862,14 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
...@@ -2878,6 +2888,7 @@ ...@@ -2878,6 +2888,7 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
...@@ -2958,7 +2969,8 @@ ...@@ -2958,7 +2969,8 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
...@@ -2970,6 +2982,7 @@ ...@@ -2970,6 +2982,7 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
...@@ -3091,6 +3104,7 @@ ...@@ -3091,6 +3104,7 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
......
<template> <template>
<div class="course-catalog"> <div class="course-catalog">
<div class="chapter-box"> <div class="chapter-box" v-for="(chapter, index) in list" :key="index">
<div class="head"> <div class="head">
<div class="name ellipsis">1.糖尿病的诊断与分型</div> <div class="name ellipsis">{{ chapter.chapterNameText }}</div>
<div class="total"> <div class="total" @click="onToggle(index)">
4 {{ chapter.lectureNum }}
<img class="arrow" src="~@/images/course/arrow_down.png" /> <img class="arrow" :class="{'arrow-active': chapter.showAll}" src="~@/images/course/arrow_down.png" />
</div> </div>
</div> </div>
<div class="lecture-box"> <div class="lecture-box" v-show="chapter.showAll">
<div class="item"> <div class="item"
<img class="icon" src="~@/images/course/array-right.png" /> :class="{'item-active': curtId === lecture.lectureId}"
<div class="info line"> v-for="lecture in chapter.lectures"
<p class="subname ellipsis">1.糖尿病的诊断</p> :key="lecture.lectureId"
<p class="time">时长: 03:56</p> @click="onSelect(lecture, 1)">
<img class="icon" src="~@/images/course/icon_play.png" />
<div class="info-box line">
<div class="info">
<p class="subname ellipsis">{{ lecture.lectureNameText }}</p>
<p class="time">
时长: {{ lecture.totalTimeText }}
<span>{{ lecture.statusText }}</span>
</p>
</div>
<div class="btn" v-if="lecture.btnText">{{ lecture.btnText }}</div>
<img v-else class="lock" src="~@/images/course/lock.png" alt="" />
</div> </div>
<div class="btn">学习</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -31,14 +41,18 @@ export default { ...@@ -31,14 +41,18 @@ export default {
default() { default() {
return [] return []
} }
},
curtId: {
type: Number,
default: 0,
},
onToggle: {
type: Function
},
onSelect: {
type: Function
} }
}, },
mounted() {
},
methods: {
}
}; };
</script> </script>
...@@ -82,24 +96,37 @@ export default { ...@@ -82,24 +96,37 @@ export default {
height: 12px; height: 12px;
transition: all 0.3s; transition: all 0.3s;
} }
.arrow-active{
transform: rotate(180deg);
}
} }
.lecture-box{ .lecture-box{
.item{ .item{
position: relative; position: relative;
display: flex; padding: 15px 0 0 25px;
padding: 15px 0 15px 30px; }
align-items: center; .item-active{
.subname, .time{
color: #449284;
}
} }
.icon{ .icon{
position: absolute; position: absolute;
left: 0; left: 0;
top: 18px; top: 20px;
width: 12px; width: 12px;
} }
.info-box{
position: relative;
display: flex;
align-items: center;
padding-bottom: 15px;
}
.info{ .info{
position: relative; position: relative;
flex: 1; flex: 1;
width: 100px; width: 100px;
padding-right: 5px;
} }
.line{ .line{
&::after{ &::after{
...@@ -125,8 +152,8 @@ export default { ...@@ -125,8 +152,8 @@ export default {
&::after{ &::after{
position: absolute; position: absolute;
content: ""; content: "";
left: 0; left: -1px;
top: 0; top: -1px;
width: 200%; width: 200%;
height: 200%; height: 200%;
border: 1px solid #449284; border: 1px solid #449284;
...@@ -135,6 +162,11 @@ export default { ...@@ -135,6 +162,11 @@ export default {
border-radius: 26px; border-radius: 26px;
} }
} }
.lock{
display: block;
width: 16px;
margin: 0 22px;
}
.subname{ .subname{
color: #676869; color: #676869;
font-size: 15px; font-size: 15px;
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
</div> </div>
</div> </div>
</div> </div>
<div class="go-app" @click="download">
<span>打开App,查看更多讨论内容</span>
</div>
</div> </div>
</template> </template>
...@@ -34,6 +37,9 @@ export default { ...@@ -34,6 +37,9 @@ export default {
default() { default() {
return [] return []
} }
},
download: {
type: Function
} }
}, },
data() { data() {
...@@ -151,5 +157,18 @@ export default { ...@@ -151,5 +157,18 @@ export default {
.show-arrow-up{ .show-arrow-up{
transform: rotate(180deg); transform: rotate(180deg);
} }
.go-app{
color: #449284;
font-size: 14px;
line-height: 14px;
text-align: center;
padding: 20px 0;
span{
display: inline-block;
padding-right: 20px;
background: url('~@/images/course/array-right.png') no-repeat right center;
background-size: 14px auto;
}
}
} }
</style> </style>
<template> <template>
<div class="course-covers-wrapper"> <div class="course-covers-wrapper">
<span class="tips" v-html="coverTips"></span> <div class="tips" v-html="coverTips"></div>
<div v-if="isShowBtn" class="course-button-group"> <div v-if="isShowBtn" class="course-button-group">
<CourseButton v-if="!isSingle" type="plain" @btnClick="btnClick(1)" :btnText="leftBtnText"></CourseButton> <CourseButton v-if="!isSingle" type="plain" @btnClick="btnClick(1)" :btnText="leftBtnText"></CourseButton>
<CourseButton @btnClick="btnClick(2)" :btnText="rightBtnText"></CourseButton> <CourseButton @btnClick="btnClick(2)" :btnText="rightBtnText"></CourseButton>
......
...@@ -16,6 +16,10 @@ export default { ...@@ -16,6 +16,10 @@ export default {
url: { url: {
type: String, type: String,
default: "" default: ""
},
visible: {
type: Boolean,
default: true,
} }
}, },
watch: { watch: {
...@@ -64,6 +68,18 @@ export default { ...@@ -64,6 +68,18 @@ export default {
viewport: viewport, viewport: viewport,
}); });
box.appendChild(canvas); box.appendChild(canvas);
if (!this.visible) {
let cover = document.createElement("div");
cover.className = 'canvas-cover';
cover.onclick = () => {
if (!this.$store.getter.logged) {
this.$store.dispatch('goLogin');
return;
}
this.$toast('前往APP购买查看')
}
box.appendChild(cover);
}
this.$el.appendChild(box); this.$el.appendChild(box);
} }
} }
...@@ -76,7 +92,17 @@ export default { ...@@ -76,7 +92,17 @@ export default {
overflow: hidden; overflow: hidden;
/deep/ .canvas-box{ /deep/ .canvas-box{
position: relative; position: relative;
padding-bottom: 30px; margin-bottom: 30px;
}
/deep/ .canvas-cover{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: url('~@/images/course/lock-big.png') no-repeat center center;
background-size: 50px auto;
background-color: rgba(255, 255, 255, .2);
} }
/deep/ canvas{ /deep/ canvas{
display: block; display: block;
......
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
@error="onError" @error="onError"
> >
</video> </video>
<div class="video-cover"></div> <div class="video-cover" @click="showControl = !showControl"></div>
<!-- 控制栏 --> <!-- 控制栏 -->
<div class="control-box"> <div class="control-box" v-show="showControl">
<div class="control-bar"> <div class="control-bar">
<div class="btn-play" :class="{'btn-pause': isPaused}" @click="togglePlay"></div> <div class="btn-play" :class="{'btn-pause': isPaused}" @click="togglePlay"></div>
<div class="progress-box" @click="setProgress"> <div class="progress-box" @click="setProgress">
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
</div> </div>
</div> </div>
<div class="time-box">{{ playTime }}/{{ totalTime }}</div> <div class="time-box">{{ playTime }}/{{ totalTime }}</div>
<div class="rate-box" @click="showRate=true"> <!-- <div class="rate-box" @click="showRate=true">
倍速 倍速
<div class="rate-list" v-show="showRate"> <div class="rate-list" v-show="showRate">
<div <div
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
:key="rate" :key="rate"
@click.stop="selectRate(rate)">{{ rate }}</div> @click.stop="selectRate(rate)">{{ rate }}</div>
</div> </div>
</div> </div> -->
<div class="btn-screen" :class="{'btn-screen-mini': isFullScreen}" @click="onFullscreen"></div> <div class="btn-screen" :class="{'btn-screen-mini': isFullScreen}" @click="onFullscreen"></div>
</div> </div>
</div> </div>
...@@ -73,9 +73,10 @@ ...@@ -73,9 +73,10 @@
<slot></slot> <slot></slot>
<!-- 试看提示 --> <!-- 试看提示 -->
<div class="proved-box" v-show="showProved"> <div class="proved-box" v-show="showProved">
可试看{{ proved > 59 ? `${parseInt(proved / 60)}分钟` : `${proved}秒` }},激活/购买后可看完整课程 可试看{{ proved > 59 ? `${parseInt(proved / 60)}分钟` : `${proved}秒` }},观看完整版请来 <span @click="download">云鹊医App</span>
<div class="proved-close" @click="showProved=false"></div>
</div> </div>
<!-- 重新播放,只有试看有 -->
<div class="replay-box" v-show="showReplay" @click="onReplay">重新播放</div>
</div> </div>
</template> </template>
...@@ -97,6 +98,12 @@ import { formatLeftTimeObj } from '@/utils'; ...@@ -97,6 +98,12 @@ import { formatLeftTimeObj } from '@/utils';
export default { export default {
name: 'pica-video', name: 'pica-video',
props: {
download: {
type: Function,
default: () => {}
}
},
data() { data() {
return { return {
url: '', // 视频链接 url: '', // 视频链接
...@@ -109,6 +116,7 @@ export default { ...@@ -109,6 +116,7 @@ export default {
totalTime: '00:00', // 总时长 totalTime: '00:00', // 总时长
isPaused: true, // 是否暂停 isPaused: true, // 是否暂停
isFullScreen: false, // 是否全屏 isFullScreen: false, // 是否全屏
showControl: true, // 显示控制栏
progressBar: {}, // 进度条 progressBar: {}, // 进度条
progressBall: 0, // 进度球 progressBall: 0, // 进度球
rates: [2, 1.5, 1, 0.5], rates: [2, 1.5, 1, 0.5],
...@@ -117,6 +125,7 @@ export default { ...@@ -117,6 +125,7 @@ export default {
showProved: false, // 试看提示文字 showProved: false, // 试看提示文字
showError: false, // 播放错误 showError: false, // 播放错误
showResume: false, // 继续播放 showResume: false, // 继续播放
showReplay: false, // 显示重播
} }
}, },
computed: { computed: {
...@@ -157,10 +166,17 @@ export default { ...@@ -157,10 +166,17 @@ export default {
} }
if (isPaused) { if (isPaused) {
this.player.play(); this.player.play();
if (this.opts.proved > 0) {
this.showProved = true;
this.provedTimer && clearTimeout(this.provedTimer);
this.provedTimer = setTimeout(() => {
this.showProved = false;
}, 5000)
}
} else { } else {
this.player.pause(); this.player.pause();
} }
// this.reportOnOff(isPaused ? 1 : 2); this.reportOnOff(isPaused ? 1 : 2);
this.isPaused = !isPaused; this.isPaused = !isPaused;
}, },
// 切换视频 // 切换视频
...@@ -173,12 +189,12 @@ export default { ...@@ -173,12 +189,12 @@ export default {
this.proved = proved; this.proved = proved;
this.history = history; this.history = history;
this.enable = enable; this.enable = enable;
this.showProved = proved > 0;
this.provedOver = false; this.provedOver = false;
this.finish = false; this.finish = false;
this.opts = opts; this.opts = opts;
this.currentTime = null; this.currentTime = null;
this.duration = null; this.duration = null;
this.showReplay = false;
if (this.showError) this.showError = false; if (this.showError) this.showError = false;
}, },
// 切换并播放 // 切换并播放
...@@ -205,6 +221,14 @@ export default { ...@@ -205,6 +221,14 @@ export default {
} }
this.timer = loop(); this.timer = loop();
}, },
// 重播
onReplay() {
this.player.currentTime = 0;
this.player.play();
this.isPaused = false;
this.reportOnOff(1);
this.$emit('onReplay')
},
// 加载完毕,获取总时长和音量。问题:移动端点击播放才会触发,且不一定会获取时长 // 加载完毕,获取总时长和音量。问题:移动端点击播放才会触发,且不一定会获取时长
loadedMetaData() { loadedMetaData() {
let duration = this.player.duration; let duration = this.player.duration;
...@@ -275,7 +299,7 @@ export default { ...@@ -275,7 +299,7 @@ export default {
if (this.isPaused) { if (this.isPaused) {
this.player.play(); this.player.play();
this.isPaused = false; this.isPaused = false;
// this.reportOnOff(1); this.reportOnOff(1);
} }
}, },
// 拖动进度条 // 拖动进度条
...@@ -323,10 +347,10 @@ export default { ...@@ -323,10 +347,10 @@ export default {
// 试看结束 // 试看结束
provedEnd() { provedEnd() {
this.provedOver = true; this.provedOver = true;
this.showProved = false;
this.player.pause(); this.player.pause();
this.$emit('onVideoEnd', { type: 2 }); this.$emit('onVideoEnd', { type: 2 });
this.finish = true; this.finish = true;
this.showReplay = true;
this.reportOnOff(2); this.reportOnOff(2);
}, },
// 播放结束 // 播放结束
...@@ -347,7 +371,10 @@ export default { ...@@ -347,7 +371,10 @@ export default {
// 上报播放、暂停,status:1开始,2暂停 // 上报播放、暂停,status:1开始,2暂停
reportOnOff(status = 1) { reportOnOff(status = 1) {
const { chapterId, courseId, lectureId } = this.opts; const { chapterId, courseId, lectureId } = this.opts;
this.$api.pauseCourse({ if (!chapterId || !courseId || !lectureId) {
return;
}
this.POST('/contents/files/resourceRecord', {
fileType: 1, fileType: 1,
resourceInfo1: courseId, resourceInfo1: courseId,
resourceInfo2: chapterId, resourceInfo2: chapterId,
...@@ -356,7 +383,6 @@ export default { ...@@ -356,7 +383,6 @@ export default {
status, status,
systemType: 3, systemType: 3,
timestamp: Date.now(), timestamp: Date.now(),
showError: false,
}) })
}, },
// 上报离开 // 上报离开
...@@ -365,7 +391,10 @@ export default { ...@@ -365,7 +391,10 @@ export default {
return; return;
} }
const { chapterId, courseId, lectureId } = this.opts; const { chapterId, courseId, lectureId } = this.opts;
this.$api.joinCourse({ if (!chapterId || !courseId || !lectureId) {
return;
}
this.POST('/contents/joinCourse/', {
requestList: [{ requestList: [{
chapterId, chapterId,
courseId, courseId,
...@@ -374,7 +403,6 @@ export default { ...@@ -374,7 +403,6 @@ export default {
time: this.duration, time: this.duration,
timeStamp: Date.now(), timeStamp: Date.now(),
}], }],
showError: false,
}) })
}, },
}, },
...@@ -530,24 +558,16 @@ export default { ...@@ -530,24 +558,16 @@ export default {
position: absolute; position: absolute;
color: #fff; color: #fff;
font-size: 12px; font-size: 12px;
left: 20px; left: 10px;
bottom: 70px; bottom: 44px;
height: 30px; height: 24px;
line-height: 30px; line-height: 24px;
padding: 0 27px 0 31px; padding: 0 12px;
border-radius: 15px; border-radius: 12px;
background: url('~@/images/video/tip.png') no-repeat 12px center; background-color: rgba(0, 0, 0, .6);
background-size: 14px auto; span{
background-color: #373839; color: #FFA34B;
} }
.proved-close{
position: absolute;
right: 0;
top: 0;
width: 30px;
height: 30px;
background: url('~@/images/video/close.png') no-repeat 10px center;
background-size: 10px auto;
} }
.cover-play{ .cover-play{
background: url('~@/images/video/cover_play.png') no-repeat center center; background: url('~@/images/video/cover_play.png') no-repeat center center;
...@@ -565,6 +585,20 @@ export default { ...@@ -565,6 +585,20 @@ export default {
transform: translate3d(0, -50%, 0); transform: translate3d(0, -50%, 0);
} }
} }
.replay-box{
position: absolute;
color: #fff;
font-size: 12px;
right: 10px;
bottom: 44px;
height: 24px;
line-height: 24px;
padding: 0 12px 0 22px;
border-radius: 12px;
background: url('~@/images/video/replay.png') no-repeat left center;
background-size: 23px auto;
background-color: rgba(0, 0, 0, .6);
}
.cover{ .cover{
position: absolute; position: absolute;
left: 0; left: 0;
......
...@@ -53,13 +53,30 @@ const router = new VueRouter({ ...@@ -53,13 +53,30 @@ const router = new VueRouter({
} }
}) })
router.beforeEach((to, from, next) => { // 过滤路由
let query = { ...to.query }; function fliterRoute(query, path) {
let has = false;
// 登录token保存并替换路径 // 登录token保存并替换路径
if (query.token && query.token != 'undefined') { if (query.token && query.token != 'undefined') {
store.dispatch('setToken', query.token); store.dispatch('setToken', query.token);
delete query.token; delete query.token;
next({ path: to.path, query: query, replace: true }); has = true;
}
// 课程详情页去掉projectId
if (path === '/course-detail' && query.projectId) {
sessionStorage.setItem('projectId', query.projectId);
delete query.projectId;
has = true;
}
return [query, has];
}
router.beforeEach((to, from, next) => {
let query = { ...to.query };
// 登录token保存并替换路径
let [newQuery, has] = fliterRoute(query, to.path);
if (has) {
next({ path: to.path, query: newQuery, replace: true });
return; return;
} }
next(); next();
......
...@@ -42,16 +42,16 @@ const user = { ...@@ -42,16 +42,16 @@ const user = {
const { certifyDoc, isExist } = res.data; const { certifyDoc, isExist } = res.data;
const picapDoctor = res.data.picapDoctor || {}; const picapDoctor = res.data.picapDoctor || {};
if (picapDoctor.id) { if (picapDoctor.id) {
let avatar = picapDoctor.avatar_image_url || ''; // let avatar = picapDoctor.avatar_image_url || '';
let avatarUrl = ''; let avatarUrl = '';
const img1 = await preLoadImg(`https://test-file.yunqueyi.com${avatar}`).catch(err => console.error(err)); // const img1 = await preLoadImg(`https://test-file.yunqueyi.com${avatar}`).catch(err => console.log(err));
const img2 = await preLoadImg(`https://file.yunqueyi.com${avatar}`).catch(err => console.error(err)); // const img2 = await preLoadImg(`https://file.yunqueyi.com${avatar}`).catch(err => console.log(err));
if (img1) { // if (img1) {
avatarUrl = img1.src; // avatarUrl = img1.src;
} // }
if (img2) { // if (img2) {
avatarUrl = img2.src; // avatarUrl = img2.src;
} // }
picapDoctor.avatar = avatarUrl || 'https://file.yunqueyi.com/File/doctor_default.png'; picapDoctor.avatar = avatarUrl || 'https://file.yunqueyi.com/File/doctor_default.png';
commit('SET_USER_INFO', { ...picapDoctor, isExist, certifyDoc }); commit('SET_USER_INFO', { ...picapDoctor, isExist, certifyDoc });
} }
......
...@@ -2,7 +2,30 @@ ...@@ -2,7 +2,30 @@
<div class="course-detail"> <div class="course-detail">
<!-- 视频 --> <!-- 视频 -->
<div class="video-box"> <div class="video-box">
<pica-video ref="picaVideo" @onVideoEnd="onVideoEnd" /> <pica-video ref="picaVideo" @onVideoEnd="onVideoEnd" @onReplay="onReplay">
<!-- 试看结束 -->
<div class="cover" v-if="logged && coverType === 1">
<course-covers coverTips="试看结束<br />请来云鹊医App学习完整课程" :isSingle="true" rightBtnText="学习完整课程" @btnClick="btnClick" />
</div>
<!-- 付费课程,下载App -->
<div class="cover" v-if="logged && coverType === 2">
<course-covers coverTips="本课程为付费课程,请来云鹊医App学习" :isSingle="true" rightBtnText="去云鹊医App" @btnClick="btnClick" />
</div>
<!-- 下一个提示 -->
<div class="next-countdown" v-if="coverType === 3">3秒后播放下一节</div>
<!-- 未学完提示 -->
<div class="cover" v-if="logged && coverType === 4">
<course-covers coverTips="您已学习至最后一节<br />但本课程中仍有未学完的内容" :isSingle="true" rightBtnText="继续学完本课程" @btnClick="btnClick" />
</div>
<!-- 已学完,无考试 -->
<div class="cover" v-if="logged && coverType === 5">
<course-covers coverTips="您已完成全部学习<br />来云鹊医App参加考试巩固学习成果" leftBtnText="返回项目" @btnClick="btnClick" />
</div>
<!-- 未登录 -->
<div class="cover" v-if="!logged">
<course-covers coverTips="登录后马上学习课程" :isSingle="true" rightBtnText="去登录" @btnClick="goLogin" />
</div>
</pica-video>
</div> </div>
<!-- 内容滚动 --> <!-- 内容滚动 -->
<div class="scroll-box"> <div class="scroll-box">
...@@ -14,7 +37,10 @@ ...@@ -14,7 +37,10 @@
</span>{{ course.courseName }} </span>{{ course.courseName }}
</div> </div>
<div class="course-num"> <div class="course-num">
<span>{{ course.joinNum }}</span>人已学 / <span>{{ course.favorNum }}</span>人收藏 <span class="num">{{ course.joinNum }}</span>人已学 /
<span class="num">{{ course.favorNum }}</span>人收藏
<span v-if="course.status === 3 || course.status === 4">/ 总进度<i class="percent">100%</i></span>
<img v-if="course.status === 4" class="img" src="~@/images/has-cert-new.png" alt="" />
</div> </div>
</div> </div>
<!-- tab栏 --> <!-- tab栏 -->
...@@ -34,13 +60,13 @@ ...@@ -34,13 +60,13 @@
</van-sticky> </van-sticky>
</div> </div>
<brief-intro v-show="curtTabIdx === 0" :doctor-list="doctors" :intro="course.intro" :harvest="harvest" /> <brief-intro v-show="curtTabIdx === 0" :doctor-list="doctors" :intro="course.intro" :harvest="harvest" />
<course-catalog v-show="curtTabIdx === 1" /> <course-catalog v-show="curtTabIdx === 1" :list="chapters" :curtId="curtLectureId" :onToggle="onToggle" :onSelect="selectLecture" :download="download" />
<course-ware v-show="curtTabIdx === 2" :url="pdfUrl" /> <course-ware v-show="curtTabIdx === 2" :url="pdfUrl" :visible="pdfVisible" />
<course-comment v-show="curtTabIdx === 3" :list="qsList" /> <course-comment v-show="curtTabIdx === 3" :list="qsList" :download="download" />
</div> </div>
</div> </div>
<!-- 打开、下载App --> <!-- 打开、下载App -->
<div class="download-box"> <!-- <div class="download-box">
<img src="~@/images/icon-pica.png" alt="logo" /> <img src="~@/images/icon-pica.png" alt="logo" />
<div class="content"> <div class="content">
<p class="title">云鹊医</p> <p class="title">云鹊医</p>
...@@ -48,7 +74,7 @@ ...@@ -48,7 +74,7 @@
</div> </div>
<div class="btn-download">下载</div> <div class="btn-download">下载</div>
<div class="btn-open">打开</div> <div class="btn-open">打开</div>
</div> </div> -->
<Loading v-if="showLoading" /> <Loading v-if="showLoading" />
</div> </div>
...@@ -56,16 +82,18 @@ ...@@ -56,16 +82,18 @@
<script> <script>
import PicaVideo from '@/components/course/pica-video'; import PicaVideo from '@/components/course/pica-video';
import CourseCovers from '@/components/course/course-covers';
import BriefIntro from '@/components/course/brief-intro'; import BriefIntro from '@/components/course/brief-intro';
import CourseCatalog from '@/components/course/course-catalog'; import CourseCatalog from '@/components/course/course-catalog';
import CourseWare from '@/components/course/course-ware'; import CourseWare from '@/components/course/course-ware';
import CourseComment from '@/components/course/course-comment'; import CourseComment from '@/components/course/course-comment';
import Loading from "@/components/common/common-loading"; import Loading from "@/components/common/common-loading";
import { getPdfFileUrl, formatLeftTimeObj } from '@/utils'; import { getPdfFileUrl, formatLeftTimeObj, deepCopy } from '@/utils';
export default { export default {
components: { components: {
PicaVideo, PicaVideo,
CourseCovers,
BriefIntro, BriefIntro,
CourseCatalog, CourseCatalog,
CourseWare, CourseWare,
...@@ -90,13 +118,26 @@ export default { ...@@ -90,13 +118,26 @@ export default {
curtLectureId: 0, // 当前播放课件id curtLectureId: 0, // 当前播放课件id
pdfUrl: '', // 当前pdf pdfUrl: '', // 当前pdf
qsList: [], // 讨论列表 qsList: [], // 讨论列表
coverType: 0, // 遮罩,
showLoading: false, showLoading: false,
}; };
}, },
computed: { computed: {
logged() {
return this.$store.getters.logged;
},
tabLeft() { tabLeft() {
const num = this.curtTabIdx + 0.5; const num = this.curtTabIdx + 0.5;
return this.tabW * num; return this.tabW * num;
},
// 当前pdf是否可看
pdfVisible() {
const { showFlag, hidePpt } = this.course;
let visible = false;
if (showFlag === 0 && !hidePpt && this.logged) {
visible = true;
}
return visible;
} }
}, },
mounted() { mounted() {
...@@ -104,15 +145,17 @@ export default { ...@@ -104,15 +145,17 @@ export default {
if (token && !info.id) { if (token && !info.id) {
this.$store.dispatch('getUserInfo'); this.$store.dispatch('getUserInfo');
} }
// this.projectId = sessionStorage.getItem('projectId');
// if (!this.projectId) {
// this.$router.push('')
// return;
// }
this.getCourseInfo(); this.getCourseInfo();
this.getCourseQas(); this.getCourseQas();
const { height } = this.$el.querySelector('.video-box').getBoundingClientRect(); const { height } = this.$el.querySelector('.video-box').getBoundingClientRect();
const { width } = this.$el.querySelector('.tab-item').getBoundingClientRect(); const { width } = this.$el.querySelector('.tab-item').getBoundingClientRect();
this.videoH = height; this.videoH = height;
this.tabW = width; this.tabW = width;
this.$refs.picaVideo.switchUrl({
url: 'https://video.yunqueyi.com/TNB/002/01_01_APP_SD.mp4',
});
}, },
methods: { methods: {
getCourseInfo() { getCourseInfo() {
...@@ -148,34 +191,65 @@ export default { ...@@ -148,34 +191,65 @@ export default {
} }
} }
this.course = { ...courseHeader, intro, showFlag, trySeeFlag, trySeeTime }; this.course = { ...courseHeader, intro, showFlag, trySeeFlag, trySeeTime };
const [chaptersAll, curtLecture] = this.getAllChapters(chapters, lectureResourceList, lastLecture); const [chaptersAll, curtLecture] = this.getAllChapters(chapters, lectureResourceList, lastLecture, showFlag, trySeeFlag);
this.chapters = chaptersAll; this.chapters = chaptersAll;
this.curtLectureId = curtLecture.lectureId; this.curtLectureId = curtLecture.lectureId;
this.pdfUrl = getPdfFileUrl(curtLecture.courseware.filePath); this.pdfUrl = getPdfFileUrl(curtLecture.courseware.filePath);
// 付费课程-请去App查看;或可试看且时长为0
let enable = true;
if (showFlag === 10 || (trySeeFlag && !trySeeTime)) {
this.coverType = 2;
enable = false
}
let history = 0;
if (curtLecture.progress < 1 && !trySeeTime) {
history = curtLecture.lastTime === 1 ? 0 : curtLecture.lastTime
}
this.$refs.picaVideo.switchUrl({
chapterId: curtLecture.chapterId,
courseId: curtLecture.courseId,
lectureId: curtLecture.lectureId,
url: curtLecture.pathUrl,
proved: trySeeTime,
history,
enable, // 付费课程-请去App查看;或可试看且时长为0
});
} else { } else {
this.$toast(res.message); this.$toast(res.message);
} }
}); });
}, },
// 将课件挂在目录上,获取播放id // 将课件挂在目录上,获取播放id
getAllChapters(chapters, resList, lastLecture) { getAllChapters(chapters, resList, lastLecture, showFlag, trySeeFlag) {
const lectureObj = {}; const lectureObj = {};
for (let item of resList) { for (let item of resList) {
lectureObj[item.lectureId] = { ...item }; lectureObj[item.lectureId] = { ...item };
} }
let count = 0;
let curtLecture = {}; let curtLecture = {};
let unfinished = false; let unfinished = false;
for (let chapter of chapters) { for (let i = 0; i < chapters.length; i++) {
for (let lecture of chapter.lectures) { let chapter = chapters[i];
count += 1; chapter.chapterNameText = `${i + 1}.${chapter.chapterName}`;
chapter.showAll = true;
for (let j = 0; j < chapter.lectures.length; j++) {
let lecture = chapter.lectures[j];
let lectureId = lecture.lectureId; let lectureId = lecture.lectureId;
if (lectureObj[lectureId]) { if (lectureObj[lectureId]) {
lecture.courseware = lectureObj[lectureId] lecture.courseware = lectureObj[lectureId]
} }
const num = count < 10 ? `0${count}` : count; lecture.lectureNameText = `${j + 1}.${lecture.lectureName}`;
lecture.lectureNameText = `${num}.${lecture.lectureName}`;
lecture.statusText = lecture.progress === 0 ? '未开始' : (lecture.progress === 1 ? '已学习' : `已学${lecture.progress * 100}%`); lecture.statusText = lecture.progress === 0 ? '未开始' : (lecture.progress === 1 ? '已学习' : `已学${lecture.progress * 100}%`);
let btnText = '';
if (showFlag === 10 || (trySeeFlag && !trySeeTime)) {
btnText = ''; // 不可看
}
if (showFlag === 20 && trySeeFlag && trySeeTime) {
btnText = '试看'; // 可试看
}
if (showFlag === 0) {
btnText = lecture.progress === 100 ? '复习课程' : '学习';
}
lecture.btnText = btnText;
const totalTime = formatLeftTimeObj(lecture.totalTime); const totalTime = formatLeftTimeObj(lecture.totalTime);
const h = totalTime.h === '00' ? '' : `${totalTime.h}:`; const h = totalTime.h === '00' ? '' : `${totalTime.h}:`;
lecture.totalTimeText = `${h}${totalTime.f}:${totalTime.s}`; lecture.totalTimeText = `${h}${totalTime.f}:${totalTime.s}`;
...@@ -194,11 +268,70 @@ export default { ...@@ -194,11 +268,70 @@ export default {
} }
return [chapters, curtLecture]; return [chapters, curtLecture];
}, },
btnClick(index) {
const coverType = this.coverType;
switch(coverType) {
case 1:
case 2:
this.download();
break;
case 4:
this.selectLecture(this.prev);
break;
case 5:
if (index === 1) {
window.history.back();
} else {
this.download();
}
break;
default:
//
}
},
// 折叠、展开目录
onToggle(index) {
const item = this.chapters[index];
item.showAll = !item.showAll;
this.chapters.splice(index, 1, item);
},
// 选择课程
selectLecture(lecture, isUserSelect) {
if (isUserSelect && !this.logged) {
this.goLogin();
return;
}
const { showFlag, trySeeFlag, trySeeTime, examType } = this.course;
// console.log(lecture);
if (examType === 2) { // 是考试,mustLearnIds必须完成的lectureId
this.$toast('请前往云鹊医APP进行考试');
return;
}
let enable = true;
if (showFlag === 10 || (trySeeFlag && !trySeeTime)) {
this.coverType = 2;
enable = false
} else {
this.coverType = 0;
}
this.curtLectureId = lecture.lectureId;
let history = 0;
if (lecture.progress < 1) {
history = lecture.lastTime === 1 ? 0 : lecture.lastTime
}
this.$refs.picaVideo.switchUrlAndPlay({
chapterId: lecture.chapterId,
courseId: lecture.courseId,
lectureId: lecture.lectureId,
url: lecture.pathUrl,
proved: trySeeTime,
history,
enable, // 付费课程-请去App查看;或可试看且时长为0
});
},
getCourseQas() { getCourseQas() {
const { projectId = 797, courseId = 3 } = this.$route.query; const { projectId = 797, courseId = 3 } = this.$route.query;
this.showLoading = true;
this.GET(`/contents/courses/v2/${courseId}/qas`, { projectId, pageNo: 1, pageSize: 10 }).then(res => { this.GET(`/contents/courses/v2/${courseId}/qas`, { projectId, pageNo: 1, pageSize: 10 }).then(res => {
this.showLoading = false;
if (res.code == "000000") { if (res.code == "000000") {
this.qsList = res.data.model && res.data.model.qaPostModel || []; this.qsList = res.data.model && res.data.model.qaPostModel || [];
} else { } else {
...@@ -207,8 +340,61 @@ export default { ...@@ -207,8 +340,61 @@ export default {
}); });
}, },
// 视频播放结束 // 视频播放结束
onVideoEnd() { onVideoEnd(opt) {
if (opt.type === 1) {
let chapters = deepCopy(this.chapters);
let curtI = 0;
let curtJ = 0;
let curtIndex = 0;
let count = 0;
let prev; // 第一个未完成的
for (let i = 0; i < chapters.length; i++) {
let lectures = chapters[i]['lectures'];
for (let j = 0; j < lectures.length; j++) {
count += 1;
let lecture = lectures[j];
if (this.curtLectureId === lecture.lectureId) {
curtIndex = count;
curtI = i;
curtJ = j;
lecture.progress = 1;
lecture.statusText = '已学习';
lecture.btnText = '复习课程';
}
if (!prev && lecture.progress < 1) {
prev = { ...lecture }
}
}
}
if (curtIndex === count) { // 最后一个
if (prev) {
this.coverType = 4;
this.prev = prev;
} else {
this.coverType = 5;
this.course.status = 3;
}
} else { // 3秒后播放下一个
let next = chapters[curtI]['lectures'][curtJ + 1] || chapters[curtI + 1]['lectures'][0];
this.coverType = 3;
setTimeout(() => {
this.selectLecture(next);
}, 3000)
}
this.chapters = chapters;
} else if (opt.type === 2) { // 试看结束
this.coverType = 1;
}
},
onReplay() {
this.coverType = 0;
},
goLogin() {
this.$store.dispatch('goLogin');
},
// 去下载app
download() {
window.location.href = "https://a.app.qq.com/o/simple.jsp?pkgname=com.picahealth.yunque";
} }
} }
}; };
...@@ -234,7 +420,7 @@ export default { ...@@ -234,7 +420,7 @@ export default {
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
.scroll-content{ .scroll-content{
padding-bottom: 60px; // padding-bottom: 60px;
} }
.course-info{ .course-info{
padding: 20px 15px; padding: 20px 15px;
...@@ -261,9 +447,16 @@ export default { ...@@ -261,9 +447,16 @@ export default {
color: #676869; color: #676869;
font-size: 13px; font-size: 13px;
margin-top: 10px; margin-top: 10px;
span{ .num{
color: #373839; color: #373839;
} }
.percent{
color: #4B9D8F;
}
.img{
float: right;
height: 20px;
}
} }
.tab-box{ .tab-box{
height: 50px; height: 50px;
...@@ -359,6 +552,18 @@ export default { ...@@ -359,6 +552,18 @@ export default {
border-radius: 15px; border-radius: 15px;
} }
} }
/deep/.next-countdown{
position: absolute;
color: #fff;
right: 10px;
bottom: 44px;
font-size: 12px;
height: 24px;
line-height: 24px;
padding: 0 12px;
border-radius: 12px;
background-color: #373839;
}
} }
</style> </style>
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册