产品课程列表及详情

master
yujialong 5 months ago
parent 05da260225
commit c9d0d17779
  1. 6
      src/api/index.js
  2. 49
      src/pages/course/index.vue
  3. 1101
      src/pages/index/list/index copy.vue
  4. 270
      src/pages/index/list/index.vue
  5. 819
      src/pages/index/show/index copy.vue
  6. 229
      src/pages/index/show/index.vue
  7. 2
      src/setting.js

@ -1,5 +1,5 @@
import Setting from '@/setting'
const host = Setting.huoranApi
const { huoranApi: host } = Setting
export default {
newlyPublishedArticles: `/iasf/sysContent/newlyPublishedArticles`,
@ -28,6 +28,10 @@ export default {
listMarketing: `/nakadai/nakadai/mall/marketing/promotion/pagingQueryList`,
courseProduct: `/iasf/productDetails/courseProduct`,
categoryList: `/iasf/categoryService/Category/list`,
productDetailsFind: `/iasf/productDetails/findById`,
courseDiscipline: `/iasf/subject/courseDiscipline`,
courseProfessionalClass: `/iasf/subject/courseProfessionalClass`,
courseProfessional: `/iasf/subject/courseProfessional`,
// 产品中心
productCategoryList: `${host}/nakadai/productClassification/productCategoryList`,
productTypeList: `${host}/nakadai/productType/productTypeList`,

@ -1,6 +1,8 @@
<template>
<div class="wrap">
<div class="search">
<img v-if="info.columnBanner" :src="info.columnBanner" alt="" class="search-bg">
<div v-else class="search-bg default"></div>
<h6>精品课程精彩讲解</h6>
<div class="input">
<img src="@/assets/images/search.png" alt="">
@ -84,6 +86,8 @@ export default {
data () {
return {
id: +this.$route.query.id,
info: {},
columnBanner: '',
columns: [],
defaultProps: {
value: 'id',
@ -106,10 +110,7 @@ export default {
};
},
mounted () {
this.getCategory()
this.getClassification()
this.getLeftColumn()
this.getData()
this.init()
},
computed: {
site () {
@ -117,6 +118,11 @@ export default {
}
},
watch: {
$route () {
this.id = this.$route.query.id
this.info = {}
this.init()
},
keyword: function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
@ -129,6 +135,12 @@ export default {
}
},
methods: {
init () {
this.getCategory()
this.getClassification()
this.getInfo()
this.getData()
},
getList () {
this.$post(this.api.courseProduct, {
...this.form,
@ -165,6 +177,17 @@ export default {
})
.catch((res) => { });
},
// banner
getBanner (data) {
for (const e of data) {
if (e.columnBanner) this.columnBanner = e.columnBanner
if (e.id == this.info.id) {
break
} else if (e.children.length) {
this.getBanner(e.children)
}
}
},
//
getLeftColumn () {
this.$post(`${this.api.oneLevelChecksThemAll}?id=${this.id}&isSort=1&siteId=${this.site}`).then(({ data }) => {
@ -173,8 +196,9 @@ export default {
// banner
if (!this.info.columnBanner) {
this.getBanner(data);
this.info.columnBanner = this.columnBanner || require('@/assets/images/column-banner.png');
this.info.columnBanner = this.columnBanner || ''
}
console.log("🚀 ~ this.$post ~ this.info:", this.info)
this.$nextTick(() => {
const el = this.$refs.leftColumn
el && el.setCurrentKey(this.id)
@ -225,10 +249,21 @@ export default {
position: relative;
padding: 100px 0 130px;
text-align: center;
.search-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
&.default {
background: url(../../assets/images/course/course-bg2.png) (73px 50px)/250px auto no-repeat,
url(../../assets/images/course/course-bg4.png) (top left) / auto no-repeat,
url(../../assets/images/course/course-bg3.png) (top right) / auto no-repeat,
url(../../assets/images/course/course-bg1.png) 0 0/100% 100% no-repeat;
}
}
h6 {
margin-bottom: 25px;
@ -338,13 +373,13 @@ export default {
right: 0;
width: 2px;
height: 100%;
background-color: #083a93;
background-color: #6fa3ff;
}
.el-tree-node__label,
.custom-tree-node {
font-weight: 600;
color: #1150ac;
color: #449cff;
}
}
}

File diff suppressed because it is too large Load Diff

@ -52,7 +52,7 @@
</div>
<div class="search">
<img class="icon" src="@/assets/images/search.png" alt="">
<input type="text" placeholder="请输入产品名称" v-model="form.productName">
<input type="text" placeholder="请输入产品名称" v-model="form.keyWord">
</div>
</div>
<div class="filter">
@ -60,79 +60,63 @@
<dl>
<dt>学科类别</dt>
<div class="vals">
<dd :class="{ active: categoryId === '' }" @click="categoryClick({ id: '' }, 1)">全部</dd>
<dd :class="{ active: categoryId === 1 }" style="margin-right: 20px"
@click="categoryClick({ id: 1 }, 1)">不限
</dd>
<dd v-for="(item, i) in category" :key="i" :class="{ active: categoryId === item.id }"
@click="categoryClick(item, 1)">{{ item.name }}</dd>
<dd :class="{ active: form.subjectCategoryId === '' }" @click="subjectClick('')">全部</dd>
<dd v-for="(item, i) in category" :key="i"
:class="{ active: form.subjectCategoryId === item.disciplineId }" @click="subjectClick(item)">{{
item.disciplineName }}</dd>
</div>
</dl>
<dl v-if="categoryId && categoryId !== 1">
<dl v-if="form.subjectCategoryId && form.subjectCategoryId !== 1">
<dt>专业类</dt>
<div class="vals">
<dd :class="{ active: professionalCategoryId === '' }" @click="categoryClick({ id: '' }, 2)">全部</dd>
<dd :class="{ active: form.professionalCategoryId === '' }" @click="professionalClick('')">全部
</dd>
<dd v-for="(item, i) in professionalClasses" :key="i"
:class="{ active: professionalCategoryId === item.id }" @click="categoryClick(item, 2)">{{ item.name
:class="{ active: form.professionalCategoryId === item.professionalClassId }"
@click="professionalClick(item)">{{
item.professionalClassName
}}
</dd>
</div>
</dl>
<dl v-if="professionalCategoryId && professionalCategoryId !== 1">
<dl v-if="form.professionalCategoryId && form.professionalCategoryId !== 1">
<dt>专业</dt>
<div class="vals">
<dd :class="{ active: professionalId === '' }" @click="categoryClick({ id: '' }, 3)">全部</dd>
<dd v-for="(item, i) in professionals" :key="i" :class="{ active: professionalId === item.id }"
@click="categoryClick(item, 3)">{{ item.name }}</dd>
<dd :class="{ active: form.majorId === '' }" @click="majorClick('')">全部</dd>
<dd v-for="(item, i) in professionals" :key="i"
:class="{ active: form.majorId === item.professionalId }" @click="majorClick(item)">{{
item.professionalName }}</dd>
</div>
</dl>
</template>
<dl v-if="curTab == 3">
<dt>产品标签</dt>
<div class="vals">
<dd :class="{ active: form.tagId === '' }" @click="filterChange('', 'tagId')">全部</dd>
<dd v-for="(item, i) in labels" :key="i" :class="{ active: form.tagId === item.tagsId }"
@click="filterChange(item.tagsId, 'tagId')">{{ item.tagsName }}</dd>
</div>
</dl>
<template v-if="curTab == 4">
<dl>
<dt>方案分类</dt>
<div class="vals">
<dd :class="{ active: form.productClassification === '' }"
@click="filterChange('', 'productClassification')">全部</dd>
<dd v-for="(item, i) in classifications" :key="i"
:class="{ active: form.productClassification === item.id }"
@click="filterChange(item.id, 'productClassification')">{{ item.classificationName }}</dd>
</div>
</dl>
<dl>
<dt>方案名称</dt>
<div class="vals">
<dd :class="{ active: form.websiteMallId === '' }" @click="filterChange('', 'websiteMallId')">全部</dd>
<dd v-for="(item, i) in schemes" :key="i" :class="{ active: form.websiteMallId === item.id }"
@click="filterChange(item.id, 'websiteMallId')">{{ item.title }}</dd>
<dd :class="{ active: form.classificationTagId === '' }" @click="filterChange('', 'classificationTagId')">
全部
</dd>
<dd v-for="(item, i) in labels" :key="i" :class="{ active: form.classificationTagId === item.categoryId }"
@click="filterChange(item.categoryId, 'classificationTagId')">{{ item.name }}</dd>
</div>
</dl>
</template>
<dl>
<dt>产品类型</dt>
<div class="vals">
<dd :class="{ active: form.productType === '' }" @click="filterChange('', 'productType')">全部</dd>
<dd v-for="(item, i) in types" :key="i" :class="{ active: form.productType === item.typeId }"
@click="filterChange(item.typeId, 'productType')">{{ item.typeName }}</dd>
<dd :class="{ active: form.categoryId === '' }" @click="filterChange('', 'categoryId')">全部</dd>
<dd v-for="(item, i) in types" :key="i" :class="{ active: form.categoryId === item.categoryId }"
@click="filterChange(item.categoryId, 'categoryId')">{{ item.name }}</dd>
</div>
</dl>
</div>
<div class="filter m-t-20">
<dl>
<dd v-for="(item, i) in sorts" :key="i" :class="{ active: form.sort === item.id }"
@click="filterChange(item.id, 'sort')">{{ item.name }}</dd>
<dd :class="{ active: form.sort === 2 || form.sort === 5 }" @click="sort">发布时间</dd>
<dd v-for="(item, i) in sorts" :key="i" :class="{ active: form.sortFiltering === item.id }"
@click="filterChange(item.id, 'sortFiltering')">{{ item.name }}</dd>
<dd :class="{ active: form.sortFiltering === 3 }" @click="sort">发布时间</dd>
<span class="caret" @click="sort">
<i :class="['asc', { active: form.sort === 2 }]"></i>
<i :class="['desc', { active: form.sort === 5 }]"></i>
<i :class="['asc', { active: form.timeOrdering === 'asc' }]"></i>
<i :class="['desc', { active: form.timeOrdering === 'desc' }]"></i>
</span>
</dl>
</div>
@ -140,14 +124,13 @@
<div class="courses">
<template v-if="list.length">
<ul>
<li v-for="(item, i) in list" :key="i" @click="toDetail(item.mallId)">
<img :src="item.coverDrawing" alt="" />
<img v-if="item.logoOfOurSchool" class="my-school" src="@/assets/images/my-school.png" alt="">
<li v-for="(item, i) in list" :key="i" @click="toDetail(item.id)">
<img :src="item.coverImageUrl" alt="" />
<div class="texts">
<el-tooltip effect="dark" :visible-arrow="false" :content="item.productName" placement="bottom">
<div class="title">{{ item.productName }}</div>
<el-tooltip effect="dark" :visible-arrow="false" :content="item.name" placement="bottom">
<div class="title">{{ item.name }}</div>
</el-tooltip>
<div class="desc" v-html="item.productIntroduction"></div>
<div class="desc" v-html="item.introduction"></div>
<div class="tags">
<el-tooltip v-if="item.tagsName" class="item" effect="dark" :visible-arrow="false"
:content="item.tagsName" placement="bottom">
@ -157,13 +140,10 @@
</el-tooltip>
</div>
<div :class="['metas']">
<el-tag v-if="item.selected" type="danger" effect="dark">
官方精选
</el-tag>
<el-tag v-if="item.typeName" effect="dark">
{{ item.typeName }}
</el-tag>
<div v-if="item.isCourse" class="meta">{{ item.learningCount }}人学</div>
<div v-if="item.isCourse" class="meta">{{ item.totalBrowsing }}人看</div>
</div>
</div>
</li>
@ -206,20 +186,16 @@ export default {
id: 3,
name: '热门标签'
},
{
id: 4,
name: '解决方案'
},
],
form: {
isShelves: 0,
hotTag: 1,
productType: '',
productName: '',
sort: 0,
tagId: '',
productClassification: '',
websiteMallId: ''
subjectCategoryId: '',
professionalCategoryId: '',
majorId: '',
classificationTagId: '',
keyWord: '',
sortFiltering: 1,
timeOrdering: '',
classificationTagId: '',
},
categoryId: '',
professionalCategoryId: '',
@ -229,7 +205,6 @@ export default {
professionals: [],
labels: [],
types: [],
classifications: [],
status: [
{
id: '',
@ -246,11 +221,11 @@ export default {
],
sorts: [
{
id: 0,
id: 1,
name: '综合排序'
},
{
id: 1,
id: 2,
name: '热销排行'
},
],
@ -265,7 +240,7 @@ export default {
};
},
watch: {
'form.productName': function (val) {
'form.keyWord': function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.initData();
@ -276,8 +251,6 @@ export default {
this.getBanner()
this.getSubject()
this.getLabel()
this.getClassification()
this.getSchemes()
this.getClass()
this.initData()
},
@ -366,25 +339,15 @@ export default {
//
getData () {
this.loadIns = Loading.service()
this.$post(this.api.websiteProductList, {
this.$post(this.api.courseProduct, {
...this.form,
siteId: this.site,
pageNum: this.page,
pageSize: this.pageSize,
categoryId: this.categoryId,
professionalCategoryId: this.categoryId ? this.professionalCategoryId : '',
professionalId: this.categoryId ? this.professionalId : '',
}).then(({ page }) => {
const list = page.records
list && list.forEach(e => {
//
const el = document.createElement('div')
el.innerHTML = e.productIntroduction
e.productIntroduction = el.innerText
const cid = e.classificationId
e.isCourse = (cid === 1 || cid === 2) && !e.isAssociatedProduct
})
this.list = list ? list : []
this.total = page.total
columnId: +this.id,
}).then(({ data }) => {
this.list = data.records
this.total = +data.total
this.loadIns.close()
}).catch(res => {
this.loadIns.close()
@ -401,53 +364,74 @@ export default {
},
//
getLabel () {
this.$get(this.api.tagsList).then(res => {
this.labels = res.tagsList
}).catch(err => { })
},
//
getClassification () {
this.$get(this.api.goodsSchemeClassification).then(({ data }) => {
this.classifications = data
}).catch(err => { })
},
//
getSchemes () {
this.$post(this.api.schemeList, {
pageNum: 1,
pageSize: 10000,
classificationId: this.form.productClassification,
querySource: 3, //(3. 4.)
}).then(({ data }) => {
this.schemes = data.records
}).catch(err => { })
async getLabel () {
const { data } = await this.$post(`${this.api.categoryList}?siteId=${this.site}&type=0`)
this.labels = data
},
//
async getSubject () {
//
this.$get(this.api.subjectCategoryCited).then(({ list }) => {
list = list.filter(e => e.disciplineId != 1)
list.map((e, i) => {
e.id = e.disciplineId
e.name = e.disciplineName
//
e.professionalClasses.map(e => {
e.id = e.professionalClassId
e.name = e.professionalClassName
//
e.professionals.map(e => {
e.id = e.professionalId
e.name = e.professionalName
})
e.children = e.professionals
const { data } = await this.$get(this.api.courseDiscipline)
this.category = data
},
//
subjectClick (item) {
this.form.subjectCategoryId = item.disciplineId
this.form.professionalCategoryId = ''
this.getProfessionalClassData(this.form)
this.initData()
},
//
async getProfessionalClassData (item) {
const { data } = await this.$get(this.api.courseProfessionalClass, {
disciplineId: item.subjectCategoryId
})
e.children = e.professionalClasses
this.professionalClasses = data
},
//
professionalClick (item) {
this.form.professionalCategoryId = item.professionalClassId
this.form.majorId = ''
this.getProfessionalData(this.form)
this.initData()
},
//
async getProfessionalData (item) {
const { data } = await this.$get(this.api.courseProfessional, {
professionalClassId: item.professionalCategoryId
})
this.category = list
}).catch(err => { })
this.professionals = data
},
//
majorClick (item) {
this.form.majorId = item.professionalId
this.initData()
},
//
// async getSubject () {
// //
// this.$get(this.api.subjectCategoryCited).then(({ list }) => {
// list = list.filter(e => e.disciplineId != 1)
// list.map((e, i) => {
// e.id = e.disciplineId
// e.name = e.disciplineName
// //
// e.professionalClasses.map(e => {
// e.id = e.professionalClassId
// e.name = e.professionalClassName
// //
// e.professionals.map(e => {
// e.id = e.professionalId
// e.name = e.professionalName
// })
// e.children = e.professionals
// })
// e.children = e.professionalClasses
// })
// this.category = list
// }).catch(err => { })
// },
//
categoryClick (item, i) {
const { id, children } = item
@ -465,38 +449,32 @@ export default {
this.initData()
},
//
getClass () {
this.$get(this.api.productTypeList).then(res => {
this.types = res.typeList
}).catch(err => { })
async getClass () {
const { data } = await this.$post(`${this.api.categoryList}?siteId=${this.site}&type=1`)
this.types = data
},
// tab
tabChange ({ id }) {
this.curTab = id
this.form.hotTag = 1
this.form.selection = ''
this.form.tagId = ''
this.form.productClassification = ''
this.form.websiteMallId = ''
if (id === 3) {
this.form.hotTag = 2
} else if (id === 2) {
this.form.classificationTagId = ''
if (id === 2) {
this.form.selection = 1
}
this.initData()
},
//
filterChange (id, prop) {
this.form[prop] = id
if (prop === 'productClassification') {
this.form.websiteMallId = ''
this.getSchemes()
if (prop !== 'sortFiltering') {
this.form.timeOrdering = ''
}
this.form[prop] = id
this.initData()
},
//
sort () {
this.form.sort = this.form.sort === 2 ? 5 : 2
this.form.sortFiltering = 3
this.form.timeOrdering = this.form.timeOrdering === 'asc' ? 'desc' : 'asc'
this.initData()
},
handleCurrentChange (val) {

@ -0,0 +1,819 @@
<template>
<div class="wrap">
<div class="inner">
<Breadcrumb ref="breadcrumb" :data.sync="routes" />
<div class="top">
<el-carousel class="pics fadeInLeft" :interval="6000" height="278px"
:arrow="form.pics.length > 1 ? 'hover' : 'never'" :indicator-position="form.pics.length > 1 ? '' : 'none'">
<el-carousel-item v-for="(item, i) in form.pics" :key="i">
<el-image class="pic" :src="item" :preview-src-list="form.pics">
</el-image>
</el-carousel-item>
</el-carousel>
<div class="right fadeInRight" id="fields">
<h6>{{ form.mall.productName }}</h6>
<div v-if="isCourse" class="meta">
<span class="val">{{ form.numberOfExperimentalItems }}</span> 个实验项目&emsp;&emsp;
已有 <span class="val">{{ form.goodsRes.learningCount }}</span>人学过
</div>
<div class="des" v-html="form.mall.productIntroduction"></div>
<div class="fields">
<div class="field">
<img src="@/assets/images/product/1.png" alt=""> 适用专业
<el-tooltip class="text" effect="dark" :visible-arrow="false" :content="form.goodsRes.professionalName"
placement="bottom">
<div>
{{ form.goodsRes.professionalName }}
</div>
</el-tooltip>
</div>
<div v-if="form.mall.applicationScenario" class="field">
<img src="@/assets/images/product/2.png" alt=""> 适用场景
<div class="text">{{ form.mall.applicationScenario }}</div>
</div>
<div v-if="form.mall.matchingCourse" class="field">
<img src="@/assets/images/product/3.png" alt=""> 匹配课程
<el-tooltip class="text" effect="dark" :visible-arrow="false" :content="form.mall.matchingCourse"
placement="bottom">
<div class="text">
{{ form.mall.matchingCourse }}
</div>
</el-tooltip>
</div>
<div v-if="form.mall.courseHours" class="field">
<img src="@/assets/images/product/4.png" alt=""> 预计课时
<div class="text">{{ form.mall.courseHours }}</div>
</div>
<div v-if="form.goodsRes.typeName" class="field">
<img src="@/assets/images/product/5.png" alt=""> 产品类型
<div class="text">{{ form.goodsRes.typeName }}</div>
</div>
</div>
<button v-if="!GTA" class="btn" @click="showQrcode">会员价采购</button>
</div>
</div>
<div class="course" id="part0">
<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">
<div class="des" v-html="form.mall.detailedIntroduction"></div>
<div class="chapter" id="part1" v-for="(item, i) in chapterList" :key="i">
<div class="chapterName">{{ item.name }}</div>
<div class="section" v-if="item.subsectionList.length">
<div v-for="(section, j) in item.subsectionList" :key="j">
<div class="sectionName" :title="section.name">
<div class="val">
<img v-if="section.fileType === 'pptx'" src="@/assets/images/exts/ppt.png" alt="">
<img v-else-if="section.fileType === 'mp4'" src="@/assets/images/exts/video.png" alt="">
<img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'"
src="@/assets/images/exts/word.png" alt="">
<img v-else-if="section.fileType === 'txt'" src="@/assets/images/exts/txt.png" alt="">
<img v-else-if="section.fileType === 'pdf'" src="@/assets/images/exts/pdf.png" alt="">
<img v-else src="@/assets/images/exts/pic.png" alt="">
{{ section.name }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="products">
<h6 class="fadeInUp">热门产品推荐</h6>
<ul class="product fadeInDown">
<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/images/my-school.png" alt="">
<div class="texts">
<div class="title">{{ item.productName }}</div>
<div :class="['desc', { 'not-tag': !item.tagsName }]" v-html="item.productIntroduction"></div>
<div v-if="item.tagsName" class="tags">
<el-tag v-for="(tag, i) in item.tagsName.split(',')" :key="i" class="tag">{{ tag }}</el-tag>
</div>
<div class="metas">
<el-tag v-if="item.selected" type="danger" effect="dark">
官方精选
</el-tag>
<div v-if="item.isCourse" class="meta">{{ item.learningCount }}人学过</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
<!-- 选择链接 -->
<el-dialog title="请选择链接" :visible.sync="linkVisible" width="420px" center :close-on-click-modal="false">
<div v-if="withLink" class="buy">
<div v-for="(link, i) in form.mallNonAssociatedLinks" :key="i" class="link-line">
{{ link.urlName }}
<a class="url" :href="link.url" target="_blank">{{ link.url }}</a>
</div>
</div>
</el-dialog>
<el-dialog title="" :visible.sync="qrcodeVisible" width="500px" center :top="qrcodeTop" custom-class="qrcode-dia">
<div>
<img width="100%" src="@/assets/images/occupationlab.png" alt="">
</div>
</el-dialog>
</div>
</template>
<script>
import Util from "@/libs/util"
import Setting from "@/setting"
import Breadcrumb from '@/components/breadcrumb'
import ScrollReveal from 'scrollreveal'
export default {
data () {
return {
id: this.$route.query.id,
routes: {},
curTab: 0,
tabs: [
{
id: 0,
name: '详情介绍'
},
],
form: {
pics: [],
classificationIds: [],
mall: {
coverDrawing: ''
},
goodsRes: {}
},
chapterList: [],
hots: [],
linkVisible: false,
height: '',
qrcodeVisible: false,
qrcodeTop: '100px'
};
},
components: {
Breadcrumb,
},
computed: {
//
withLink () {
const links = this.form.mallNonAssociatedLinks
const id = this.form.classificationIds
return (this.form.mall.isAssociatedProduct || (id && id[0] == 5)) && links && links.length
},
//
isCourse () {
let id = this.form.classificationIds
if (id) {
id = id[0]
const isCourse = (id == 1 || id == 2) && this.form.mall.isAssociatedProduct === 0
this.tabs = [
{
id: 0,
name: '详情介绍'
},
]
isCourse && this.tabs.push({
id: 1,
name: '课程目录'
})
return isCourse
}
return false
},
//
isValueModule () {
let id = this.form.classificationIds
if (id) return id[0] == 3
return false
},
//
isDataforward () {
let id = this.form.classificationIds
if (id) return id[0] == 5
return false
},
},
mounted () {
const height = (window.innerHeight - 758) / 2
this.qrcodeTop = (height > 0 ? height : 0) + 'px'
this.getData()
this.getHot()
},
methods: {
//
getData () {
this.$get(`${this.api.detailsOfGoods}?mallId=${this.id}`).then(res => {
const e = res.orderDetails
e.pics = [e.mall.coverDrawing]
if (e.mall.interfaceDiagram) {
const pics = e.mall.interfaceDiagram.split(',').slice(0, 3)
e.pics.push(...pics)
e.interfaceDiagrams = pics
}
this.form = e
this.routes = [
{
name: '职站商城',
path: '/index',
query: {
id: 13,
siteId: 1
}
},
{
name: e.mall.productName
}
]
this.chapterList = ''
e.mall.associatedProduct && this.getChapter()
this.$nextTick(() => {
this.height = document.querySelector('#fields').clientHeight + 'px'
this.initAnimate()
})
}).catch(err => { })
},
//
async getChapter () {
let res = await this.$get(this.api.curriculumChapter + '/' + this.form.mall.associatedProduct)
this.chapterList = res.chapterList
},
//
initAnimate () {
const sr = ScrollReveal()
sr.reveal('.animate', {
reset: true, // true, n
// origin: 'bottom', //
distance: '50px',//
duration: 1000, //
scale: 0.8,
// viewFactor: 100,
})
sr.reveal('.fadeInUp', {
reset: true, // true, n
origin: 'top', //
distance: '100px',//
duration: 1000, //
// scale: 0.8,
// viewFactor: 100,
})
sr.reveal('.fadeInDown', {
reset: true, // true, n
origin: 'bottom', //
distance: '100px',//
duration: 1000, //
// scale: 0.8,
// viewFactor: 100,
})
ScrollReveal().reveal('.fadeInDown0', {
reset: true, // true, n
origin: 'bottom', //
distance: '150px',//
duration: 1000, //
// scale: 0.8,
// viewFactor: 100,
})
ScrollReveal().reveal('.fadeInDown1', {
reset: true, // true, n
origin: 'bottom', //
distance: '150px',//
duration: 1000, //
delay: 100,
// scale: 0.8,
// viewFactor: 100,
})
ScrollReveal().reveal('.fadeInDown2', {
reset: true, // true, n
origin: 'bottom', //
distance: '150px',//
duration: 1000, //
delay: 200,
// scale: 0.8,
// viewFactor: 100,
})
sr.reveal('.fadeInLeft', {
reset: true, // true, n
origin: this.$store.getters.getModelType ? 'left' : 'top', //
distance: '100px',//
duration: 1000, //
// scale: 0.8,
// viewFactor: 100,
})
sr.reveal('.fadeInRight', {
reset: true, // true, n
origin: this.$store.getters.getModelType ? 'right' : 'bottom', //
distance: '100px',//
duration: 1000, //
// scale: 0.8,
// viewFactor: 100,
})
},
// tab
tabChange ({ id }) {
this.curTab = id
document.querySelector(`#part${id}`).scrollIntoView({
behavior: 'smooth'
})
},
//
toPreview (i, j) {
this.qrcodeVisible = true
// this.form.goodsRes.logoOfOurSchool ?
// this.$router.push(`/station/preview?courseId=${this.form.mall.associatedProduct}&curriculumName=${this.form.mall.productName}&mallId=${this.id}&chapter=${i}&section=${j}&admin=1`) :
// this.toTrail()
},
// /
studySection (item) {
item.whetherToStudyOrNot ?
this.$post(`${this.api.deleteLearningProgress}?id=${item.learningProgressId}`).then(res => {
this.getChapter()
}).catch(res => { }) :
this.$post(this.api.saveLearningProgress, {
cid: this.form.mall.associatedProduct,
projectId: item.projectId,
}).then(res => {
this.getChapter()
}).catch(res => { })
},
//
showQrcode () {
this.qrcodeVisible = true
},
//
toStation () {
if (this.isCourse) { //
this.$post(`${this.api.addLearningRecord}?mallId=${this.id}`).then(res => {
this.$router.push('/station/preview?courseId=' + this.form.mall.associatedProduct + '&curriculumName=' + this.form.mall.productName + '&mallId=' + this.id)
}).catch(res => { })
} else if (this.withLink) { //
this.linkVisible = true
}
},
//
toSystem () {
this.$router.push(`/match`)
},
//
getHot () {
this.$post(this.api.websiteProductList, {
hotTag: 1,
sort: 1,
pageNum: 1,
pageSize: 2,
}).then(({ page }) => {
const list = page.records
list.forEach(e => {
//
const el = document.createElement('div')
el.innerHTML = e.productIntroduction
e.productIntroduction = el.innerText
const cid = e.classificationId
e.isCourse = (cid === 1 || cid === 2) && !e.isAssociatedProduct
})
this.hots = list
}).catch(res => { })
},
//
toDetail (id) {
this.$router.push(`/index/show?id=${id}`)
this.id = id
this.getData()
},
}
};
</script>
<style lang="scss" scoped>
.wrap {
padding: 24px;
background: url(../../../assets/images/product/bg1.png) 0 373px no-repeat,
url(../../../assets/images/product/bg2.png) bottom right no-repeat;
background-color: #f3f6fa;
.inner {
width: 1146px;
margin: 0 auto;
}
.top {
display: flex;
padding: 24px;
background-color: #fff;
border-radius: 10px;
.pics {
width: 484px;
margin-right: 20px;
.pic {
width: 100%;
height: 100%;
border-radius: 8px;
}
}
.right {
width: 592px;
overflow: hidden;
}
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;
@include mul-ellipsis(3);
}
.field {
display: inline-flex;
align-items: center;
margin: 0 20px 10px 0;
font-size: 14px;
color: #2e2d31;
&:last-child {
margin-right: 0;
}
.label {
color: #333;
}
.text {
max-width: 160px;
@include ellipsis;
}
img {
margin-right: 5px;
}
}
.fields {
display: flex;
// justify-content: space-between;
flex-wrap: wrap;
height: 60px;
margin: 10px 0 10px;
overflow: hidden;
}
.btn {
width: 119px;
height: 46px;
color: #fff;
background: #007eff;
border-radius: 6px;
border: 0;
cursor: pointer;
&:hover {
opacity: 0.9;
}
&:first-child {
margin-left: 11px;
}
}
}
.tab {
z-index: 100;
position: sticky;
top: 90px;
display: flex;
padding: 10px 10px 20px;
background-color: #fff;
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: calc(100% - 294px);
padding: 20px 24px;
background-color: #fff;
border-radius: 10px;
}
}
.courses {
padding-top: 10px;
overflow: hidden;
/deep/.des {
div,
p,
span {
font-family: PingFangSC-Regular !important;
}
img {
max-width: 100%;
object-fit: cover;
}
}
.chapters {
margin-top: 16px;
max-height: calc(100% - 53px);
overflow: auto;
}
.chapter {
padding-top: 60px;
margin-bottom: 20px;
}
.chapterName {
padding: 0 12px;
margin-bottom: 15px;
color: #333;
font-size: 14px;
}
.sectionName {
position: relative;
display: flex;
justify-content: space-between;
padding: 12px;
font-size: 14px;
color: #666;
border-radius: 8px;
@include ellipsis;
img {
margin-right: 8px;
}
&:hover {
color: #007eff;
background: #f6fbff;
}
.val {
display: inline-flex;
align-items: center;
}
.icon {
font-size: 18px;
color: #666;
}
}
}
.products {
width: 270px;
margin-left: 24px;
&>h6 {
font-size: 16px;
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: 0.3s;
object-fit: cover;
}
.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;
&.not-tag {
-webkit-line-clamp: 3;
}
}
.tags {
margin-top: 10px;
}
.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);
}
}
}
}
}
.link-line {
margin: 5px 0;
.url {
color: #007eff;
text-decoration: underline;
}
}
.buy {
text-align: center;
.tips {
margin-bottom: 10px;
font-size: 14px;
}
img {
width: 85%;
}
}
/deep/.qrcode-dia {
.el-dialog__header,
.el-dialog__body {
padding: 0;
}
.el-dialog__headerbtn .el-dialog__close {
color: #fff;
}
}
@media (max-width: 1200px) {
.wrap {
.inner {
width: 100%;
}
.top {
flex-direction: column;
.pics {
width: 100%;
margin-bottom: 20px;
}
.el-image__preview {
object-fit: cover;
}
.right {
width: 100%;
}
}
.course {
flex-direction: column;
.detail {
width: 100%;
margin-bottom: 20px;
}
.products {
width: 100%;
margin-left: 0;
}
}
}
}
@media (max-width: 480px) {
.wrap {
.tab {
position: static;
}
}
}
</style>

@ -3,53 +3,46 @@
<div class="inner">
<Breadcrumb ref="breadcrumb" :data.sync="routes" />
<div class="top">
<el-carousel class="pics fadeInLeft" :interval="6000" height="278px"
:arrow="form.pics.length > 1 ? 'hover' : 'never'" :indicator-position="form.pics.length > 1 ? '' : 'none'">
<el-carousel-item v-for="(item, i) in form.pics" :key="i">
<el-image class="pic" :src="item" :preview-src-list="form.pics">
</el-image>
</el-carousel-item>
</el-carousel>
<el-image class="pic" :src="form.coverImageUrl" :preview-src-list="[form.coverImageUrl]" />
<div class="right fadeInRight" id="fields">
<h6>{{ form.mall.productName }}</h6>
<div v-if="isCourse" class="meta">
<span class="val">{{ form.numberOfExperimentalItems }}</span> 个实验项目&emsp;&emsp;
已有 <span class="val">{{ form.goodsRes.learningCount }}</span>人学过
<h6>{{ form.name }}</h6>
<div class="meta">
已有 <span class="val">{{ form.totalBrowsing }}</span>人看过
</div>
<div class="des" v-html="form.mall.productIntroduction"></div>
<div class="des" v-html="form.introduction"></div>
<div class="fields">
<div class="field">
<img src="@/assets/images/product/1.png" alt=""> 适用专业
<el-tooltip class="text" effect="dark" :visible-arrow="false" :content="form.goodsRes.professionalName"
<el-tooltip class="text" effect="dark" :visible-arrow="false" :content="form.professionalName"
placement="bottom">
<div>
{{ form.goodsRes.professionalName }}
{{ form.professionalName }}
</div>
</el-tooltip>
</div>
<div v-if="form.mall.applicationScenario" class="field">
<div v-if="form.applicationScenario" class="field">
<img src="@/assets/images/product/2.png" alt=""> 适用场景
<div class="text">{{ form.mall.applicationScenario }}</div>
<div class="text">{{ form.applicationScenario }}</div>
</div>
<div v-if="form.mall.matchingCourse" class="field">
<div v-if="form.matchingCourse" class="field">
<img src="@/assets/images/product/3.png" alt=""> 匹配课程
<el-tooltip class="text" effect="dark" :visible-arrow="false" :content="form.mall.matchingCourse"
<el-tooltip class="text" effect="dark" :visible-arrow="false" :content="form.matchingCourse"
placement="bottom">
<div class="text">
{{ form.mall.matchingCourse }}
{{ form.matchingCourse }}
</div>
</el-tooltip>
</div>
<div v-if="form.mall.courseHours" class="field">
<div v-if="form.courseHours" class="field">
<img src="@/assets/images/product/4.png" alt=""> 预计课时
<div class="text">{{ form.mall.courseHours }}</div>
<div class="text">{{ form.courseHours }}</div>
</div>
<div v-if="form.goodsRes.typeName" class="field">
<div v-if="form.typeName" class="field">
<img src="@/assets/images/product/5.png" alt=""> 产品类型
<div class="text">{{ form.goodsRes.typeName }}</div>
<div class="text">{{ form.typeName }}</div>
</div>
</div>
<button v-if="!GTA" class="btn" @click="showQrcode">会员价采购</button>
<button v-if="form.jumpButtonName" class="btn" @click="toLink">{{ form.jumpButtonName }}</button>
</div>
</div>
<div class="course" id="part0">
@ -59,45 +52,22 @@
tab.name }}</li>
</ul>
<div class="courses">
<div class="des" v-html="form.mall.detailedIntroduction"></div>
<div class="chapter" id="part1" v-for="(item, i) in chapterList" :key="i">
<div class="chapterName">{{ item.name }}</div>
<div class="section" v-if="item.subsectionList.length">
<div v-for="(section, j) in item.subsectionList" :key="j">
<div class="sectionName" :title="section.name">
<div class="val">
<img v-if="section.fileType === 'pptx'" src="@/assets/images/exts/ppt.png" alt="">
<img v-else-if="section.fileType === 'mp4'" src="@/assets/images/exts/video.png" alt="">
<img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'"
src="@/assets/images/exts/word.png" alt="">
<img v-else-if="section.fileType === 'txt'" src="@/assets/images/exts/txt.png" alt="">
<img v-else-if="section.fileType === 'pdf'" src="@/assets/images/exts/pdf.png" alt="">
<img v-else src="@/assets/images/exts/pic.png" alt="">
{{ section.name }}
</div>
</div>
</div>
</div>
</div>
<div class="des" v-html="form.detailedDescription"></div>
</div>
</div>
<div class="products">
<h6 class="fadeInUp">热门产品推荐</h6>
<ul class="product fadeInDown">
<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/images/my-school.png" alt="">
<img :src="item.coverImageUrl" alt="" />
<div class="texts">
<div class="title">{{ item.productName }}</div>
<div class="title">{{ item.name }}</div>
<div :class="['desc', { 'not-tag': !item.tagsName }]" v-html="item.productIntroduction"></div>
<div v-if="item.tagsName" class="tags">
<el-tag v-for="(tag, i) in item.tagsName.split(',')" :key="i" class="tag">{{ tag }}</el-tag>
</div>
<div class="metas">
<el-tag v-if="item.selected" type="danger" effect="dark">
官方精选
</el-tag>
<div v-if="item.isCourse" class="meta">{{ item.learningCount }}人学过</div>
<div class="meta">{{ item.learningCount }}人看过</div>
</div>
</div>
</li>
@ -106,16 +76,6 @@
</div>
</div>
<!-- 选择链接 -->
<el-dialog title="请选择链接" :visible.sync="linkVisible" width="420px" center :close-on-click-modal="false">
<div v-if="withLink" class="buy">
<div v-for="(link, i) in form.mallNonAssociatedLinks" :key="i" class="link-line">
{{ link.urlName }}
<a class="url" :href="link.url" target="_blank">{{ link.url }}</a>
</div>
</div>
</el-dialog>
<el-dialog title="" :visible.sync="qrcodeVisible" width="500px" center :top="qrcodeTop" custom-class="qrcode-dia">
<div>
<img width="100%" src="@/assets/images/occupationlab.png" alt="">
@ -149,9 +109,7 @@ export default {
},
goodsRes: {}
},
chapterList: [],
hots: [],
linkVisible: false,
height: '',
qrcodeVisible: false,
qrcodeTop: '100px'
@ -160,46 +118,6 @@ export default {
components: {
Breadcrumb,
},
computed: {
//
withLink () {
const links = this.form.mallNonAssociatedLinks
const id = this.form.classificationIds
return (this.form.mall.isAssociatedProduct || (id && id[0] == 5)) && links && links.length
},
//
isCourse () {
let id = this.form.classificationIds
if (id) {
id = id[0]
const isCourse = (id == 1 || id == 2) && this.form.mall.isAssociatedProduct === 0
this.tabs = [
{
id: 0,
name: '详情介绍'
},
]
isCourse && this.tabs.push({
id: 1,
name: '课程目录'
})
return isCourse
}
return false
},
//
isValueModule () {
let id = this.form.classificationIds
if (id) return id[0] == 3
return false
},
//
isDataforward () {
let id = this.form.classificationIds
if (id) return id[0] == 5
return false
},
},
mounted () {
const height = (window.innerHeight - 758) / 2
this.qrcodeTop = (height > 0 ? height : 0) + 'px'
@ -208,41 +126,9 @@ export default {
},
methods: {
//
getData () {
this.$get(`${this.api.detailsOfGoods}?mallId=${this.id}`).then(res => {
const e = res.orderDetails
e.pics = [e.mall.coverDrawing]
if (e.mall.interfaceDiagram) {
const pics = e.mall.interfaceDiagram.split(',').slice(0, 3)
e.pics.push(...pics)
e.interfaceDiagrams = pics
}
this.form = e
this.routes = [
{
name: '职站商城',
path: '/index',
query: {
id: 13,
siteId: 1
}
},
{
name: e.mall.productName
}
]
this.chapterList = ''
e.mall.associatedProduct && this.getChapter()
this.$nextTick(() => {
this.height = document.querySelector('#fields').clientHeight + 'px'
this.initAnimate()
})
}).catch(err => { })
},
//
async getChapter () {
let res = await this.$get(this.api.curriculumChapter + '/' + this.form.mall.associatedProduct)
this.chapterList = res.chapterList
async getData () {
const { data } = await this.$post(`${this.api.productDetailsFind}?id=${this.id}`)
this.form = data
},
//
initAnimate () {
@ -329,63 +215,18 @@ export default {
behavior: 'smooth'
})
},
//
toPreview (i, j) {
this.qrcodeVisible = true
// this.form.goodsRes.logoOfOurSchool ?
// this.$router.push(`/station/preview?courseId=${this.form.mall.associatedProduct}&curriculumName=${this.form.mall.productName}&mallId=${this.id}&chapter=${i}&section=${j}&admin=1`) :
// this.toTrail()
},
// /
studySection (item) {
item.whetherToStudyOrNot ?
this.$post(`${this.api.deleteLearningProgress}?id=${item.learningProgressId}`).then(res => {
this.getChapter()
}).catch(res => { }) :
this.$post(this.api.saveLearningProgress, {
cid: this.form.mall.associatedProduct,
projectId: item.projectId,
}).then(res => {
this.getChapter()
}).catch(res => { })
},
//
showQrcode () {
this.qrcodeVisible = true
},
//
toStation () {
if (this.isCourse) { //
this.$post(`${this.api.addLearningRecord}?mallId=${this.id}`).then(res => {
this.$router.push('/station/preview?courseId=' + this.form.mall.associatedProduct + '&curriculumName=' + this.form.mall.productName + '&mallId=' + this.id)
}).catch(res => { })
} else if (this.withLink) { //
this.linkVisible = true
}
},
//
toSystem () {
this.$router.push(`/match`)
//
toLink () {
window.open(this.form.jumpLinkUrl)
},
//
getHot () {
this.$post(this.api.websiteProductList, {
hotTag: 1,
sort: 1,
async getHot () {
const { data } = await this.$post(this.api.courseProduct, {
pageNum: 1,
pageSize: 2,
}).then(({ page }) => {
const list = page.records
list.forEach(e => {
//
const el = document.createElement('div')
el.innerHTML = e.productIntroduction
e.productIntroduction = el.innerText
const cid = e.classificationId
e.isCourse = (cid === 1 || cid === 2) && !e.isAssociatedProduct
columnId: +this.id,
})
this.hots = list
}).catch(res => { })
this.hots = data.records
},
//
toDetail (id) {
@ -415,14 +256,12 @@ export default {
background-color: #fff;
border-radius: 10px;
.pics {
.pic {
width: 484px;
margin-right: 20px;
.pic {
width: 100%;
height: 100%;
border-radius: 8px;
/deep/.el-image__inner {
object-fit: cover;
}
}

@ -18,7 +18,7 @@ const Setting = {
titleSuffix: '深圳或然科技官网', // 网页标题的后缀
routerMode: "hash", // 路由模式,可选值为 history 或 hash
apiBaseURL: host, // 接口请求地址
huoranApi: `https://occupationlab.com`,
huoranApi: `http://121.37.12.51`,
autoLogoutTime: 3600000, // 长时间未操作,自动退出登录时间
modalDuration: 3, // 接口请求返回错误时,弹窗的持续时间,单位:秒
errorModalType: "Message", // 接口请求返回错误时,弹窗的类型,可选值为 Message 或 Notice

Loading…
Cancel
Save