提交 9bcd159b authored 作者: 王鹏飞's avatar 王鹏飞

2.0第一版提测

上级 48d63988
......@@ -2814,8 +2814,8 @@
},
"@vue/component-compiler-utils": {
"version": "3.2.0",
"resolved": "https://registry.npm.taobao.org/@vue/component-compiler-utils/download/@vue/component-compiler-utils-3.2.0.tgz?cache=0&sync_timestamp=1595427694165&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcomponent-compiler-utils%2Fdownload%2F%40vue%2Fcomponent-compiler-utils-3.2.0.tgz",
"integrity": "sha1-j4UYLO7Sjps8dTE95mn4MWbRHl0=",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz",
"integrity": "sha512-lejBLa7xAMsfiZfNp7Kv51zOzifnb29FwdnMLa96z26kXErPFioSf9BMcePVIQ6/Gc6/mC0UrPpxAWIHyae0vw==",
"requires": {
"consolidate": "^0.15.1",
"hash-sum": "^1.0.2",
......@@ -2830,8 +2830,8 @@
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM="
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
......@@ -3460,17 +3460,17 @@
"dev": true
},
"axios": {
"version": "0.20.0",
"resolved": "https://registry.npm.taobao.org/axios/download/axios-0.20.0.tgz?cache=0&sync_timestamp=1597979791211&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faxios%2Fdownload%2Faxios-0.20.0.tgz",
"integrity": "sha1-BXujDwSIRpSZOozQf6OUz/EcUL0=",
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
},
"dependencies": {
"follow-redirects": {
"version": "1.13.0",
"resolved": "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.0.tgz?cache=0&sync_timestamp=1597057997789&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.13.0.tgz",
"integrity": "sha1-tC6Nk6Kn7qXtiGM2dtZZe8jjhNs="
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
}
}
},
......@@ -3556,9 +3556,9 @@
},
"dependencies": {
"core-js": {
"version": "2.6.11",
"resolved": "https://registry.npm.taobao.org/core-js/download/core-js-2.6.11.tgz",
"integrity": "sha1-OIMUafmSK97Y7iHJ3EaYXgOZMIw="
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
}
}
},
......@@ -4446,8 +4446,8 @@
},
"consolidate": {
"version": "0.15.1",
"resolved": "https://registry.npm.taobao.org/consolidate/download/consolidate-0.15.1.tgz",
"integrity": "sha1-IasEMjXHGgfUXZqtmFk7DbpWurc=",
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz",
"integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==",
"requires": {
"bluebird": "^3.1.1"
}
......@@ -4547,9 +4547,9 @@
}
},
"core-js": {
"version": "3.6.5",
"resolved": "https://registry.npm.taobao.org/core-js/download/core-js-3.6.5.tgz",
"integrity": "sha1-c5XcJzrzf7LlDpvT2f6EEoUjHRo="
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
"integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q=="
},
"core-js-compat": {
"version": "3.6.5",
......@@ -4667,9 +4667,9 @@
}
},
"cross-env": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz",
"integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==",
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"requires": {
"cross-spawn": "^7.0.1"
}
......@@ -5280,9 +5280,9 @@
"dev": true
},
"element-ui": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.14.0.tgz",
"integrity": "sha512-dda4xw40HT7Xcx/7aV5METvGjwMumdd5D1B7vjhDkmqvJP/9IEqgL5VsYA4YXz+RUVqyxMByRwf1WedrICJTTQ==",
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.0.tgz",
"integrity": "sha512-9z/1+b7V8fvp08OnKUEW4/BZ72kT+IhuKR9cTMz3XoCTKmEsqLLb32XjbO/DznSFaaiFbOYU93G7WtkvrCAL9A==",
"requires": {
"async-validator": "~1.8.1",
"babel-helper-vue-jsx-merge-props": "^2.0.0",
......@@ -7044,7 +7044,7 @@
},
"hash-sum": {
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
"integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ="
},
"hash.js": {
......@@ -8080,9 +8080,9 @@
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"loglevel": {
"version": "1.6.8",
......@@ -8101,8 +8101,8 @@
},
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427519396&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz",
"integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
......@@ -8184,16 +8184,16 @@
},
"merge-source-map": {
"version": "1.1.0",
"resolved": "https://registry.npm.taobao.org/merge-source-map/download/merge-source-map-1.1.0.tgz",
"integrity": "sha1-L93n5gIJOfcJBqaPLXrmheTIxkY=",
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
"integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
"requires": {
"source-map": "^0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM="
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
......@@ -9452,8 +9452,8 @@
},
"prettier": {
"version": "1.19.1",
"resolved": "https://registry.npm.taobao.org/prettier/download/prettier-1.19.1.tgz?cache=0&sync_timestamp=1598414081254&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fprettier%2Fdownload%2Fprettier-1.19.1.tgz",
"integrity": "sha1-99f1/4qc2HKnvkyhQglZVqYHl8s=",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"optional": true
},
"pretty-error": {
......@@ -9576,7 +9576,7 @@
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"psl": {
......@@ -12091,18 +12091,18 @@
},
"vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz",
"integrity": "sha1-UylVzB6yCKPZkLOp+acFdGV+CPI="
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
"integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog=="
},
"vue-i18n": {
"version": "8.18.2",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.18.2.tgz",
"integrity": "sha512-0X5nBTCZAVjlwcrPaYJwNs3iipBBTv0AUHwQUOa8yP3XbQGWKbRHqBb3OhCYtum/IHDD21d/df5Xd2VgyxbxfA=="
"version": "8.22.4",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.22.4.tgz",
"integrity": "sha512-XLI5s0AdqMP2Lf4I4CmdmOq8kjb5DDFGR77wAuxCfpEuYSfhTRyyx6MetgZMiL6Lxa0DasjBOiOcciU3NkL3/Q=="
},
"vue-loader": {
"version": "15.9.3",
"resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-15.9.3.tgz",
"integrity": "sha1-DeNdnlVdPtU5aVFsrFziVTEpndo=",
"version": "15.9.6",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz",
"integrity": "sha512-j0cqiLzwbeImIC6nVIby2o/ABAWhlppyL/m5oJ67R5MloP0hj/DtFgb0Zmq3J9CG7AJ+AXIvHVnJAPBvrLyuDg==",
"requires": {
"@vue/component-compiler-utils": "^3.1.0",
"hash-sum": "^1.0.2",
......@@ -12132,14 +12132,14 @@
}
},
"vue-router": {
"version": "3.4.3",
"resolved": "https://registry.npm.taobao.org/vue-router/download/vue-router-3.4.3.tgz?cache=0&sync_timestamp=1597843291750&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-router%2Fdownload%2Fvue-router-3.4.3.tgz",
"integrity": "sha1-+pN2hhbuM4qhdPFgrJZRZ/pXL/o="
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz",
"integrity": "sha512-CGAKWN44RqXW06oC+u4mPgHLQQi2t6vLD/JbGRDAXm0YpMv0bgpKuU5bBd7AvMgfTz9kXVRIWKHqRwGEb8xFkA=="
},
"vue-style-loader": {
"version": "4.1.2",
"resolved": "https://registry.npm.taobao.org/vue-style-loader/download/vue-style-loader-4.1.2.tgz",
"integrity": "sha1-3t80mAbyXOtOZPOtfApE+6c1/Pg=",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
"integrity": "sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==",
"requires": {
"hash-sum": "^1.0.2",
"loader-utils": "^1.0.2"
......@@ -12156,13 +12156,13 @@
},
"vue-template-es2015-compiler": {
"version": "1.9.1",
"resolved": "https://registry.npm.taobao.org/vue-template-es2015-compiler/download/vue-template-es2015-compiler-1.9.1.tgz",
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU="
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw=="
},
"vuex": {
"version": "3.5.1",
"resolved": "https://registry.npm.taobao.org/vuex/download/vuex-3.5.1.tgz",
"integrity": "sha1-8bjc6mSbwlJUz09DWAgdv12hiz0="
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
"integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
},
"watchpack": {
"version": "1.7.4",
......@@ -12967,7 +12967,7 @@
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
},
"yargs": {
......
......@@ -69,19 +69,19 @@
"vconsole-webpack-plugin": "^1.5.2"
},
"dependencies": {
"axios": "^0.20.0",
"cross-env": "^7.0.2",
"element-ui": "^2.14.0",
"axios": "^0.21.1",
"cross-env": "^7.0.3",
"element-ui": "^2.15.0",
"js-cookie": "^2.2.1",
"lodash": "^4.17.15",
"lodash": "^4.17.20",
"vue": "^2.6.12",
"vue-i18n": "^8.16.0",
"vue-loader": "^15.9.3",
"vue-i18n": "^8.22.4",
"vue-loader": "^15.9.6",
"vue-meta-info": "^0.1.7",
"vue-router": "^3.4.3",
"vue-router": "^3.4.9",
"vue-template-compiler": "^2.6.12",
"vuex": "^3.5.1",
"core-js": "^3.6.5"
"vuex": "^3.6.0",
"core-js": "^3.8.3"
},
"engines": {
"node": ">=8.9"
......
......@@ -2,6 +2,9 @@
<div class="app-container">
<div class="app-container-hd" v-if="title">
<div class="app-container-hd__title">{{ title }}</div>
<div class="app-container-hd__right">
<slot name="header-right"></slot>
</div>
</div>
<div class="app-container-bd">
<slot></slot>
......@@ -28,6 +31,9 @@ export default {
box-sizing: border-box;
}
.app-container-hd {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 8px;
margin-bottom: 20px;
border-bottom: 1px solid #ccc;
......
<template>
<div class="course-list" element-loading-text="加载中..." v-loading="!loaded">
<template v-if="list.length">
<course-list-item v-for="item in list" :data="item" :key="item.id" v-bind="$attrs" v-on="$listeners" />
<template v-if="currentList.length">
<course-list-item v-for="item in currentList" :data="item" :key="item.id" v-bind="$attrs" v-on="$listeners" />
</template>
<template v-else>
<slot name="empty">
......@@ -19,7 +19,8 @@ export default {
name: 'CourseList',
components: { CourseListItem },
props: {
requestCallback: Function
requestCallback: Function,
searchValue: String
},
data() {
return {
......@@ -27,10 +28,20 @@ export default {
list: []
}
},
computed: {
currentList() {
if (!this.searchValue) {
return this.list
}
return this.list.filter(item => {
return item.course_name.includes(this.searchValue)
})
}
},
methods: {
getCourseList() {
api
.getCourseModule()
.getCourseList()
.then(response => {
this.list = this.requestCallback ? this.requestCallback(response) : response
this.$emit('request-success', response)
......
<template>
<div class="course-item">
<div class="course-item-top">
<img class="course-item-pic" :src="data.photo" v-if="data.photo" />
<div class="course-item-content">
<div class="course-item__title">{{ data.title }}</div>
<div class="course-item__tools">
<div class="course-item__text course-item__text__course">{{ data.course_num }}节课</div>
<div class="course-item__text course-item__text__video">{{ data.video_num }}节视频课</div>
<div class="course-item__text course-item__text__freevideo">{{ data.free_video_num }}个免费视频</div>
<img class="course-item-pic" :src="data.curriculum.curriculum_picture" @click="$emit('on-click', data)" />
<div class="course-item-content">
<div class="course-item__title">{{ data.course_name }}</div>
<div class="course-item__tools">
<div class="course-item__progress">
<span>视频观看进度</span>
<el-progress :percentage="data.video_progress"></el-progress>
</div>
<div class="course-item__buttons">
<el-button type="primary" size="small" round @click="$emit('on-click', data)">查看课程</el-button>
</div>
</div>
</div>
<div class="course-item-bottom">
<div class="course-child" v-for="item in data.child" :key="item.id" @click="$emit('on-click', item)">
<div class="name">{{ item.course_name }}</div>
<div class="progress" v-if="showProgress">{{ item.video_progress | progressText }}</div>
</div>
</div>
</div>
......@@ -47,13 +43,11 @@ export default {
<style lang="scss" scoped>
.course-item {
background: #ffffff;
border-radius: 8px;
padding: 30px;
margin-bottom: 20px;
}
.course-item-top {
display: flex;
padding: 14px 0;
}
.course-item + .course-item {
border-top: 1px solid #ccc;
}
.course-item-pic {
width: 160px;
......@@ -61,6 +55,7 @@ export default {
margin-right: 20px;
border-radius: 2px;
overflow: hidden;
cursor: pointer;
}
.course-item-content {
flex: 1;
......@@ -78,40 +73,16 @@ export default {
-webkit-line-clamp: 2;
overflow: hidden;
}
.course-item__text {
display: inline-block;
font-size: 14px;
}
.course-item__text + .course-item__text {
margin-left: 0.1rem;
}
.course-item__text__course {
color: #88bbff;
}
.course-item__text__video {
color: #5ad0b2;
}
.course-item__text__freevideo {
color: #d05a5a;
}
.course-child {
.course-item__tools {
display: flex;
align-items: center;
padding: 20px 0;
border-bottom: 1px solid #eee;
cursor: pointer;
&:hover {
color: #c01540;
}
.name {
flex: 1;
font-size: 18px;
}
.progress {
margin-left: 20px;
font-size: 12px;
color: #999;
}
.course-item__progress {
display: flex;
flex: 1;
.el-progress {
margin: 0 10px;
width: 50%;
}
}
</style>
......@@ -8,14 +8,24 @@
<span @click="logout">退出登录</span>
</div>
</div>
<ul class="nav">
<li v-for="(item, index) in datalist" :key="index" :class="genClasses(item)">
<router-link :to="item.path">
<i class="iconfont" :class="item.icon" v-if="item.icon"></i>
<span>{{ item.title }}</span>
</router-link>
</li>
</ul>
<el-menu class="nav" :unique-opened="true" :router="true" :default-active="activeLink">
<template v-for="item in datalist">
<el-submenu :index="item.title" :key="item.title" v-if="item.children">
<template slot="title">
<i class="iconfont" :class="item.icon"></i>
<span>{{ item.title }}</span>
</template>
<el-menu-item :index="item.path" :key="item.title" v-for="item in item.children">
<span slot="title">{{ item.title }}</span>
</el-menu-item>
</el-submenu>
<el-menu-item :index="item.path" :key="item.title" v-else>
<i class="iconfont" :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</el-menu-item>
</template>
</el-menu>
</div>
</div>
</template>
......@@ -27,19 +37,49 @@ export default {
name: 'AppAside',
props: {
menus: { type: Array, default: () => [] },
showUser: { type: Boolean, default: true }
showUser: { type: Boolean, default: false }
},
data() {
return {
activeLink: '/course/learn',
defaultMenus: [
{ title: '课程学习', icon: 'icon-bianzu6-hong', path: '/course/learn' },
{ title: '考前摸底', icon: 'icon-bianzuhong', path: '/testExam' },
// { title: '真题实战', icon: 'icon-kaoshihong', path: '/mock' },
{ title: '错题集合', icon: 'icon-guanlizhongxinbeifen-hong', path: '/my/questions/wrong' },
{ title: '收藏试题', icon: 'icon-shoucang-hong', path: '/my/questions/collection' },
// { title: '必考考点', icon: 'icon-kaozheng-hong', path: '/course/test' },
{ title: '意见反馈', icon: 'icon-fankui-hong', path: '/feedback' },
{ title: '联系客服', icon: 'icon-bianzu8-hong', path: '/contact' }
{
title: '我的课程',
icon: 'icon-bianzu6-hong',
children: [{ title: '课程学习', path: '/course/learn' }]
},
{
title: '我的考试',
icon: 'icon-bianzuhong',
children: [
{ title: '考前摸底', path: '/testExam' },
{ title: '错题集合', path: '/my/questions/wrong' },
{ title: '收藏试题', path: '/my/questions/collection' }
]
},
{
title: '实训练习',
icon: 'icon-kaoshihong',
children: [{ title: '实训案例练习', path: '/xxxx' }]
},
{
title: '个人中心',
icon: 'icon-guanlizhongxinbeifen-hong',
children: [
{ title: '个人信息', path: '/account' },
{ title: '修改密码', path: '/account/password' },
{ title: '安全设置', path: '/account/safe' }
]
},
{
title: '帮助与反馈',
icon: 'icon-bianzu8-hong',
children: [
{ title: '服务专区', path: '/contact' },
{ title: '系统说明', path: '/doc' },
{ title: '常见问题', path: '/help' }
]
}
]
}
},
......@@ -57,6 +97,14 @@ export default {
return this.user.avatar || defaultAvatar
}
},
watch: {
$route: {
immediate: true,
handler(to, from) {
this.activeLink = to.path
}
}
},
methods: {
genClasses(data) {
const isActive = this.$route.fullPath.includes(data.path)
......@@ -110,28 +158,27 @@ export default {
}
.nav {
border: 0;
padding: 30px 0;
li {
text-align: center;
color: #ccc;
.iconfont {
font-size: 16px;
font-weight: 600;
color: #666;
a {
display: block;
padding: 16px 0;
}
&:hover,
&.is-active {
color: #c01540;
background-color: #fff4f7;
.iconfont {
color: #c01540;
}
}
.iconfont {
margin-right: 4px;
color: #ccc;
}
color: currentColor;
}
.el-submenu__title:hover {
color: #c01540;
}
.is-active {
color: #c01540;
}
.is-active .el-submenu__title {
background: #fff4f7;
color: #c01540;
}
.el-menu-item:hover,
.el-menu-item:focus {
color: #c01540;
background: transparent;
}
}
}
......
......@@ -5,17 +5,28 @@
</div>
<div class="tool">
<!-- <app-search-bar :value="$route.query.keywords" @search="handleSearch" /> -->
<nav class="nav">
<!-- <nav class="nav">
<router-link to="/">首页</router-link>
<router-link to="/my">我的</router-link>
<!-- <router-link to="/messages">通知</router-link> -->
</nav>
<router-link to="/messages">通知</router-link>
</nav> -->
<el-dropdown>
<div class="user">
<img :src="avatar" class="user-avatar" />
<span class="user-name">{{ user.realname }}</span>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-user" @click.native="$router.push('/account')">个人中心</el-dropdown-item>
<el-dropdown-item icon="el-icon-switch-button" @click.native="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import AppSearchBar from '@/components/AppSearchBar'
import defaultAvatar from '@/assets/images/avatar.png'
export default {
name: 'AppHeader',
components: { AppSearchBar },
......@@ -24,15 +35,29 @@ export default {
title: '金融产品数字化营销职业技能等级证书'
}
},
computed: {
user() {
return this.$store.state.user
},
avatar() {
return this.user.avatar || defaultAvatar
}
},
methods: {
handleSearch(value) {
this.$router.replace({ path: '/search', query: { keywords: value } })
},
// 退出登录
logout() {
this.$store.dispatch('logout').then(() => {
window.location.href = webConf.others.loginUrl
})
}
}
}
</script>
<style lang="scss" >
<style lang="scss">
.app-header {
display: flex;
align-items: center;
......@@ -60,5 +85,30 @@ export default {
padding: 0 20px;
}
}
.user {
height: 80px;
padding: 0 10px;
display: flex;
align-items: center;
cursor: pointer;
&:hover {
background-color: #fff4f7;
}
}
.user-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.user-name {
padding: 0 10px;
}
}
</style>
......@@ -13,11 +13,11 @@
id="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no, viewport-fit=cover"
/>
<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.1/skins/default/aliplayer-min.css" />
<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.3/skins/default/aliplayer-min.css" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2173492_ctgt96uojqw.css" />
</head>
<body>
<div id="app"></div>
<script src="https://g.alicdn.com/de/prismplayer/2.9.1/aliplayer-min.js"></script>
<script src="https://g.alicdn.com/de/prismplayer/2.9.3/aliplayer-min.js"></script>
</body>
</html>
......@@ -6,7 +6,7 @@
<aside-chapter :data="data" :chapters="chapters" :active="active"></aside-chapter>
</div>
</el-tab-pane>
<el-tab-pane label="学习资料" name="1" v-if="active && active.type === 2">
<el-tab-pane label="讲义" name="1" v-if="active && active.type === 2">
<div class="tab-pane">
<aside-lecture :ppts="ppts" :pptIndex="pptIndex" v-on="$listeners"></aside-lecture>
</div>
......
<template>
<app-container title="个人信息"> </app-container>
</template>
<script>
import AppContainer from '@/components/AppContainer'
export default {
components: { AppContainer }
}
</script>
......@@ -10,10 +10,12 @@
<el-form-item label="重复新密码" prop="passwordR">
<el-input type="password" v-model="ruleForm.passwordR" placeholder="请重复新密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">保存</el-button>
</el-form-item>
</el-form>
<template #footer>
<div class="app-container-ft">
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">保存</el-button>
</div>
</template>
</app-container>
</template>
......
<template>
<app-container title="安全设置">
<el-form :model="ruleForm" :rules="rules" label-width="100px" ref="ruleForm" class="form">
<el-form-item label="手机号码" prop="phone">
<el-input type="password" v-model="ruleForm.phone"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="app-container-ft">
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">保存</el-button>
</div>
</template>
</app-container>
</template>
<script>
import AppContainer from '@/components/AppContainer'
import * as api from '@/api/account'
export default {
components: { AppContainer },
data() {
return {
ruleForm: {
phone: ''
},
rules: {
phone: [{ required: true, message: '请输入手机号码', trigger: 'blur' }]
},
submitLoading: false
}
},
methods: {
handleSubmit() {
this.$refs.ruleForm.validate().then(this.handleSubmitRequest)
},
handleSubmitRequest() {
this.submitLoading = true
api
.updatePassword(this.ruleForm)
.then(response => {
this.$message({ message: '密码修改成功', type: 'success' })
// 重置表单
this.$refs.ruleForm.resetFields()
})
.finally(() => {
this.submitLoading = false
})
}
}
}
</script>
<style lang="scss" scoped>
.form {
max-width: 340px;
}
</style>
......@@ -4,6 +4,7 @@
<ul>
<li v-for="subItem in item.children" :key="subItem.id" @click="handleClick(subItem)">
<div class="name">{{ subItem.name }}</div>
<div class="duration">{{ subItem.duration }}</div>
<div class="progress" v-if="showProgress">{{ progressText(subItem.video_progress) }}</div>
</li>
</ul>
......
<template>
<div class="teacher">
<div class="teacher-item" v-for="item in data" :key="item.id">
<img :src="item.lecturer_avatar" class="teacher-item-pic" />
<div class="teacher-item-content">
<p class="t1">{{ item.lecturer_name }}</p>
<p class="t2">{{ item.lecturer_education }}</p>
<p class="t2">{{ item.lecturer_title }}</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: { type: Array, default: () => [] }
}
}
</script>
<style lang="scss" scoped>
.teacher-item {
display: flex;
margin-bottom: 10px;
}
.teacher-item-pic {
width: 90px;
height: 110px;
object-fit: cover;
margin-right: 10px;
}
.teacher-item-content {
flex: 1;
.t1 {
font-weight: bold;
}
.t2 {
margin-top: 5px;
color: #707070;
}
}
</style>
<template>
<course-list @on-click="handleClick" />
<app-container title="课程学习">
<template #header-right>
<div class="search">
<el-input prefix-icon="el-icon-search" clearable v-model="searchValue" @keyup.enter.native="handleSearch" />
<el-button type="text" @click="handleSearch">搜索</el-button>
</div>
</template>
<course-list @on-click="handleClick" :searchValue="searchValue" />
</app-container>
</template>
<script>
import AppContainer from '@/components/AppContainer'
import CourseList from '@/components/CourseList.vue'
export default {
components: { CourseList },
components: { AppContainer, CourseList },
data() {
return {
searchValue: ''
}
},
methods: {
handleClick(data) {
this.$router.push({ name: 'courseLearnItem', params: { id: data.id } })
}
this.$router.push({ name: 'courseLearnItem', params: { id: data.course_id } })
},
// 搜索
handleSearch() {}
}
}
</script>
<style lang="scss" scoped>
.search {
display: flex;
width: 300px;
.el-button {
margin-left: 10px;
}
}
</style>
<template>
<div class="main-container" element-loading-text="加载中..." v-loading="!loaded">
<div class="course-top" v-if="detail.curriculum">
<app-container title="课程详情" element-loading-text="加载中..." v-loading="!loaded">
<div class="course-top" v-if="loaded">
<div class="course-top-hd">
<div class="course-top__title">{{ detail.curriculum.curriculum_name }}</div>
<div class="course-top-hd-left">
<div class="course-top__title">{{ detail.curriculum.curriculum_name }}</div>
<div class="course-top__progress">
视频观看进度 <el-progress :percentage="detail.video_progress"></el-progress>
</div>
</div>
<div class="course-top-hd-right">
<el-button type="primary" size="small" @click="onChapterClick(latestVideo)" v-if="latestVideo">
{{ buttonText }}
</el-button>
</div>
</div>
<div class="course-top-bd">
<div class="course-top__pic"><img :src="detail.curriculum.curriculum_picture" /></div>
<div class="course-top__content" v-html="detail.curriculum.curriculum_represent"></div>
</div>
</div>
<el-tabs v-model="tabActive">
<el-tab-pane lazy label="按章节学习">
<course-chapter :courseId="courseId" :data="detail.chapters"></course-chapter>
</el-tab-pane>
<!-- <el-tab-pane lazy label="按考点学习">
<div class="course-bottom">
<div class="course-bottom-left">
<el-tabs v-model="tabActive">
<el-tab-pane lazy label="课程内容">
<course-chapter :courseId="courseId" :showProgress="true" :data="detail.chapters"></course-chapter>
</el-tab-pane>
<!-- <el-tab-pane lazy label="按考点学习">
<course-tag :courseId="courseId" @on-click="onTagClick"></course-tag>
</el-tab-pane> -->
</el-tabs>
</div>
</el-tabs>
</div>
<div class="course-bottom-right">
<el-tabs>
<el-tab-pane label="课程讲师">
<course-teacher :data="detail.lecturers"></course-teacher>
</el-tab-pane>
</el-tabs>
</div>
</div>
</app-container>
</template>
<script>
import AppContainer from '@/components/AppContainer'
import CourseChapter from './components/CourseChapter'
import CourseTeacher from './components/CourseTeacher'
import CourseTag from '@/components/CourseTag'
import * as api from '@/api/course.js'
export default {
components: { CourseChapter, CourseTag },
components: { AppContainer, CourseChapter, CourseTag, CourseTeacher },
metaInfo() {
return {
title: this.detail.course_name || ''
......@@ -41,6 +64,23 @@ export default {
computed: {
courseId() {
return this.$route.params.id
},
buttonText() {
return this.detail.latest_play ? '继续学习' : '开始学习'
},
// 扁平化章节数据
flatChapters() {
return this.detail.chapters.reduce((result, item) => {
return result.concat(item.children)
}, [])
},
// 最新的视频
latestVideo() {
if (this.detail.latest_play && this.flatChapters.length) {
return this.flatChapters.find(item => item.resource_id === this.detail.latest_play)
} else {
return this.flatChapters.length ? this.flatChapters[0] : null
}
}
},
methods: {
......@@ -59,6 +99,9 @@ export default {
// 考点点击
onTagClick(data) {
this.$router.push({ name: 'courseTagItem', params: { courseId: this.courseId, id: data.id } })
},
onChapterClick(data) {
this.$router.push({ name: 'viewerCourseChapter', params: { cid: this.courseId, id: data.id } })
}
},
beforeMount() {
......@@ -79,15 +122,27 @@ export default {
padding-bottom: 20px;
}
.course-top-hd {
padding-bottom: 8px;
margin-bottom: 10px;
border-bottom: 1px solid #ccc;
display: flex;
justify-content: space-between;
padding-bottom: 10px;
}
.course-top-hd-left {
flex: 1;
}
.course-top__title {
font-size: 18px;
font-weight: bold;
line-height: 1;
}
.course-top__progress {
margin-top: 10px;
display: flex;
align-items: center;
.el-progress {
width: 50%;
margin: 0 10px;
}
}
.course-top-bd {
display: flex;
}
......@@ -108,4 +163,14 @@ export default {
line-height: 24px;
overflow: hidden;
}
.course-bottom {
display: flex;
}
.course-bottom-left {
flex: 1;
}
.course-bottom-right {
margin-left: 20px;
width: 300px;
}
</style>
<template>
<app-container title="系统说明"> </app-container>
</template>
<script>
import AppContainer from '@/components/AppContainer'
export default {
components: { AppContainer }
}
</script>
<template>
<app-container title="常见问题">
<dl v-for="(item, index) in list" :key="index">
<dt>{{ item.title }}</dt>
<dd>{{ item.content }}</dd>
</dl>
</app-container>
</template>
<script>
import AppContainer from '@/components/AppContainer'
export default {
components: { AppContainer },
data() {
return {
list: [
{
title: '给组件绑定的事件为什么无法触发?',
content: '在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native 修饰符'
},
{
title: '给组件绑定的事件为什么无法触发?',
content: '在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native 修饰符'
},
{
title: '给组件绑定的事件为什么无法触发?',
content: '在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native 修饰符'
}
]
}
}
}
</script>
<style lang="scss" scoped>
dl {
padding: 10px 0;
}
dt {
font-weight: bold;
color: #262626;
}
dd {
padding-top: 10px;
color: #666;
}
dl + dl {
border-top: 1px solid #eee;
}
</style>
......@@ -69,11 +69,23 @@ export default [
{ path: '/contact', component: () => import(/* webpackChunkName: "contact" */ '@/pages/contact') },
/* 通知 */
{ path: '/messages', component: () => import(/* webpackChunkName: "messages" */ '@/pages/messages') },
/* 通知 */
{ path: '/doc', component: () => import(/* webpackChunkName: "help" */ '@/pages/doc') },
/* 通知 */
{ path: '/help', component: () => import(/* webpackChunkName: "help" */ '@/pages/help') },
{
path: '/account',
component: () => import(/* webpackChunkName: "account" */ '@/pages/account/index')
},
/* 修改密码 */
{
path: '/account/password',
component: () => import(/* webpackChunkName: "account" */ '@/pages/account/password')
},
{
path: '/account/safe',
component: () => import(/* webpackChunkName: "account" */ '@/pages/account/safe')
},
{
path: '/my/questions/wrong',
component: () => import(/* webpackChunkName: "course-learn" */ '@/pages/my/questions/questionWrong')
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论