Branch_d40a2540
yujialong 2 years ago
parent bad2c7bb35
commit 186618506f
  1. 10
      src/api/index.js
  2. BIN
      src/assets/img/exts/pdf.png
  3. BIN
      src/assets/img/exts/pic.png
  4. BIN
      src/assets/img/exts/ppt.png
  5. BIN
      src/assets/img/exts/txt.png
  6. BIN
      src/assets/img/exts/video.png
  7. BIN
      src/assets/img/exts/word.png
  8. BIN
      src/assets/img/eye.png
  9. BIN
      src/assets/img/hot.png
  10. BIN
      src/assets/img/my-school.png
  11. BIN
      src/assets/img/platform.png
  12. BIN
      src/assets/img/product-bg.png
  13. BIN
      src/assets/img/sort.png
  14. BIN
      src/assets/img/type.png
  15. 567
      src/pages/product/list/index.vue
  16. 455
      src/pages/product/show/index.vue
  17. 2
      src/pages/screen/index.vue
  18. 2
      src/pages/station/list/index.vue
  19. 251
      src/pages/station/preview/index.vue
  20. 6
      src/router/modules/product.js
  21. 9
      src/styles/page/station.scss

@ -30,10 +30,10 @@ export default {
saveLearningProgress: 'nakadai/nakadai/curriculum/learning/progressprogress/save', saveLearningProgress: 'nakadai/nakadai/curriculum/learning/progressprogress/save',
updateLearningProgress: 'nakadai/nakadai/curriculum/learning/progressprogress/update', updateLearningProgress: 'nakadai/nakadai/curriculum/learning/progressprogress/update',
// 课程笔记 // 课程笔记
addNote: `${host2}nakadai/curriculumNotes/addNote`, addNote: `nakadai/curriculumNotes/addNote`,
curriculumNoteList: `${host2}nakadai/curriculumNotes/curriculumNoteList`, curriculumNoteList: `nakadai/curriculumNotes/curriculumNoteList`,
deleteNotes: `${host2}nakadai/curriculumNotes/deleteNotes`, deleteNotes: `nakadai/curriculumNotes/deleteNotes`,
updateNote: `${host2}nakadai/curriculumNotes/updateNote`, updateNote: `nakadai/curriculumNotes/updateNote`,
// 权限管理 // 权限管理
getUserRolesPermissionMenu: `users/users/user-role/getUserRolesPermissionMenu`, getUserRolesPermissionMenu: `users/users/user-role/getUserRolesPermissionMenu`,
@ -363,6 +363,8 @@ export default {
supplierList: `nakadai/supplier/supplierList`, supplierList: `nakadai/supplier/supplierList`,
tagsList: `nakadai/tags/tagsList`, tagsList: `nakadai/tags/tagsList`,
listOfGoods: `nakadai/mall/listOfGoods`, listOfGoods: `nakadai/mall/listOfGoods`,
detailsOfGoods: `nakadai/mall/detailsOfGoods`,
addLearningRecord: `nakadai/mallCourseLearningRecord/addLearningRecord`,
// 课程管理三级联查 // 课程管理三级联查
courseDiscipline: `nakadai/nakadai/subject/courseDiscipline`, //课程学科类别 courseDiscipline: `nakadai/nakadai/subject/courseDiscipline`, //课程学科类别
courseProfessionalClass: `nakadai/nakadai/subject/courseProfessionalClass`, //课程专业类 courseProfessionalClass: `nakadai/nakadai/subject/courseProfessionalClass`, //课程专业类

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

@ -1,83 +1,104 @@
<template> <template>
<div class="wrap"> <div class="wrap">
<div class="search"> <el-carousel :interval="6000">
<div class="input"> <template v-for="(item, i) in banners">
<img src="@/assets/img/search.png" alt=""> <el-carousel-item :key="i">
<input type="text" placeholder="请输入产品名称" v-model="form.productName"> <div :class="['banner-item', {'cursor-pointer': item.url}]" @click="openLink(item)">
<img :src="item.banner" alt="">
<p class="banner-name">{{ item.title }}</p>
</div>
</el-carousel-item>
</template>
</el-carousel>
<div class="inner">
<div class="typw-wrap">
<div>
<img src="@/assets/img/hot.png" alt="">
<img class="m-l-5 m-r-10" src="@/assets/img/type.png" alt="">
<ul class="tab">
<li v-for="(tab, i) in tabs" :key="i" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li>
</ul>
</div>
<div class="search">
<img class="icon" src="@/assets/img/search.png" alt="">
<input type="text" placeholder="请输入产品名称" v-model="form.productName">
</div> </div>
</div>
<div class="p-wrap">
<div class="switchs">
<p class="type">分类</p>
<div class="val">全部</div>
<p class="type">按学科专业</p>
<div class="val">产品精选</div>
<div class="val">按热门标签</div>
</div> </div>
<div class="inner"> <div class="filter">
<div class="filter"> <dl>
<div class="wrap-inner" style="padding-bottom: 0"> <dt>学科专业</dt>
<dl v-if="active != 2"> <el-select v-model="form.categoryId" clearable @change="getProfessionalClass()" @clear="clearClass()">
<dt>学科专业</dt> <el-option v-for="(item,index) in subjectList" :key="index" :label="item.disciplineName" :value="item.disciplineId"></el-option>
<el-select v-model="form.categoryId" clearable @change="getProfessionalClass()" @clear="clearClass()"> </el-select>
<el-option v-for="(item,index) in subjectList" :key="index" :label="item.disciplineName" :value="item.disciplineId"></el-option>
</el-select>
<dt class="m-l-20">专业类</dt> <dt style="margin: 0 10px 0 50px">专业类</dt>
<el-select v-model="form.professionalCategoryId" clearable :disabled="form.categoryId ? false : true" @change="getProfessional" @clear="clearProfess()"> <el-select v-model="form.professionalCategoryId" clearable :disabled="form.categoryId ? false : true" @change="getProfessional" @clear="clearProfess()">
<el-option v-for="(item,index) in professionalClassList" :key="index" :label="item.professionalClassName" :value="item.professionalClassId"></el-option> <el-option v-for="(item,index) in professionalClassList" :key="index" :label="item.professionalClassName" :value="item.professionalClassId"></el-option>
</el-select> </el-select>
<dt class="m-l-20">专业</dt> <dt style="margin: 0 10px 0 50px">专业</dt>
<el-select v-model="form.professionalId" clearable :disabled="form.professionalCategoryId ? false : true" @change="initData"> <el-select v-model="form.professionalId" clearable :disabled="form.professionalCategoryId ? false : true" @change="initData">
<el-option v-for="(item,index) in professionalList" :key="index" :label="item.professionalName" :value="item.professionalId"></el-option> <el-option v-for="(item,index) in professionalList" :key="index" :label="item.professionalName" :value="item.professionalId"></el-option>
</el-select> </el-select>
</dl> </dl>
<dl> <dl>
<dt>产品类型</dt> <dt>产品类型</dt>
<dd :class="{active: form.productClassification === ''}" @click="filterChange('', 'productClassification')">全部</dd> <dd :class="{active: form.productClassification === ''}" @click="filterChange('', 'productClassification')">全部</dd>
<dd v-for="(item, i) in classifications" :key="i" :class="{active: form.productClassification === item.typeId}" @click="filterChange(item.typeId, 'productClassification')">{{ item.typeName }}</dd> <dd v-for="(item, i) in classifications" :key="i" :class="{active: form.productClassification === item.typeId}" @click="filterChange(item.typeId, 'productClassification')">{{ item.typeName }}</dd>
</dl> </dl>
<dl> <dl>
<dt>购买状态</dt> <dt>购买状态</dt>
<dd v-for="(item, i) in status" :key="i" :class="{active: form.purchaseStatus === item.id}" @click="filterChange(item.id, 'purchaseStatus')">{{ item.name }}</dd> <dd v-for="(item, i) in status" :key="i" :class="{active: form.purchaseStatus === item.id}" @click="filterChange(item.id, 'purchaseStatus')">{{ item.name }}</dd>
</dl> </dl>
<dl> </div>
<dt>排序</dt>
<dd v-for="(item, i) in sort" :key="i" :class="{active: form.sort === item.id}" @click="filterChange(item.id, 'sort')">{{ item.name }}</dd> <div class="filter m-t-20">
</dl> <dl>
</div> <dd v-for="(item, i) in sorts" :key="i" :class="{active: form.sort === item.id}" @click="filterChange(item.id, 'sort')">{{ item.name }}</dd>
</div> </dl>
<div class="courses"> </div>
<div class="course-bg"></div>
<template v-if="list.length"> <div class="courses">
<ul> <template v-if="list.length">
<li v-for="(item, index) in list" :key="index" @click="toDetail(item.id)"> <ul>
<img :src="item.coverUrl" alt="" /> <li v-for="(item, i) in list" :key="i" @click="toDetail(item.mallId)">
<div class="title">{{ item.productName }}</div> <img :src="item.coverDrawing" alt="" />
<div class="desc" v-html="item.courseIntroduction"></div> <img v-if="item.logoOfOurSchool" class="my-school" src="@/assets/img/my-school.png" alt="">
<div class="metas"> <div class="texts">
<div class="meta"> <div class="title">{{ item.productName }}</div>
<i class="el-icon-view"></i> <div class="desc" v-html="item.productIntroduction"></div>
1 <div class="metas">
</div> <template v-if="curTab === 2">
<div class="meta collect" @click.stop="collect(item)"> <el-tag
<i :class="item.collectionStatus ? 'el-icon-star-on' : 'el-icon-star-off'"></i> type="danger"
</div> effect="dark">
<div class="meta"> 官方精选
<i class="el-icon-user"></i> </el-tag>
职站 <div class="meta">{{ item.learningCount }}学过</div>
</div> </template>
<span v-if="item.courseType == 0" class="type">{{ item.courseType == 1 ? '付费' : '免费'}}</span> <div v-if="curTab === 3 && item.tagsName">
</div> <el-tag v-for="(tag, i) in item.tagsName.split(',')" :key="i" class="tag">{{ tag }}</el-tag>
</li> </div>
</ul> <template v-if="!curTab || curTab === 1">
<div class="pagination"> <div class="meta">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page"> <img class="icon" src="@/assets/img/eye.png" alt="">
</el-pagination> {{ item.learningCount }}
</div>
<div v-if="item.isAssociatedProduct === 0" class="meta">
<img class="icon" src="@/assets/img/platform.png" alt="">
平台官方
</div>
<!-- <span class="type">{{ item.courseType == 1 ? '付费' : '免费'}}</span> -->
</template>
</div>
</div> </div>
</template> </li>
</div> </ul>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page"></el-pagination>
</div>
</template>
</div> </div>
</div> </div>
</div> </div>
@ -87,13 +108,32 @@
import { Loading } from "element-ui"; import { Loading } from "element-ui";
import Setting from "@/setting"; import Setting from "@/setting";
export default { export default {
name: "course",
data() { data() {
return { return {
banners: [],
timer: null, timer: null,
active: +this.$route.query.source || 0, curTab: '',
tabs: [
{
id: '',
name: '全部'
},
{
id: 1,
name: '学科专业'
},
{
id: 2,
name: '产品精选'
},
{
id: 3,
name: '热门标签'
},
],
form: { form: {
categoryId: '', categoryId: '',
hotTag: 1,
professionalCategoryId: '', professionalCategoryId: '',
professionalId: '', professionalId: '',
productClassification: '', productClassification: '',
@ -119,7 +159,7 @@ export default {
name: '未购买' name: '未购买'
}, },
], ],
sort: [ sorts: [
{ {
id: 0, id: 0,
name: '综合排序' name: '综合排序'
@ -164,11 +204,22 @@ export default {
} }
}, },
mounted() { mounted() {
this.getBanner()
this.getSubject() this.getSubject()
this.getClass() this.getClass()
this.initData() this.initData()
}, },
methods: { methods: {
// banner
getBanner() {
this.$post(this.api.listMarketing, {
pageNum: 1,
pageSize: 1000
}).then(({ page }) => {
this.banners = page.records
}).catch(res => {})
},
//
getData() { getData() {
this.loadIns = Loading.service() this.loadIns = Loading.service()
this.$post(this.api.listOfGoods, { this.$post(this.api.listOfGoods, {
@ -250,6 +301,18 @@ export default {
this.classificationList = page.records this.classificationList = page.records
}).catch(res => {}) }).catch(res => {})
}, },
// tab
tabChange({ id }) {
this.curTab = id
this.form.hotTag = 1
this.form.selection = ''
if (id === 3) {
this.form.hotTag = 2
} else if (id === 2) {
this.form.selection = 1
}
this.initData()
},
// //
filterChange(id, prop) { filterChange(id, prop) {
this.form[prop] = id this.form[prop] = id
@ -259,14 +322,9 @@ export default {
this.page = val; this.page = val;
this.getData(); this.getData();
}, },
// //
collect(item) {
this.$post(`${this.api.collectCourse}?courseId=${item.id}&state=${item.collectionStatus ? 0 : 1}`).then(res => {
this.getData()
}).catch(res => {})
},
toDetail(id) { toDetail(id) {
this.$router.push(`/${this.isTourist ? 'preCourse' : 'course'}/details?id=${id}&source=${this.active}`); this.$router.push(`show?id=${id}`);
} }
} }
}; };
@ -275,180 +333,201 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.wrap { .wrap {
margin: -24px; margin: -24px;
} .banner-item {
.search {
position: relative; position: relative;
padding: 100px 0 130px;
text-align: center;
background: url(../../../assets/img/course-bg1.png) 0 0/100% 100% no-repeat;
h6 {
margin-bottom: 25px;
font-size: 26px;
color: #fff;
}
.input {
position: relative;
width: 700px;
margin: 0 auto;
}
img { img {
position: absolute; width: 100%;
top: 19px; height: 336px;
left: 14px;
} }
input { .banner-name {
width: 100%; position: absolute;
height: 62px; top: 116px;
line-height: 62px; left: 188px;
padding: 0 50px; font-size: 50px;
font-size: 18px; color: #2E2D31;
color: #333;
border: 0;
outline: none;
border-radius: 4px;
} }
}
.p-wrap {
display: flex;
justify-content: space-between;
width: 80%;
margin: 20px auto;
.inner {
width: calc(100% - 150px);
}
}
.switchs {
width: 150px;
.type {
font-weight: bold;
} }
.val { .inner {
margin: 10px 20px; width: 1146px;
font-size: 14px; margin: 18px auto;
} }
} .typw-wrap {
.wrap { display: flex;
.filter { justify-content: space-between;
width: 100%; margin-bottom: 18px;
padding: 15px; .left {
background-color: #fff; display: inline-flex;
dl {
display: flex;
align-items: center;
margin: 20px 0;
dt {
color: #333;
font-size: 16px;
font-weight: 600;
white-space: nowrap;
}
dd {
padding: 5px 15px;
color: #6a6a6a;
font-size: 16px;
white-space: nowrap;
cursor: pointer;
border-radius: 4px;
&.active {
color: $main-color;
background-color: #e6f0ff;
}
}
}
} }
.courses { .tab {
display: inline-flex;
li {
position: relative; position: relative;
padding: 10px 0 20px; margin: 0 20px;
// background: url(../../../assets/img/course3.png) 0 0/auto no-repeat; font-size: 18px;
.course-bg { line-height: 25px;
color: #0B1D30;
cursor: pointer;
&:after {
content: '';
position: absolute; position: absolute;
top: 0; bottom: -10px;
right: 0; left: 50%;
width: 602px; width: 53px;
height: 100%; height: 4px;
// background: url(../../../assets/img/course4.png) (0 -100px)/140% 140% no-repeat; transform: translateX(-50%);
} }
ul { &.active:after {
position: relative; background-color: #007EFF;
display: flex;
flex-wrap: wrap;
} }
li { }
width: calc(20% - 20px); }
min-height: 250px; }
overflow: hidden; .search {
padding: 18px; position: relative;
margin: 10px; display: flex;
cursor: pointer; align-items: center;
border-radius: 8px; width: 410px;
background-color: #fff; height: 48px;
transition: all 0.3s; padding: 0 18px;
img { background-color: #fff;
width: 100%; border-radius: 31px;
height: 165px; input {
transition: .3s; height: 40px;
} margin-left: 7px ;
.title { font-size: 14px;
margin: 10px 0 5px; color: #333;
color: #0B1D30; border: 0;
font-size: 16px; outline: none !important;
word-wrap: break-word; }
word-break: break-all; }
overflow: hidden; .filter {
text-overflow: ellipsis; padding: 5px 30px;
white-space: nowrap; background-color: #fff;
} border-radius: 10px;
.desc span { dl {
color: #f00; display: flex;
font-size: 14px; align-items: center;
background-color: #f00; margin: 20px 0;
} dt {
.desc { min-width: 60px;
color: #757F92; margin-right: 30px;
font-size: 14px; color: #666;
display: -webkit-box; font-size: 14px;
-webkit-box-orient: vertical; font-weight: 600;
-webkit-line-clamp: 2; white-space: nowrap;
overflow: hidden; }
dd {
&.ie { padding: 5px 15px;
height: 80px; color: #333;
text-overflow: ellipsis; font-size: 14px;
white-space: nowrap; white-space: nowrap;
} cursor: pointer;
} &.active {
.type { font-weight: 600;
display: inline-block; color: #007EFF;
padding: 2px 10px;
border-radius: 20px;
color: #1cdbb8;
border: 1px solid;
}
.metas {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.meta {
color: #a9a9a9;
font-size: 12px;
}
.collect {
font-size: 20px;
}
&:hover {
box-shadow: 0px 5px 12px 4px rgba(142, 123, 253, 0.09), 0px 3px 6px 0px rgba(142, 123, 253, 0.12), 0px 1px 2px -2px rgba(142, 123, 253, 0.16);
img {
transform: scale(1.05);
}
}
} }
@media (max-width: 1700px) { }
li { }
width: calc(25% - 20px); }
} .courses {
position: relative;
margin-top: 24px;
ul {
position: relative;
display: flex;
flex-wrap: wrap;
}
li {
position: relative;
width: calc((100% - 66px) / 4);
min-height: 250px;
margin: 0 22px 22px 0;
cursor: pointer;
border-radius: 10px;
background-color: #fff;
transition: all 0.3s;
overflow: hidden;
&:nth-child(4n) {
margin-right: 0;
}
img {
width: 100%;
height: 140px;
transition: .3s;
}
.my-school {
position: absolute;
top: 0;
right: 0;
width: 57px;
height: 22px;
}
.texts {
padding: 10px;
}
.title {
margin-bottom: 10px;
color: #0B1D30;
font-size: 14px;
font-weight: 600;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc {
min-height: 34px;
color: #757F92;
font-size: 12px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
&.ie {
height: 80px;
text-overflow: ellipsis;
white-space: nowrap;
} }
}
.tag {
margin-right: 8px;
color: #007EFF;
background-color: #F9F9F9;
border: 0;
}
.type {
display: inline-block;
padding: 4px 11px;
font-size: 12px;
color: #666;
border: 1px solid #DADADA;
border-radius: 20px;
}
.metas {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.meta {
display: inline-flex;
align-items: center;
color: #B5BFD5;
font-size: 12px;
.icon {
width: 14px;
max-height: 14px;
margin-right: 3px;
}
}
&:hover {
box-shadow: 0px 5px 12px 4px rgba(142, 123, 253, 0.09), 0px 3px 6px 0px rgba(142, 123, 253, 0.12), 0px 1px 2px -2px rgba(142, 123, 253, 0.16);
img {
transform: scale(1.05);
}
}
} }
}
} }
</style> </style>

@ -0,0 +1,455 @@
<template>
<div class="wrap">
<div class="inner">
<div class="top">
<div v-if="form.interfaceDiagrams" class="pics">
<img v-for="(pic, i) in form.interfaceDiagrams" :key="i" :src="pic" alt="">
</div>
<div class="right">
<h6>{{ form.mall.productName }}</h6>
<div class="meta">
<span class="val">48</span> 个实验项目&emsp;&emsp;已有 <span class="val">{{ form.goodsRes.learningCount }}</span>人学过
</div>
<div class="des" v-html="form.mall.productIntroduction"></div>
<div class="field">适用专业{{ form.goodsRes.disciplineName }}</div>
<div class="fields">
<div v-if="form.mall.applicationScenario" class="field"><span class="label">适用场景</span>{{ form.mall.applicationScenario }}</div>
<div v-if="form.mall.matchingCourse" class="field"><span class="label">匹配课程</span>{{ form.mall.matchingCourse }}</div>
<div v-if="form.mall.courseHours" class="field"><span class="label">预计课时</span>{{ form.mall.courseHours }}</div>
<div v-if="form.goodsRes.typeName" class="field"><span class="label">产品类型</span>{{ form.goodsRes.typeName }}</div>
</div>
<button v-if="form.goodsRes.logoOfOurSchool" class="btn" @click="toTrail">试用体验</button>
<button v-else class="btn entry" @click="toStation">进入实验</button>
</div>
</div>
<div class="course">
<div class="detail">
<ul class="tab">
<li v-for="(tab, i) in tabs" :key="i" :class="{active: curTab === tab.id}" @click="tabChange(tab)">{{ tab.name }}</li>
</ul>
<div class="courses">
<template v-if="!curTab">
<h6>课程介绍</h6>
<div class="des" v-html="form.mall.detailedIntroduction"></div>
</template>
<template v-else>
<div v-for="(item, i) in chapterList" :key="i">
<h6>{{ item.name }}</h6>
<ul v-if="item.subsectionList.length" class="list">
<li v-for="(section, i) in item.subsectionList" :key="i" @click="toPreview(item, section)">
<p class="name">
<img v-if="section.fileType === 'pptx'" src="@/assets/img/exts/ppt.png" alt="">
<img v-else-if="section.fileType === 'mp4'" src="@/assets/img/exts/video.png" alt="">
<img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'" src="@/assets/img/exts/word.png" alt="">
<img v-else-if="section.fileType === 'txt'" src="@/assets/img/exts/txt.png" alt="">
<img v-else-if="section.fileType === 'pdf'" src="@/assets/img/exts/pdf.png" alt="">
<img v-else src="@/assets/img/exts/pic.png" alt="">
{{ section.projectName }}
</p>
<i :class="['status', section.whetherToStudyOrNot ? 'el-icon-success' : 'circle']" @click.stop="studySection(item, section)"></i>
</li>
</ul>
</div>
</template>
</div>
</div>
<div class="products">
<h6>热门产品推荐</h6>
<ul class="product">
<li v-for="(item, i) in hots" :key="i" @click="toDetail(item.mallId)">
<img :src="item.coverDrawing" alt="" />
<img v-if="item.logoOfOurSchool" class="my-school" src="@/assets/img/my-school.png" alt="">
<div class="texts">
<div class="title">{{ item.productName }}</div>
<div class="desc" v-html="item.productIntroduction"></div>
<div class="metas">
<template v-if="item.selected">
<el-tag
type="danger"
effect="dark">
官方精选
</el-tag>
<div class="meta">{{ item.learningCount }}学过</div>
</template>
<template v-else>
<div class="meta">
<img class="icon" src="@/assets/img/eye.png" alt="">
{{ item.learningCount }}
</div>
<div v-if="item.isAssociatedProduct === 0" class="meta">
<img class="icon" src="@/assets/img/platform.png" alt="">
平台官方
</div>
<span class="type">{{ item.courseType == 1 ? '付费' : '免费'}}</span>
</template>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import Util from "@/libs/util"
import Setting from "@/setting"
export default {
data() {
return {
id: this.$route.query.id,
curTab: 0,
tabs: [
{
id: 0,
name: '详情介绍'
},
{
id: 1,
name: '课程目录'
},
],
form: {
mall: {},
goodsRes: {}
},
chapterList: [],
hots: []
};
},
mounted() {
this.getData()
this.getHot()
},
methods: {
//
getData() {
this.$get(`${this.api.detailsOfGoods}?mallId=${this.id}`).then(res => {
const e = res.orderDetails
if (e.mall.interfaceDiagram) e.interfaceDiagrams = e.mall.interfaceDiagram.split(',')
this.form = e
this.getChapter()
}).catch(err => {})
},
//
async getChapter() {
let res = await this.$post(`${this.api.courseLearningProgress}?courseId=${this.form.mall.associatedProduct}`)
this.chapterList = res.list
},
// tab
tabChange({ id }) {
this.curTab = id
},
//
toPreview(item, section) {
this.form.goodsRes.logoOfOurSchool ?
this.$router.push('/station/preview?courseId=' + this.form.mall.associatedProduct + '&curriculumName=' + this.form.mall.associatedProductName) :
this.toTrail()
},
// /
studySection(item) {
item.whetherToStudyOrNot ?
this.$post(`${this.api.deleteLearningProgress}?id=${item.learningProgressId}`).then(res => {
this.getProgress()
}).catch(res => {}) :
this.$post(this.api.saveLearningProgress, {
cid: this.courseId,
projectId: item.projectId,
}).then(res => {
this.getProgress()
}).catch(res => {})
},
//
toTrail() {
window.open('https://f.wps.cn/g/VekixBcm/')
},
//
toStation() {
this.$post(`${this.api.addLearningRecord}?mallId=${this.id}`).then(res => {
this.$router.push('/station/preview?courseId=' + this.form.mall.associatedProduct + '&curriculumName=' + this.form.mall.associatedProductName)
}).catch(res => {})
},
//
getHot() {
this.$post(this.api.listOfGoods, {
hotTag: 1,
sort: 1,
pageNum: 1,
pageSize: 2,
}).then(({ page }) => {
this.hots = page.records
}).catch(res => {})
},
//
toDetail(id) {
this.$router.push(`show?id=${id}`);
},
}
};
</script>
<style lang="scss" scoped>
.wrap {
background: #F3F6FA;
.inner {
width: 1154px;
margin: 0 auto;
}
.top {
display: flex;
padding: 24px;
background-color: #fff;
border-radius: 10px;
.pics {
width: 436px;
margin-right: 24px;
img {
width: 140px;
height: 62px;
margin-right: 8px;
border-radius: 8px;
&:first-child {
width: 100%;
height: 192px;
margin-bottom: 12px;
}
&:last-child {
margin-right: 0;
}
}
}
.right {
width: 646px;
}
h6 {
font-size: 24px;
font-weight: 600;
color: #2E2D31;
}
.meta {
margin: 10px 0;
font-size: 12px;
color: #2E2D31;
.val {
color: #007EFF;
}
}
.des {
margin-bottom: 15px;
font-size: 14px;
color: #666;
line-height: 20px;
}
.field {
font-size: 14px;
color: #2E2D31;
.label {
color: #333;
}
}
.fields {
display: flex;
margin: 10px 0 20px;
.field {
margin-right: 50px;
&:last-child {
margin-right: 0;
}
}
}
.btn {
width: 119px;
height: 46px;
color: #fff;
background: #64C25A;
border-radius: 6px;
border: 0;
cursor: pointer;
&:hover {
opacity: .9;
}
&:first-child {
margin-left: 11px;
}
}
.entry {
background: #007EFF;
}
}
.tab {
display: inline-flex;
li {
position: relative;
margin-right: 20px;
font-size: 18px;
line-height: 25px;
color: #0B1D30;
cursor: pointer;
&:after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
width: 53px;
height: 4px;
transform: translateX(-50%);
}
&.active:after {
background-color: #007EFF;
}
}
}
.course {
display: flex;
margin-top: 20px;
.detail {
width: 835px;
padding: 20px 36px;
background-color: #fff;
border-radius: 10px;
}
}
.courses {
margin-top: 40px;
h6 {
margin-bottom: 20px;
font-size: 14px;
color: #333;
}
.list {
height: calc(100vh - 530px);
padding-right: 15px;
overflow: auto;
li {
display: flex;
justify-content: space-between;
align-items: center;
height: 46px;
border-radius: 8px;
&:hover {
background: #F6FBFF;
}
}
.name {
display: inline-flex;
align-items: center;
font-size: 14px;
color: #333;
img {
margin-right: 8px;
}
}
.status {
font-size: 18px;
color: #00c935;
}
.circle {
width: 18px;
height: 18px;
border-radius: 50%;
border: 1px solid #ccc;
}
}
}
.products {
width: 270px;
margin-left: 24px;
&>h6 {
font-size: 14px;
color: #0B1D30;
}
}
.product {
margin-top: 11px;
li {
position: relative;
margin-bottom: 15px;
cursor: pointer;
border-radius: 10px;
background-color: #fff;
transition: all 0.3s;
overflow: hidden;
img {
width: 100%;
height: 140px;
transition: .3s;
}
.my-school {
position: absolute;
top: 0;
right: 0;
width: 57px;
height: 22px;
}
.texts {
padding: 10px;
}
.title {
margin-bottom: 10px;
color: #0B1D30;
font-size: 14px;
font-weight: 600;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc {
min-height: 34px;
color: #757F92;
font-size: 12px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
&.ie {
height: 80px;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.tag {
margin-right: 8px;
color: #007EFF;
background-color: #F9F9F9;
border: 0;
}
.type {
display: inline-block;
padding: 4px 11px;
font-size: 12px;
color: #666;
border: 1px solid #DADADA;
border-radius: 20px;
}
.metas {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.meta {
display: inline-flex;
align-items: center;
color: #B5BFD5;
font-size: 12px;
.icon {
width: 14px;
max-height: 14px;
margin-right: 3px;
}
}
&:hover {
box-shadow: 0px 5px 12px 4px rgba(142, 123, 253, 0.09), 0px 3px 6px 0px rgba(142, 123, 253, 0.12), 0px 1px 2px -2px rgba(142, 123, 253, 0.16);
img {
transform: scale(1.05);
}
}
}
}
}
</style>

@ -327,7 +327,7 @@
</thead> </thead>
</table> </table>
</div> </div>
<div class="main_table" ref="active" style="max-height: 220px;margin-top: 0;overflow: hidden"> <div class="main_table" ref="active" style="max-height: 230px;margin-top: 0;overflow: hidden">
<table> <table>
<tbody> <tbody>
<tr v-for="(item, i) in actives" :key="i"> <tr v-for="(item, i) in actives" :key="i">

@ -19,7 +19,7 @@
<div class="item" :title="item.curriculumName" @click="goPreview(item)" :key="index" v-if="!keyword || item.curriculumName.includes(keyword)"> <div class="item" :title="item.curriculumName" @click="goPreview(item)" :key="index" v-if="!keyword || item.curriculumName.includes(keyword)">
<img :src="item.coverUrl" alt=""> <img :src="item.coverUrl" alt="">
<div class="bottom"> <div class="bottom">
<p class="text"><span>{{ item.curriculumName }}</span></p> <p class="text"><span>{{ item.goodsName || item.curriculumName }}</span></p>
<a>进入实验</a> <a>进入实验</a>
</div> </div>
</div> </div>

@ -64,7 +64,7 @@
<i class="icon el-icon-notebook-2"></i> 目录 <i class="icon el-icon-notebook-2"></i> 目录
</div> </div>
<div :class="['item', { active: type === 2 }]" @click="typeChange(2)"> <div :class="['item', { active: type === 2 }]" @click="typeChange(2)">
<i class="icon el-icon-timer"></i> 进度 <i class="icon el-icon-timer"></i> 学进度
</div> </div>
</div> </div>
<div class="chapters"> <div class="chapters">
@ -81,9 +81,9 @@
</template> </template>
</template> </template>
<div v-else class="section"> <div v-else class="section">
<p class="sectionName" v-for="(item, i) in progressList" :key="i"> <p class="sectionName" v-for="(item, i) in progressList" :key="i" :title="item.projectName">
{{ i + 1 }}. {{ i + 1 }}.
{{ item.name }} {{ item.projectName }}
<i :class="['icon', item.whetherToStudyOrNot ? 'el-icon-success' : 'circle']" @click.stop="studySection(item)"></i> <i :class="['icon', item.whetherToStudyOrNot ? 'el-icon-success' : 'circle']" @click.stop="studySection(item)"></i>
</p> </p>
</div> </div>
@ -98,115 +98,117 @@
<div class="tabs"> <div class="tabs">
<a class="item" v-for="(item, i) in tabs" :key="i" :class="{active: item.id == active}" @click="tabChange(item)">{{ item.name }}</a> <a class="item" v-for="(item, i) in tabs" :key="i" :class="{active: item.id == active}" @click="tabChange(item)">{{ item.name }}</a>
</div> </div>
<template v-if="active === 1"> <div class="tab-content">
<el-card shadow="hover" class="m-t-20 m-b-20"> <template v-if="active === 1">
<h4 style="margin-bottom: 10px;font-size: 16px;">课程简介</h4> <el-card shadow="hover" class="m-t-20 m-b-20">
<p>{{ briefIntroduction }}</p> <h4 style="margin-bottom: 10px;font-size: 16px;">课程简介</h4>
</el-card> <p>{{ briefIntroduction }}</p>
<el-card shadow="hover" class="m-b-20"> </el-card>
<h4 style="margin-bottom: 10px;font-size: 16px;">课程目标</h4> <el-card shadow="hover" class="m-b-20">
<p>{{ teachingObjectives }}</p> <h4 style="margin-bottom: 10px;font-size: 16px;">课程目标</h4>
</el-card> <p>{{ teachingObjectives }}</p>
</template> </el-card>
<template v-if="active === 2"> </template>
<div class="page"> <template v-if="active === 2">
<template v-if="showNoteAdd"> <div class="page">
<el-form class="form" ref="form" label-width="120px" center> <template v-if="showNoteAdd">
<el-form-item class="required" label="笔记标题"> <el-form class="form" ref="form" label-width="120px" center>
<el-input placeholder="请输入笔记标题" v-model="noteForm.noteName" maxlength="30" style="width: 400px"></el-input> <el-form-item class="required" label="笔记标题">
</el-form-item> <el-input placeholder="请输入笔记标题" v-model="noteForm.noteName" maxlength="30" style="width: 400px"></el-input>
<el-form-item class="required" label="笔记内容"> </el-form-item>
<Editor api-key='rnk6zw9v267xqz7pf98twt1vmrvltmd436je7a642pckltda' v-model="noteForm.noteContent" :init="editorConfig" /> <el-form-item class="required" label="笔记内容">
</el-form-item> <Editor api-key='rnk6zw9v267xqz7pf98twt1vmrvltmd436je7a642pckltda' v-model="noteForm.noteContent" :init="editorConfig" />
</el-form> </el-form-item>
<div class="text-right"> </el-form>
<el-button type="primary" @click="submitNote">保存</el-button> <div class="text-right">
</div> <el-button type="primary" @click="submitNote">保存</el-button>
</template>
<template v-else>
<div class="tool">
<ul class="filter">
<li>
<label>搜索</label>
<el-input placeholder="请输入标题" v-model="noteKeyword" clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" @click="addNote">新增笔记</el-button>
</div> </div>
</div> </template>
<el-timeline class="timeline"> <template v-else>
<el-timeline-item placement="top" v-for="(item, i) in notes" :key="i"> <div class="tool">
<p class="sign">{{ item.createTime }}</p> <ul class="filter">
<div class="ver"> <li>
<div> <label>搜索</label>
{{ item.noteName }} <el-input placeholder="请输入标题" v-model="noteKeyword" clearable></el-input>
<span class="action"> </li>
<i class="el-icon-edit-outline" @click="editNote(item)"></i> </ul>
<i class="el-icon-delete" @click="delNote(item)"></i> <div>
</span> <el-button type="primary" @click="addNote">新增笔记</el-button>
</div>
</div>
<div class="des" v-html="item.noteContent"></div>
</el-timeline-item>
</el-timeline>
</template>
</div>
</template>
<template v-if="active === 4">
<div class="page">
<quill ref="quill" :border="true" v-model="msg" :height="150" :toTop="false" />
<ul class="msg">
<li v-for="(item, i) in msgs" :key="i">
<div class="li-wrap">
<img :src="item.avatar" alt="" class="avatar">
<div class="texts">
<h6>
<span class="name">{{ item.userName }}</span>
发表于 {{ item.createDate }}
</h6>
<div class="des" v-html="item.content"></div>
</div>
<div class="action">
<i class="icon el-icon-chat-dot-square"></i>
<i class="icon el-icon-delete"></i>
<img class="icon" src="@/assets/img/like.png" alt="">
</div> </div>
</div> </div>
<div class="reply" v-if="item.showReply"> <el-timeline class="timeline">
<quill :border="true" v-model="item.replyContent" :toTop="false" :height="150" /> <el-timeline-item placement="top" v-for="(item, i) in notes" :key="i">
<div class="m-t-10 text-right"> <p class="sign">{{ item.createTime }}</p>
<el-button type="primary" size="mini">提交</el-button> <div class="ver">
<div>
{{ item.noteName }}
<span class="action">
<i class="el-icon-edit-outline" @click="editNote(item)"></i>
<i class="el-icon-delete" @click="delNote(item)"></i>
</span>
</div>
</div>
<div class="des" v-html="item.noteContent"></div>
</el-timeline-item>
</el-timeline>
</template>
</div>
</template>
<template v-if="active === 4">
<div class="page">
<quill ref="quill" :border="true" v-model="msg" :height="150" :toTop="false" />
<ul class="msg">
<li v-for="(item, i) in msgs" :key="i">
<div class="li-wrap">
<img :src="item.avatar" alt="" class="avatar">
<div class="texts">
<h6>
<span class="name">{{ item.userName }}</span>
发表于 {{ item.createDate }}
</h6>
<div class="des" v-html="item.content"></div>
</div>
<div class="action">
<i class="icon el-icon-chat-dot-square"></i>
<i class="icon el-icon-delete"></i>
<img class="icon" src="@/assets/img/like.png" alt="">
</div>
</div> </div>
</div> <div class="reply" v-if="item.showReply">
<ul class="msg children" v-if="item.showChildren"> <quill :border="true" v-model="item.replyContent" :toTop="false" :height="150" />
<li v-for="(reply,i) in item.children" :key="i"> <div class="m-t-10 text-right">
<div class="li-wrap"> <el-button type="primary" size="mini">提交</el-button>
<img class="avatar" :src="reply.avatar" alt=""> </div>
<div class="texts"> </div>
<div class="name">{{reply.userName}}</div> <ul class="msg children" v-if="item.showChildren">
<div class="des" v-html="reply.content"></div> <li v-for="(reply,i) in item.children" :key="i">
<div class="date">{{reply.createDate}}</div> <div class="li-wrap">
</div> <img class="avatar" :src="reply.avatar" alt="">
<div class="action"> <div class="texts">
<i class="icon el-icon-chat-dot-square"></i> <div class="name">{{reply.userName}}</div>
<i class="icon el-icon-delete"></i> <div class="des" v-html="reply.content"></div>
<img class="icon" src="@/assets/img/like.png" alt=""> <div class="date">{{reply.createDate}}</div>
</div> </div>
</div> <div class="action">
<div class="reply" v-if="reply.showReply"> <i class="icon el-icon-chat-dot-square"></i>
<quill :border="true" v-model="reply.replyContent" :toTop="false" :height="150" /> <i class="icon el-icon-delete"></i>
<div class="m-t-10 text-right"> <img class="icon" src="@/assets/img/like.png" alt="">
<el-button type="primary" size="mini">提交</el-button> </div>
</div> </div>
</div> <div class="reply" v-if="reply.showReply">
</li> <quill :border="true" v-model="reply.replyContent" :toTop="false" :height="150" />
<div class="m-t-10 text-right">
<el-button type="primary" size="mini">提交</el-button>
</div>
</div>
</li>
</ul>
<div v-if="item.getCommentReplyNum" class="toggle"><span @click="item.showChildren = !item.showChildren">{{item.showChildren ? '收起所有回复' : `查看所有${item.getCommentReplyNum}条回复`}} <i class="el-icon-arrow-down"></i></span></div>
</li>
</ul> </ul>
<div v-if="item.getCommentReplyNum" class="toggle"><span @click="item.showChildren = !item.showChildren">{{item.showChildren ? '收起所有回复' : `查看所有${item.getCommentReplyNum}条回复`}} <i class="el-icon-arrow-down"></i></span></div> </div>
</li> </template>
</ul> </div>
</div>
</template>
<el-dialog title="请选择项目" v-loading="loading" :visible.sync="projectVisible" width="828px" custom-class="project-dia" :close-on-click-modal="false"> <el-dialog title="请选择项目" v-loading="loading" :visible.sync="projectVisible" width="828px" custom-class="project-dia" :close-on-click-modal="false">
@ -385,24 +387,23 @@ export default {
// 10 // 10
this.overdue = isRenew this.overdue = isRenew
this.getChapter() this.getChapter()
this.getProgress()
}).catch(res => {}) }).catch(res => {})
}, },
//
async getChapter() { async getChapter() {
let res = await this.$post(`${this.api.courseLearningProgress}?courseId=${this.courseId}`); let res = await this.$get(`${this.api.curriculumChapter}/${this.courseId}`);
this.chapterList = res.chapterList; this.chapterList = res.chapterList;
const list = []
res.chapterList.forEach(e => {
e.subsectionList.forEach(n => {
n.chapterId = e.id
list.push(n)
})
})
this.progressList = list
this.schedule = +(res.schedule.replace('%', ''))
if (this.chapterList.length && this.chapterList[0].subsectionList && this.chapterList[0].subsectionList.length) { if (this.chapterList.length && this.chapterList[0].subsectionList && this.chapterList[0].subsectionList.length) {
this.preview(this.chapterList[0].subsectionList[0], this.chapterList[0].name, 1); this.preview(this.chapterList[0].subsectionList[0], this.chapterList[0].name, 1);
} }
}, },
//
async getProgress() {
let res = await this.$post(`${this.api.courseLearningProgress}?courseId=${this.courseId}`);
this.progressList = res.list
this.schedule = +(res.schedule.replace('%', ''))
},
// //
typeChange(id) { typeChange(id) {
this.getChapter() this.getChapter()
@ -489,14 +490,13 @@ export default {
studySection(item) { studySection(item) {
item.whetherToStudyOrNot ? item.whetherToStudyOrNot ?
this.$post(`${this.api.deleteLearningProgress}?id=${item.learningProgressId}`).then(res => { this.$post(`${this.api.deleteLearningProgress}?id=${item.learningProgressId}`).then(res => {
this.getChapter() this.getProgress()
}).catch(res => {}) : }).catch(res => {}) :
this.$post(this.api.saveLearningProgress, { this.$post(this.api.saveLearningProgress, {
chapterId: item.chapterId,
cid: this.courseId, cid: this.courseId,
subsectionId: item.id, projectId: item.projectId,
}).then(res => { }).then(res => {
this.getChapter() this.getProgress()
}).catch(res => {}) }).catch(res => {})
}, },
preview(row, chapterName, showDia = 0) { preview(row, chapterName, showDia = 0) {
@ -797,9 +797,6 @@ $height: 700px;
/deep/.el-progress-bar { /deep/.el-progress-bar {
width: 92%; width: 92%;
} }
/deep/.el-progress__text {
color: #fff;
}
.desc-wrap{ .desc-wrap{
position: relative; position: relative;
.desc{ .desc{
@ -878,9 +875,6 @@ $height: 700px;
border-radius: 50%; border-radius: 50%;
border: 1px solid #ccc; border: 1px solid #ccc;
} }
&.active{
color: #fff;
}
} }
} }
.buy { .buy {
@ -998,6 +992,9 @@ $height: 700px;
} }
} }
.tab-content {
width: 80%;
}
/deep/.project-dia { /deep/.project-dia {
.el-dialog__body { .el-dialog__body {
padding: 28px 32px; padding: 28px 32px;

@ -14,10 +14,14 @@ export default {
component: BasicLayout, component: BasicLayout,
children: [ children: [
{ {
name: `${pre}list`,
path: `list`, path: `list`,
component: () => import("@/pages/product/list"), component: () => import("@/pages/product/list"),
meta: { title: "产品中心" } meta: { title: "产品中心" }
}, },
{
path: `show`,
component: () => import("@/pages/product/show"),
meta: { title: "产品详情" }
},
] ]
}; };

@ -80,8 +80,11 @@
} }
/deep/.timeline { /deep/.timeline {
padding-left: 12%; padding-left: 9%;
overflow: hidden; overflow: hidden;
.el-timeline-item {
padding-bottom: 40px;
}
.el-timeline-item__node--normal { .el-timeline-item__node--normal {
top: 30px; top: 30px;
} }
@ -96,7 +99,7 @@
.sign { .sign {
position: relative; position: relative;
display: inline-block; display: inline-block;
margin-left: -15%; margin-left: -12.5%;
font-size: 14px; font-size: 14px;
color: #9076FF; color: #9076FF;
} }
@ -110,7 +113,7 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding-bottom: 10px; padding-bottom: 10px;
margin: -32px 0 20px; margin: -22px 0 20px;
font-size: 18px; font-size: 18px;
color: #9076FF; color: #9076FF;
border-bottom: 1px dashed #bfbfbf; border-bottom: 1px dashed #bfbfbf;

Loading…
Cancel
Save