提交 413dd4a1 authored 作者: GOD_ZYX's avatar GOD_ZYX

合并 直播部分 进入 sofia

上级 2c8ba80e
...@@ -43,8 +43,11 @@ ...@@ -43,8 +43,11 @@
<!-- <p class="no-data">暂无数据</p> --> <!-- <p class="no-data">暂无数据</p> -->
</template> </template>
<!-- <p class="text-danger">{this.state.error}</p> --> <!-- <p class="text-danger">{this.state.error}</p> -->
<template v-if="this.deadLine">
<p style="color: red">请于截止日期 {{this.deadLine}} 前提交</p>
</template>
<div class="area-btns"> <div class="area-btns">
<el-button type="primary" @click="submitWork" :disabled="homeData.checker_time">{{homeData.checker_time ? '已批改' : '提交'}}</el-button> <el-button type="primary" @click="submitWork" :disabled="!!homeData.checker_time || deadLineFlag">{{homeData.checker_time ? '已批改' : '提交'}}</el-button>
<span class="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span> <span class="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span>
<template v-if="homeData.checker_time"> <template v-if="homeData.checker_time">
<div class="play-paper-check"> <div class="play-paper-check">
...@@ -96,7 +99,9 @@ export default { ...@@ -96,7 +99,9 @@ export default {
homeData: {}, homeData: {},
/* 设置是否可以初始化 ckeditor */ /* 设置是否可以初始化 ckeditor */
setTime: null, setTime: null,
isInit: false isInit: false,
deadLine: '',
deadLineFlag: false
} }
}, },
/* 本组件 仅支持 单个 ckeditor 存在 */ /* 本组件 仅支持 单个 ckeditor 存在 */
...@@ -143,6 +148,15 @@ export default { ...@@ -143,6 +148,15 @@ export default {
}, 50) }, 50)
loading.close() loading.close()
}) })
setTimeout(() => {
cAction.chapterAction.getHomeworkStopTime(this.sid, this.cid, this.chapterId).then(data => {
this.deadLine = data.dead_line || ''
let deadLine = data.dead_line ? new Date(data.dead_line).getTime() : ''
// deadLine = new Date().getTime() - 100
this.deadLineFlag = ((new Date().getTime() > deadLine) && !!deadLine)
// console.log(this.deadLine)
}).catch(e => { this.$message.error(e.message) }).finally(() => {})
}, 500)
}, },
submitWork () { submitWork () {
if (!this.ckeditor.getData()) { if (!this.ckeditor.getData()) {
......
...@@ -4,6 +4,16 @@ ...@@ -4,6 +4,16 @@
<div class="play-top cl" :style="(state.sideBar ? {} : { marginRight: 0 })"> <div class="play-top cl" :style="(state.sideBar ? {} : { marginRight: 0 })">
<router-link class="router-link-class" :to="{ path: `/app/my-learn/course-detail/${sid}/${cid}` }"><i class="play-back el-icon-arrow-left"></i></router-link> <router-link class="router-link-class" :to="{ path: `/app/my-learn/course-detail/${sid}/${cid}` }"><i class="play-back el-icon-arrow-left"></i></router-link>
<p>{{chapterList.title}}</p> <p>{{chapterList.title}}</p>
<router-link class="router-link-class" id="sys-help" :to="{ path: `/mobile/help/student` }" target="_blank">
<el-tooltip effect="light" content="帮助" placement="bottom-start">
<i class="el-icon-self-icon-test"></i>
</el-tooltip>
</router-link>
<router-link class="router-link-class" id="sys-callback" :to="{ path: `/app/account/feedbackCreate` }" target="_blank">
<el-tooltip effect="light" content="意见反馈" placement="bottom-start">
<i class="el-icon-self-fankuiyijian"></i>
</el-tooltip>
</router-link>
</div> </div>
<div class="play-content"> <div class="play-content">
<router-view <router-view
...@@ -21,6 +31,7 @@ ...@@ -21,6 +31,7 @@
@changeVideoArr="changeVideoArr" @changeVideoArr="changeVideoArr"
@handlePlayTime="handlePlayTime" @handlePlayTime="handlePlayTime"
@updateProgress="updateProgress" @updateProgress="updateProgress"
@changeSideBar="changeSideBar"
></router-view> ></router-view>
</div> </div>
</div> </div>
...@@ -53,7 +64,7 @@ ...@@ -53,7 +64,7 @@
</div> </div>
</div> </div>
<template v-if="!state.sideBar"> <template v-if="!state.sideBar">
<div class="switch"> <div class="switch" id="switch-btn">
<a :href="('#' + SIDEBAR_CHAPTER)" class="switch-chapter" @click="changeSideBar(SIDEBAR_CHAPTER)"> <a :href="('#' + SIDEBAR_CHAPTER)" class="switch-chapter" @click="changeSideBar(SIDEBAR_CHAPTER)">
<i class="el-icon-self-wenjian"></i> <i class="el-icon-self-wenjian"></i>
<div>章节</div> <div>章节</div>
...@@ -385,5 +396,38 @@ export default { ...@@ -385,5 +396,38 @@ export default {
} }
} }
} }
#sys-help {
display: none;
position: absolute;
top: 6px;
right: 50px;
/* width: 40px; */
height: 40px;
overflow: hidden;
color: #fff;
font-size: 16px;
line-height: 40px;
text-align: center;
text-decoration: none;
i {
font-size: 20px;
}
}
#sys-callback {
display: none;
position: absolute;
top: 6px;
right: 15px;
/* width: 40px; */
height: 40px;
overflow: hidden;
color: #fff;
font-size: 16px;
line-height: 40px;
text-align: center;
text-decoration: none;
i {
font-size: 20px;
}
}
</style> </style>
<template>
<iframe id="myIframe" :src="live.url" frameborder="0" width="100%" height="100%" allow="autoplay;geolocation;microphone;camera;midi;encrypted-media;"></iframe>
</div>
</template>
<script>
import cAction from '@actions'
export default {
props: {
sid: { type: String, require: false },
cid: { type: String, require: false },
id: { type: String, require: false }
},
data () {
return {
live: {},
ccLive: null
}
},
mounted () {
this.loadAjax()
},
destroyed () {
if (window.document.getElementById('switch-btn')) {
window.document.getElementById('switch-btn').style.display = 'block'
window.document.getElementById('sys-help').style.display = 'none'
window.document.getElementById('sys-callback').style.display = 'none'
}
if (this.ccLive) {
this.ccLive.logout({
success: function (res) {
},
error: function (res) {
}
})
}
},
methods: {
loadAjax () {
/* 只能清除本域名下的cookie,不能清除其他域名下的cookie */
// cAction.loginAction.clearCookie({
// cookies: [{
// name: 'sessionid',
// obj: { path: '/', domain: '.csslcloud.net' }
// }, {
// name: 'TGC',
// obj: { path: '/', domain: '.ezijing.com' }
// }]
// }).then().finally(() => {})
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.chapterAction.getChapterList(this.cid, this.sid, this.id).then(json => {
this.live = (json.curJson && json.curJson.live) || {}
if (this.live.id) {
if (this.live.record_id && this.live.live_status === 103) {
this.live.url = 'https://view.csslcloud.net/api/view/callback?recordid=' + this.live.record_id + '&roomid=' + this.live.room_id + '&userid=' + this.live.user_id + '&autoLogin=true&viewername=' + this.live.viewer_name + '&viewertoken=' + this.live.viewer_token // + '&groupid=xxx'
} else {
this.$emit('changeSideBar', '')
setTimeout(() => {
if (window.document.getElementById('switch-btn')) {
window.document.getElementById('switch-btn').style.display = 'none'
window.document.getElementById('sys-help').style.display = 'block'
window.document.getElementById('sys-callback').style.display = 'block'
}
}, 1000)
this.live.viewer_name = window.G.UserInfo.student_info.personal_name || window.G.UserInfo.nickname
this.live.url = 'https://view.csslcloud.net/api/view/index?roomid=' + this.live.room_id + '&userid=' + this.live.user_id + '&autoLogin=true&viewername=' + this.live.viewer_name + '&viewertoken=' + this.live.viewer_token // + '&groupid=xxx'
}
this.CCLiveInit(this.live)
}
loading.close()
}).catch(e => { this.$message.error(e.message) }).finally(() => { })
},
CCLiveInit (live) {
window.DWLive.init({
userid: live.user_id, // 必须参数
roomid: live.room_id, // 必须参数
// groupid: "groupid", // 可选
viewername: live.viewer_name, // 可选
viewertoken: live.viewer_token // 如果直播间设置为密码验证,必选
// viewercustomua: 'android', // 可选
// language: 'en', // 可选
// viewercustominfo: '{"exportInfos": [ {"key": "城市", "value": "北京"}, {"key": "姓名", "value": "哈哈"}]}', // 可选
// fastMode:true // 可选参数,默认为true
})
this.ccLive = window.DWLive
}
},
watch: {
id: {
handler () {
this.loadAjax()
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
...@@ -7,8 +7,12 @@ ...@@ -7,8 +7,12 @@
<ul class="knot-list"> <ul class="knot-list">
<template v-for="(_item, _index) in item.chapters"> <template v-for="(_item, _index) in item.chapters">
<li v-bind:key="_index" :class="['knob-item', (_item.id === list.currentChapterId ? 'on' : '')]"> <li v-bind:key="_index" :class="['knob-item', (_item.id === list.currentChapterId ? 'on' : '')]">
<a :data-vid="_item.id" :data-type="_item.video_provider" :data-hasVA='_item.time' @click='jumpToOtherVA' :data-index='index' :data-count='_index' class="knot-name">{{_item.name}}</a> <a :data-vid="_item.id" :data-type="_item.video_provider" :data-hasVA='_item.time' @click='jumpToOtherVA' :data-index='index' :data-count='_index' class="knot-name">
{{_item.name + (_item.type === 5 ? ("(" + _item.live.statusStr + ")") : "") }}
</a>
<template v-if="_item.type !== 5">
<i :class="['el-icon', (_item.time ? 'el-icon-self-iconset0481' : (_item.type === 3 ? 'el-icon-edit-outline' : 'el-icon-self-cc-book'))]"></i> <i :class="['el-icon', (_item.time ? 'el-icon-self-iconset0481' : (_item.type === 3 ? 'el-icon-edit-outline' : 'el-icon-self-cc-book'))]"></i>
</template>
</li> </li>
</template> </template>
</ul> </ul>
...@@ -64,6 +68,18 @@ export default { ...@@ -64,6 +68,18 @@ export default {
this.$router.push({ path: `/survey/${sid}/${cid}` }) this.$router.push({ path: `/survey/${sid}/${cid}` })
} else if (_course.chapters[i2].type === 'exam') { } else if (_course.chapters[i2].type === 'exam') {
this.$router.push({ path: `/player/${sid}/${cid}/exam/${_id}` }) this.$router.push({ path: `/player/${sid}/${cid}/exam/${_id}` })
} else if (_course.chapters[i2].type === 5) {
let status = _course.chapters[i2].live.live_status
if (status !== 0 && status !== 1 && status !== 103) {
this.$message.error(_course.chapters[i2].live.statusStr)
return
}
let enableRecord = _course.chapters[i2].live.enable_record
if (status === 103 && enableRecord !== undefined && enableRecord !== null && !enableRecord) {
this.$message.info('该直播没有回放')
return
}
this.$router.push({ path: `/player/${sid}/${cid}/live/${_id}` })
} }
return return
} }
......
...@@ -66,6 +66,10 @@ export default class ChapterAPI extends BaseAPI { ...@@ -66,6 +66,10 @@ export default class ChapterAPI extends BaseAPI {
* 提交课程 作业或问题 * 提交课程 作业或问题
*/ */
updateHomework = (obj = {}) => this.post('/v2/education/homeworks', obj, { headers: { 'Content-Type': 'multipart/form-data' } }) updateHomework = (obj = {}) => this.post('/v2/education/homeworks', obj, { headers: { 'Content-Type': 'multipart/form-data' } })
/**
* 课程作业截止时间
*/
getHomeworkStopTime = (sid, cid, chapterId) => this.get(`/v2/education/homeworks/${sid}/${cid}/${chapterId}/deadline`, {})
/** /**
* 获取对应 大作业 回答 * 获取对应 大作业 回答
* @param {[string]} sid * @param {[string]} sid
...@@ -85,4 +89,12 @@ export default class ChapterAPI extends BaseAPI { ...@@ -85,4 +89,12 @@ export default class ChapterAPI extends BaseAPI {
* @param {[string]} obj.raw (base64) * @param {[string]} obj.raw (base64)
*/ */
updateSurveyAnswer = (obj) => this.post(`/v2/education/survey/answer`, obj) updateSurveyAnswer = (obj) => this.post(`/v2/education/survey/answer`, obj)
/**
* 手机端 获取实时最新直播接口
*/
getNewLiveMsg = (obj = {}) => this.get(`/v2/education/lives/latest`, obj)
/**
* 手机端 获取列表接口
*/
getLiveList = (obj = {}) => this.get(`/v2/education/lives/courses`, obj)
} }
...@@ -65,4 +65,6 @@ export default class LoginAPI extends BaseAPI { ...@@ -65,4 +65,6 @@ export default class LoginAPI extends BaseAPI {
* 个人信息 - 上传头像 * 个人信息 - 上传头像
*/ */
updatePic = (obj = {}) => this.post('/v3/storage/upload/avatar', obj, { headers: { 'Content-Type': 'multipart/form-data' } }) updatePic = (obj = {}) => this.post('/v3/storage/upload/avatar', obj, { headers: { 'Content-Type': 'multipart/form-data' } })
/* 清cookie - 只能清除请求的同域名下cookie */
clearCookie = (obj = {}) => this.post('/clear/cookie', obj, { headers: { 'Content-Type': 'application/json' } })
} }
...@@ -82,9 +82,40 @@ export default class ChapterAction { ...@@ -82,9 +82,40 @@ export default class ChapterAction {
homework: _homework, homework: _homework,
chapterRead: _chapterRead, chapterRead: _chapterRead,
chapterWork: _chapterWork, chapterWork: _chapterWork,
chapterVideo: _chapterVideo chapterVideo: _chapterVideo,
live: __.live || ''
} }
} }
if (__.live && __.live.id) {
let str = ''
switch (__.live.live_status) {
case 0: str = '直播未开始'; break
case 1: str = '正在直播'; break
case 2: str = '直播结束'; break
case 101: str = '直播结束,视频剪辑中'; break // 录制开始
case 102: str = '直播结束,视频剪辑中'; break // 录制结束
case 103: str = '观看回放'; break
default: str = '直播未开始'
}
// 5分钟内显示“即将开始”,5~1小时内“N分钟后开始”,1~24小时内“N小时后开始”,1天以上“N天后开始”天就显示年月日
if (__.live.live_status === 0 && __.live.start_time) {
let time = (new Date(__.live.start_time).getTime() - new Date().getTime()) / 1000
if (time <= 5 * 60) {
str = '即将开始'
} else if (time <= 1 * 60 * 60) {
str = parseInt(time / 60) + '分钟后开始'
} else if (time <= 24 * 60 * 60) {
str = parseInt(time / (60 * 60)) + '小时' + parseInt(time / 60 % 60) + '分钟后开始'
} else {
str = parseInt(time / (24 * 60 * 60)) + '天后开始'
}
}
if (__.live.live_status === 103 && __.live.enable_record !== undefined && __.live.enable_record !== null && !__.live.enable_record) {
str = ''
}
__.live.statusStr = str
}
return { return {
id: __.resource_id, id: __.resource_id,
video_provider: (__.video && __.video.video_provider) || '', video_provider: (__.video && __.video.video_provider) || '',
...@@ -95,7 +126,8 @@ export default class ChapterAction { ...@@ -95,7 +126,8 @@ export default class ChapterAction {
homework: _homework, homework: _homework,
chapterRead: _chapterRead, chapterRead: _chapterRead,
chapterWork: _chapterWork, chapterWork: _chapterWork,
chapterVideo: _chapterVideo chapterVideo: _chapterVideo,
live: __.live || ''
} }
}) })
} }
...@@ -231,8 +263,14 @@ export default class ChapterAction { ...@@ -231,8 +263,14 @@ export default class ChapterAction {
updateHomework (obj) { return chapterApi.updateHomework(obj).then(res => res) } updateHomework (obj) { return chapterApi.updateHomework(obj).then(res => res) }
/* 获取大作业 回答 */ /* 获取大作业 回答 */
getCourseHomework (sid, cid) { return chapterApi.getCourseHomework(sid, cid).then(res => res) } getCourseHomework (sid, cid) { return chapterApi.getCourseHomework(sid, cid).then(res => res) }
/* 获取作业截止时间 */
getHomeworkStopTime (sid, cid, chapterId) { return chapterApi.getHomeworkStopTime(sid, cid, chapterId).then(res => res) }
/* 提交大作业 */ /* 提交大作业 */
updateCourseHomework (sid, cid, obj) { return chapterApi.updateCourseHomework(sid, cid, obj).then(res => res) } updateCourseHomework (sid, cid, obj) { return chapterApi.updateCourseHomework(sid, cid, obj).then(res => res) }
/* 提交课程考核 */ /* 提交课程考核 */
updateSurveyAnswer (obj) { return chapterApi.updateSurveyAnswer(obj).then(res => res) } updateSurveyAnswer (obj) { return chapterApi.updateSurveyAnswer(obj).then(res => res) }
/* 获取当前最新直播提醒 */
getNewLiveMsg () { return chapterApi.getNewLiveMsg().then(res => res) }
/* 获取手机直播列表 */
getLiveList () { return chapterApi.getLiveList().then(res => res) }
} }
...@@ -108,6 +108,36 @@ export default class CourseAction { ...@@ -108,6 +108,36 @@ export default class CourseAction {
_homework.work_id = __.resource_id _homework.work_id = __.resource_id
_homework.semester_id = data.semester_id _homework.semester_id = data.semester_id
} }
if (__.live && __.live.id) {
let str = ''
switch (__.live.live_status) {
case 0: str = '直播未开始'; break
case 1: str = '正在直播'; break
case 2: str = '直播结束'; break
case 101: str = '直播结束,视频剪辑中'; break // 录制开始
case 102: str = '直播结束,视频剪辑中'; break // 录制结束
case 103: str = '观看回放'; break
default: str = '直播未开始'
}
// 5分钟内显示“即将开始”,5~1小时内“N分钟后开始”,1~24小时内“N小时后开始”,1天以上“N天后开始”天就显示年月日
if (__.live.live_status === 0 && __.live.start_time) {
let time = (new Date(__.live.start_time).getTime() - new Date().getTime()) / 1000
if (time <= 5 * 60) {
str = '即将开始'
} else if (time <= 1 * 60 * 60) {
str = parseInt(time / 60) + '分钟后开始'
} else if (time <= 24 * 60 * 60) {
str = parseInt(time / (60 * 60)) + '小时' + parseInt(time / 60 % 60) + '分钟后开始'
} else {
str = parseInt(time / (24 * 60 * 60)) + '天后开始'
}
}
if (__.live.live_status === 103 && __.live.enable_record !== undefined && __.live.enable_record !== null && !__.live.enable_record) {
str = ''
}
__.live.statusStr = str
}
return { return {
cid: cur.course_id, cid: cur.course_id,
sid: cur.semester_id, sid: cur.semester_id,
...@@ -119,7 +149,8 @@ export default class CourseAction { ...@@ -119,7 +149,8 @@ export default class CourseAction {
name: __.name, name: __.name,
type: __.type, type: __.type,
work_type: (__.homework && __.homework.work_type) || '', work_type: (__.homework && __.homework.work_type) || '',
homework: _homework homework: _homework,
live: __.live || ''
} }
}) })
} }
......
...@@ -99,4 +99,8 @@ export default class LoginAction { ...@@ -99,4 +99,8 @@ export default class LoginAction {
* 调用个人信息 - 上传头像 * 调用个人信息 - 上传头像
*/ */
updatePic (obj) { return loginApi.updatePic(obj).then(res => res) } updatePic (obj) { return loginApi.updatePic(obj).then(res => res) }
/**
* 清除cookie
*/
clearCookie (obj) { return loginApi.clearCookie(obj).then(res => res) }
} }
...@@ -85,8 +85,8 @@ export default { ...@@ -85,8 +85,8 @@ export default {
] ]
}, },
{ {
name: '系统反馈', name: '意见反馈',
iconClass: 'el-icon-bell', iconClass: 'el-icon-self-fankuiyijian',
index: '3' index: '3'
} }
] ]
......
...@@ -41,6 +41,10 @@ ...@@ -41,6 +41,10 @@
<!-- 直接引入aliyun播放插件 JS --> <!-- 直接引入aliyun播放插件 JS -->
<script type="text/javascript" charset="utf-8" src="https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js"></script> <script type="text/javascript" charset="utf-8" src="https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js"></script>
<script type="text/javascript" charset="utf-8" src="https://player.alicdn.com/aliplayer/presentation/js/aliplayercomponents.min.js"></script> <script type="text/javascript" charset="utf-8" src="https://player.alicdn.com/aliplayer/presentation/js/aliplayercomponents.min.js"></script>
<!-- 解决iframe嵌套,CC视频在safri中打开免登陆兼容问题 -->
<script src="//view.csslcloud.net/js/_fix_.js"></script>
<script src="//view.csslcloud.net/js/jquery-1.9.0.min.js" type="text/javascript"></script>
<script src="//view.csslcloud.net/js/sdk/3.1.0/liveSDK.js" type="text/javascript"></script>
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/console-polyfill.js"></script> <script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/console-polyfill.js"></script>
<script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/html5shiv.min.js"></script> <script src="https://zws-imgs-pub.ezijing.com/static/build/learn-mba/static/compatible/html5shiv.min.js"></script>
......
...@@ -2,6 +2,7 @@ import Vue from 'vue' // 引入vue框架 ...@@ -2,6 +2,7 @@ import Vue from 'vue' // 引入vue框架
import Element from 'element-ui' // 引入 element-ui 框架 import Element from 'element-ui' // 引入 element-ui 框架
import './components/style/_com.scss' // 定义 element-ui主题色 + 公共样式 import './components/style/_com.scss' // 定义 element-ui主题色 + 公共样式
import VueRouter from 'vue-router' // 使用 vue-router import VueRouter from 'vue-router' // 使用 vue-router
import MetaInfo from 'vue-meta-info'
import createRouter from './router' // router定义 import createRouter from './router' // router定义
import Main from './main.vue' // 初始化 vue页面 import Main from './main.vue' // 初始化 vue页面
import UploadForm from '../components/upload-form' import UploadForm from '../components/upload-form'
...@@ -19,6 +20,7 @@ require('promise.prototype.finally').shim() ...@@ -19,6 +20,7 @@ require('promise.prototype.finally').shim()
Vue.use(Element) Vue.use(Element)
Vue.use(VueRouter) Vue.use(VueRouter)
Vue.use(MetaInfo)
Vue.use(UploadForm) Vue.use(UploadForm)
Vue.component(UploadForm.name, UploadForm) Vue.component(UploadForm.name, UploadForm)
const router = createRouter() const router = createRouter()
...@@ -31,7 +33,9 @@ Vue.prototype.$md5 = md5 ...@@ -31,7 +33,9 @@ Vue.prototype.$md5 = md5
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
/* 设置 全局变量 */ /* 设置 全局变量 */
BeforeRouter.globalVariable.init(Vue, { to, from, next }) BeforeRouter.globalVariable.init(Vue, { to, from, next })
if (to.name !== 'normalLogin' && to.name !== 'codeLogin' && to.name !== 'forgetPwd') { // 所有登录页 不进行登录校验 if (to.name === 'studentHelp' || to.name === 'teacherHelp') {
next()
} else if (to.name !== 'normalLogin' && to.name !== 'codeLogin' && to.name !== 'forgetPwd') { // 所有登录页 不进行登录校验
BeforeRouter.loginInfo.isLogin(Vue).then(str => { BeforeRouter.loginInfo.isLogin(Vue).then(str => {
if (/^login/gi.test(str)) { if (/^login/gi.test(str)) {
next() next()
......
<template>
<div>
<router-view></router-view>
</div>
</template>
<template>
<div class="pages">
<div class="head">
<img class="logo5" alt="logo" src="../../assets/img/logo-header.png">
<div class="userinfo">
<div class="login-out" @click="goOutLogin()">退出</div>
<div class="name">{{ name }}</div>
</div>
</div>
<div class="hint" v-show="latest && latest.live" @click="opencc(latest)" >
<div class="left">
<div class="left-1">直播提醒</div>
<div class="left-2">{{latest.course_name}}》将于 {{latest.live && latest.live.start_time.slice(5)}} 开始</div>
</div>
<div class="right">进入直播 ></div>
</div>
<div class="tips">提示语:已参加的课程请到电脑端学习系统观看回放</div>
<div class="list-box">
<div class="curriculum" v-for="(item, index) in obj" v-bind:key="index" >
<h4 class="curriculum-name">{{item.course_name}}</h4>
<div class="curriculum-box" @click="opencc(item)" >
<img class="curriculum-picture" :src="item.curriculum.curriculum_picture" />
<div class="curriculum-introduce">
<div class="title">{{item.curriculum.curriculum_name}}</div>
<div class="time">{{item.live ? item.live.time : ''}}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import cAction from '@actions'
export default {
data () {
return {
name: (window.G.UserInfo && window.G.UserInfo.student_info && window.G.UserInfo.student_info.personal_name) || '匿名',
latest: '',
obj: [],
loading: null
}
},
metaInfo () {
return {
title: '清华大学五道口金融学院',
meta: [
// { vmid: 'description', name: 'description', content: this.description }
]
}
},
mounted () {
const _this = this
this.loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
this.dealRender()
_this.getNewLiveMsg()
_this.getLiveLis()
setInterval(function () {
_this.getNewLiveMsg()
_this.getLiveLis()
}, 3000)
},
methods: {
/* 退出登录 - 跳转方法 */
goOutLogin () {
cAction.loginAction.outLogin().then(str => {
if (/^login/gi.test(str)) {
window.G.UserInfo = {}
// this.$router.push({ path: '/login/index' })
// this.$router.push({ path: '/' })
window.location.href = 'https://pbcsf.ezijing.com/login/index'
} else {
/* 出错 */
}
}).catch(e => {
this.$message.error(e.message)
})
/* 清空一下记录,然后调整到登录页 */
// this.$router.push({ path: '/login/index' })
},
getNewLiveMsg: function () {
// 获取最新直播提醒
const _this = this
// const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.chapterAction.getNewLiveMsg().then(json => {
if (json.status === 200) {
_this.latest = json.data
window.console.log(_this.latest)
}
if (_this.loading) {
_this.loading.close()
_this.loading = null
}
}).catch(e => { this.$message.error(e.message) }).finally(() => { })
},
getLiveLis: function () {
// 获取最新直播列表
const _this = this
cAction.chapterAction.getLiveList().then(json => {
if (json.status === 200) {
json.data.map(function (item, index, arr) {
if (item.live && (item.live.length || item.live.user_id)) {
let _time = item.live.start_time
let _status = item.live.live_status
let enableRecord = item.live.enable_record // 0: 不启用回放 1: 开启回放
let str = ''
switch (_status) {
case 0: str = '直播未开始'; break
case 1: str = '正在直播'; break
case 2: str = '直播结束'; break
case 101: str = '直播结束,视频剪辑中'; break // 录制开始
case 102: str = '直播结束,视频剪辑中'; break // 录制结束
case 103: str = '观看回放'; break
default: str = '直播未开始'
}
if (_status === 103 && !enableRecord) str = ''
if (_status === 0 && _time) {
_time = _time.replace(/-/g, '/')
let time = (new Date(_time).getTime() - new Date().getTime()) / 1000
if (time <= 5 * 60) {
str = '即将开始'
} else if (time <= 1 * 60 * 60) {
str = parseInt(time / 60) + '分钟后开始'
} else if (time <= 24 * 60 * 60) {
str = parseInt(time / (60 * 60)) + '小时' + parseInt(time / 60 % 60) + '分钟后开始'
} else {
str = parseInt(time / (24 * 60 * 60)) + '天后开始'
}
}
item.live.time = str
}
return item
})
_this.obj = json.data
}
if (_this.loading) {
_this.loading.close()
_this.loading = null
}
}).catch(e => { this.$message.error(e.message) }).finally(() => { })
},
dealRender: () => {
(function (win, doc) {
let wWidth = (win.screen.width > 0) ? (win.innerWidth >= win.screen.width || win.innerWidth === 0) ? win.screen.width : win.innerWidth : win.innerWidth, wFsize // eslint-disable-line
wFsize = (wWidth > 640 ? 640 : wWidth) / 375 * 100
// wFsize = wFsize > 32 ? wFsize : 32;
doc.documentElement.style.fontSize = wFsize + 'px'
})(window, document)
},
opencc: function (obj) {
let _live = obj.live
if (!_live || !_live.user_id) {
this.$message.error('网络错误,刷新重试')
return
}
let userid = _live.user_id
let roomid = _live.room_id
let viewertoken = _live.viewer_token
let recordid = _live.record_id
let liveStatus = _live.live_status
let enableRecord = _live.enable_record // 0: 不启用回放 1: 开启回放
let viewername = this.name
let _url = 'https://view.csslcloud.net/api/view'
if (recordid && liveStatus === 103) {
if (!enableRecord) {
this.$message.warning('该直播没有回放')
return
}
// 可以回放
// https://view.csslcloud.net/api/view/callback?recordid=xxx&roomid=xxx&userid=xxx&autoLogin=true&viewername=xxx&viewertoken=xxx&groupid=xxx
_url = _url + '/callback?autoLogin=true&roomid=' + roomid + '&userid=' + userid + '&recordid=' + recordid + '&viewername=' + viewername + '&viewertoken=' + viewertoken
} else {
// 可以直播
// https://view.csslcloud.net/api/view/index?roomid=xxx&userid=xxx&autoLogin=true&viewername=xxx&viewertoken=xxx&groupid=xxx
_url = _url + '/index?autoLogin=true&roomid=' + roomid + '&userid=' + userid + '&viewername=' + viewername + '&viewertoken=' + viewertoken
}
window.console.log(_url)
window.open(_url, '_blank')
}
}
}
</script>
<style>
html{
font-size: 100px;
}
body{
padding: 0;
margin: 0;
}
.float-left{
float: left;
}
.float-right{
float: right;
}
</style>
<style scoped >
.pages{
font-size: .14rem;
padding-top: .2rem;
}
.head{
height: 0.48rem;
padding: 0 0.2rem;
}
.head .logo5{
width: 1.18rem;
height: .3rem;
float: left;
}
.name{
padding: 0 0.1rem;
width: 1.1rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.login-out{
color: #999;
}
.userinfo{
height: 0.68rem;
}
.userinfo > div {
float: right;
}
.hint{
min-height: 0.7rem;
display: flex;
background: rgba(176,28,61,.1) ;
padding: 0 0.2rem .1rem;
justify-content: space-between;
font-size: .14rem;
}
.hint .left{
flex-grow: 1;
display: flex;
flex-direction: column;
padding-right: .08rem;
}
.hint .left .left-1{
height: .4rem;
line-height: .4rem;
}
.hint .left .left-2{
margin-left: - 0.08rem;
}
.hint .right{
width: .78rem;
flex-shrink:0;
color: #b01c3d;
align-self:center;
}
.tips{
height: .4rem;
line-height: .4rem;
padding: 0 .2rem;
color: #999;
font-size: .14rem;
overflow: hidden;
}
.list-box{
padding: 0 .2rem;
}
.curriculum{
width: 100%;
padding-top: .05rem;
height: 1.2rem;
border-bottom: 1px solid #ccc ;
}
.curriculum-name{
padding: 0;
margin: 0;
height: .4rem;
line-height: .4rem;
color: #333;
}
.curriculum-box{
display: flex;
width: 100%;
height: .6rem;
cursor: pointer;
}
.curriculum-picture{
width: .86rem;
height: .6rem;
}
.curriculum-introduce{
padding-left: 10px;
flex-grow:1;
display: flex;
flex-direction:column;
justify-content:space-between;
}
.curriculum-introduce .time{
color: #b01c3d;
text-align: right;
}
</style>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
:http-request="uploadFile1" :http-request="uploadFile1"
:file-list="filesArr1"> :file-list="filesArr1">
<el-button size="mini" type="primary">点击上传</el-button> <el-button size="mini" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">(请下载重修申请表,填写完整再上传)<a href="http://zws-imgs-pub.oss-cn-beijing.aliyuncs.com/static/public/713efef7718281271b2ad3eea135e327.docx">模板下载</a></div> <div slot="tip" class="el-upload__tip">(请下载重修申请表,填写完整再上传)<a href="https://zws-imgs-pub.oss-cn-beijing.aliyuncs.com/static/public/713efef7718281271b2ad3eea135e327.docx">模板下载</a></div>
<template v-if="successFileUrl1"> <template v-if="successFileUrl1">
{{successFileUrl1.replace(/.*\/([^\/]*\.[^.]+)$/gi, '$1')}} {{successFileUrl1.replace(/.*\/([^\/]*\.[^.]+)$/gi, '$1')}}
</template> </template>
......
<template> <template>
<div> <div>
<template v-if="newLiveMsg.live">
<div class="live-msg">
<div class="txt">直播提醒:</div>
<div class="txt">您的直播课程 《{{newLiveMsg.course_name}}》 将于 {{newLiveMsg.live.start_time}} 开始</div>
<el-button class="in-btn" type="primary" size="small" round @click="goLive">进入直播</el-button>
</div>
</template>
<div class="con-title">我的课程</div> <div class="con-title">我的课程</div>
<div class="con-box"> <div class="con-box">
<template v-for="(item, index) in find"> <template v-for="(item, index) in find">
...@@ -26,14 +33,14 @@ ...@@ -26,14 +33,14 @@
<li v-bind:key="index" class="item"> <li v-bind:key="index" class="item">
<div class="left-pic"> <div class="left-pic">
<template v-if="item.src"> <template v-if="item.src">
<img :src="item.src" alt=""> <img :src="item.src" alt="" @click="goCourseContent" :data-cid='item.id' :data-sid='item.sid'>
</template> </template>
<template v-else> <template v-else>
<div class="no-img"><i class="el-icon-self-13"></i></div> <div class="no-img"><i class="el-icon-self-13"></i></div>
</template> </template>
</div> </div>
<div class="right-bd"> <div class="right-bd">
<div class="title">{{item.title}}</div> <div class="title" @click="goCourseContent" :data-cid='item.id' :data-sid='item.sid'>{{item.title}}</div>
<div class="tags"> <div class="tags">
<template v-for="(item1, index) in item.arrTab"> <template v-for="(item1, index) in item.arrTab">
<span v-bind:key="index">{{item1}}</span> <span v-bind:key="index">{{item1}}</span>
...@@ -105,16 +112,36 @@ export default { ...@@ -105,16 +112,36 @@ export default {
// progress: 0 // progress: 0
// } // }
], ],
param: {} param: {},
timeInterval: null,
newLiveMsg: {}
} }
}, },
mounted () { mounted () {
if (this.timeInterval) {
clearInterval(this.timeInterval)
this.timeInterval = null
}
this.timeInterval = setInterval(() => {
cAction.chapterAction.getNewLiveMsg().then(json => {
if (json.status === 200) {
this.newLiveMsg = json.data
}
}).catch(e => { this.$message.error(e.message) }).finally(() => { })
}, 3000)
const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' }) const loading = this.$loading({ lock: true, text: '', spinner: '', background: 'rgba(255, 255, 255, 0.9)' })
cAction.courseAction.getlearnFindList().then(data => { cAction.courseAction.getlearnFindList().then(data => {
this.find[0].arrItem = data this.find[0].arrItem = data
this.getAjaxList(true, '请去选课广场选课') this.getAjaxList(true, '请去选课广场选课')
}).catch(e => { this.$message.error(e.message) }).finally(() => { loading.close() }) }).catch(e => { this.$message.error(e.message) }).finally(() => { loading.close() })
}, },
destroyed () {
if (this.timeInterval) {
clearInterval(this.timeInterval)
this.timeInterval = null
}
},
methods: { methods: {
goCourseAll () { goCourseAll () {
this.$router.push({ path: '/app/my-learn/course-all' }) this.$router.push({ path: '/app/my-learn/course-all' })
...@@ -178,12 +205,29 @@ export default { ...@@ -178,12 +205,29 @@ export default {
} }
this.getAjaxList(true, '请去选课广场选课') this.getAjaxList(true, '请去选课广场选课')
},
/* 直接进直播 */
goLive () {
this.$router.push({ path: `/player/${this.newLiveMsg.semester_id}/${this.newLiveMsg.course_id}/live/${this.newLiveMsg.live.id}` })
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.live-msg {
position: relative;
padding: 15px;
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
.txt {
padding-right: 100px;
}
.in-btn {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
}
}
/* 列表 筛选 */ /* 列表 筛选 */
ul.tabs-list { ul.tabs-list {
float: left; float: left;
...@@ -280,6 +324,7 @@ ul.course-list { ...@@ -280,6 +324,7 @@ ul.course-list {
width: 100%; width: 100%;
// height: 100%; // height: 100%;
// transform: translate(-50%, -50%); // transform: translate(-50%, -50%);
cursor: pointer;
} }
} }
.right-bd { .right-bd {
...@@ -293,6 +338,7 @@ ul.course-list { ...@@ -293,6 +338,7 @@ ul.course-list {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
cursor: pointer;
} }
.tags { .tags {
margin: 0.05rem 0; margin: 0.05rem 0;
......
...@@ -48,9 +48,14 @@ ...@@ -48,9 +48,14 @@
</div> </div>
<template v-for="(item1, index1) in _item.chapters"> <template v-for="(item1, index1) in _item.chapters">
<div v-bind:key="index1" :class='["body", (item1.id === tabs[1].chapterList.currentChapterId && "on")]'> <div v-bind:key="index1" :class='["body", (item1.id === tabs[1].chapterList.currentChapterId && "on")]'>
<div class='name' :data-vid='item1.vid' :data-cid='item1.cid' :data-sid='item1.sid' :data-hasVA='item1.time' :data-type="item1.video_provider" :data-name='item1.name' @click='jumpToOtherVA' :data-index='index' :data-count='index1'> <div class='name' :data-vid='item1.vid' :data-cid='item1.cid' :data-sid='item1.sid' :data-hasVA='item1.time' :data-type="item1.video_provider" :data-name='item1.name' :data-index='index' :data-count='index1' @click='jumpToOtherVA'>
{{item1.name}} {{item1.name}}
<template v-if='item1.type === 5'>
<div class='time'>{{ item1.live.statusStr }}</div>
</template>
<template v-else>
<div class='time'>{{item1.time}}</div> <div class='time'>{{item1.time}}</div>
</template>
</div> </div>
</div> </div>
</template> </template>
...@@ -293,7 +298,7 @@ export default { ...@@ -293,7 +298,7 @@ export default {
}, { }, {
title: '课程考核', title: '课程考核',
isShow: false, isShow: false,
richText: "<div class='h1'>一、最终成绩计算</div> <div class='p'>课程表现得分*30%+每章试题得分*30%+结业大作业得分*40%=该门课程总得分,满分100分,低于80分为不及格,需重修此门课程。84分以上方可申请学位。</div> <img class='b1' src='http://zws-imgs-pub.oss-cn-beijing.aliyuncs.com/static/build/www/course-check.png' mode='aspectFill' /> <div class='h1'>二、具体细则</div> <div class='h2'>课程表现:总分100分(占科目总成绩的30%)</div> <div class='p'>1、每个视频观看完成度50分:以后台数据统计为准,全部看完视频满分50分,其它酌情给分。</div> <div class='em'>注:视频观看考核的是实际播放时长,不是进度条的显示状态,进度条满格并不一定表示观看完这个视频。以下方每日学习时长为准。</div> <div class='p'>2、课程反馈建设性问题及课程完成情况50分:反馈问题以教务老师统计为准,课程完成情况以后台数据为准,是否按时完成视频观看、测试、作业提交,满分50分,酌情给分。</div> <div class='h2'>每章试题:总分100分(占科目总成绩的30%)</div> <div class='p'>本课程所有试题的平均正确率*100分*占总成绩30%=此项得分。(比如正确度为80%,则此项得分:80%*100*30%=24分)</div> <div class='h2'>结业大作业:总分100分(占科目总成绩的40%)</div> <div class='p'>结业大作业满分为100分,以助教老师给分为准。</div>", richText: "<div class='h1'>一、最终成绩计算</div> <div class='p'>课程表现得分*30%+每章试题得分*30%+结业大作业得分*40%=该门课程总得分,满分100分,低于80分为不及格,需重修此门课程。84分以上方可申请学位。</div> <img class='b1' src='https://zws-imgs-pub.oss-cn-beijing.aliyuncs.com/static/build/www/course-check.png' mode='aspectFill' /> <div class='h1'>二、具体细则</div> <div class='h2'>课程表现:总分100分(占科目总成绩的30%)</div> <div class='p'>1、每个视频观看完成度50分:以后台数据统计为准,全部看完视频满分50分,其它酌情给分。</div> <div class='em'>注:视频观看考核的是实际播放时长,不是进度条的显示状态,进度条满格并不一定表示观看完这个视频。以下方每日学习时长为准。</div> <div class='p'>2、课程反馈建设性问题及课程完成情况50分:反馈问题以教务老师统计为准,课程完成情况以后台数据为准,是否按时完成视频观看、测试、作业提交,满分50分,酌情给分。</div> <div class='h2'>每章试题:总分100分(占科目总成绩的30%)</div> <div class='p'>本课程所有试题的平均正确率*100分*占总成绩30%=此项得分。(比如正确度为80%,则此项得分:80%*100*30%=24分)</div> <div class='h2'>结业大作业:总分100分(占科目总成绩的40%)</div> <div class='p'>结业大作业满分为100分,以助教老师给分为准。</div>",
assess: { assess: {
score: '20', score: '20',
duration: '00:01:20', duration: '00:01:20',
...@@ -358,7 +363,8 @@ export default { ...@@ -358,7 +363,8 @@ export default {
'title': [ 'title': [
{ required: true, message: '请输入标题', trigger: 'blur' } { required: true, message: '请输入标题', trigger: 'blur' }
] ]
} },
timeHeart: null
} }
}, },
mounted () { mounted () {
...@@ -403,12 +409,18 @@ export default { ...@@ -403,12 +409,18 @@ export default {
}).catch(e => { this.$message.error(e.message) }).finally(() => { }) }).catch(e => { this.$message.error(e.message) }).finally(() => { })
}).catch(e => { this.$message.error(e.message); loading.close() }).finally(() => { }) }).catch(e => { this.$message.error(e.message); loading.close() }).finally(() => { })
window.addEventListener('resize', this.resizeRoot.bind(this), false) window.addEventListener('resize', this.resizeRoot.bind(this), false)
/* 实时刷新数据 */
if (this.timeHeart) { clearInterval(this.timeHeart); this.timeHeart = null }
this.timeHeart = setInterval(() => {
this.updatePages()
}, 3000)
}, },
destroyed () { destroyed () {
window.removeEventListener('resize', this.resizeRoot.bind(this), false) window.removeEventListener('resize', this.resizeRoot.bind(this), false)
/* 清空 ckeditor 需要调用方法删除 并 在DOM结构中也移除 */ /* 清空 ckeditor 需要调用方法删除 并 在DOM结构中也移除 */
this.ckeditor && this.ckeditor.destroy(true) this.ckeditor && this.ckeditor.destroy(true)
this.ckeditor = null this.ckeditor = null
if (this.timeHeart) { clearInterval(this.timeHeart); this.timeHeart = null }
}, },
updated () { updated () {
this.resizeRoot() this.resizeRoot()
...@@ -448,6 +460,20 @@ export default { ...@@ -448,6 +460,20 @@ export default {
] ]
})) }))
}, },
updatePages () {
cAction.courseAction.getCourseDetail(this.cid, this.sid).then(json => {
/* 更新直播状态 */
let course = json.tabs1ChapterList.course
for (let i = 0; i < course.length; i++) {
let chapters = course[i].chapters
for (let j = 0; j < chapters.length; j++) {
if (chapters[j].type === 5) {
this.tabs[1].chapterList.course[i].chapters[j].live = chapters[j].live
}
}
}
}).catch(e => { this.$message.error(e.message) }).finally(() => { })
},
/** /**
* 课程内容 - 列表展开或者跳转 * 课程内容 - 列表展开或者跳转
*/ */
...@@ -523,10 +549,22 @@ export default { ...@@ -523,10 +549,22 @@ export default {
} }
} else if (_course.chapters[i2].type === 4) { } else if (_course.chapters[i2].type === 4) {
this.$router.push({ path: `/player/${sid}/${cid}/chapter-read/${_id}` }) this.$router.push({ path: `/player/${sid}/${cid}/chapter-read/${_id}` })
} else if (_course.chapters[i2].type === 5) {
let status = _course.chapters[i2].live.live_status
if (status !== 0 && status !== 1 && status !== 103) {
this.$message.error(_course.chapters[i2].live.statusStr)
return
}
let enableRecord = _course.chapters[i2].live.enable_record
if (status === 103 && enableRecord !== undefined && enableRecord !== null && !enableRecord) {
this.$message.info('该直播没有回放')
return
}
this.$router.push({ path: `/player/${sid}/${cid}/live/${_id}` })
} }
return return
} }
this.$message.error('系统未知错误003') this.$message.error('点击频率过快,系统反应不过来,请稍后再试003')
return return
} }
this.$router.push({ path: `/player/${sid}/${cid}/chapter-video/${_id}/${type}` }) this.$router.push({ path: `/player/${sid}/${cid}/chapter-video/${_id}/${type}` })
......
...@@ -2,7 +2,7 @@ import App from '../app.vue' ...@@ -2,7 +2,7 @@ import App from '../app.vue'
import container from '../components/layout/container.vue' import container from '../components/layout/container.vue'
export default [ export default [
{ path: '/', redirect: '/app/my-learn/course' }, { path: '/', redirect: window.document.documentElement.clientWidth > 799 ? '/app/my-learn/course' : '/mobile/list' },
{ {
path: '/login', path: '/login',
redirect: '/login/index', redirect: '/login/index',
...@@ -126,6 +126,12 @@ export default [ ...@@ -126,6 +126,12 @@ export default [
name: 'exam', name: 'exam',
component: () => import('../../components/player/exam/exam.vue'), component: () => import('../../components/player/exam/exam.vue'),
props: true props: true
},
{
path: 'live/:id',
name: 'live',
component: () => import('../../components/player/live/live.vue'),
props: true
} }
] ]
}, },
...@@ -145,6 +151,32 @@ export default [ ...@@ -145,6 +151,32 @@ export default [
component: () => import('../../components/survey/surveyPhone.vue'), component: () => import('../../components/survey/surveyPhone.vue'),
props: true props: true
}, },
/* mobile 移动端 - 指向 */
{
path: '/mobile',
redirect: '/mobile/0/0/error/404',
component: () => import('../pages/mobile/index.vue'),
props: true,
children: [
{ path: 'error/404', component: () => import('../components/error/404.vue') },
{
path: 'list',
name: 'list',
component: () => import('../pages/mobile/list.vue'),
props: true
},
{
path: 'help/student',
name: 'studentHelp',
component: () => import('../pages/mobile/studentHelp.vue')
},
{
path: 'help/teacher',
name: 'teacherHelp',
component: () => import('../pages/mobile/teacherHelp.vue')
}
]
},
/* survey-phone 内未找到页面时 - 指向 */ /* survey-phone 内未找到页面时 - 指向 */
{ path: '/survey-phone/*', redirect: '/learn-error/learn-error' }, { path: '/survey-phone/*', redirect: '/learn-error/learn-error' },
/* 静态测试页面 */ /* 静态测试页面 */
......
...@@ -73,9 +73,9 @@ ...@@ -73,9 +73,9 @@
"js-md5": "^0.7.3", "js-md5": "^0.7.3",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"promise.prototype.finally": "^3.1.0", "promise.prototype.finally": "^3.1.0",
"vue": "^2.5.17", "vue": "^2.6.11",
"vue-loader": "^15.4.2", "vue-loader": "^15.9.0",
"vue-router": "^3.0.7", "vue-router": "^3.1.6",
"vue-template-compiler": "^2.5.17" "vue-template-compiler": "^2.6.11"
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论