Commit 1f5686d1 by zhengxiao

feat(custom): 课程小程序首页更改

parent 615421ac
......@@ -5,7 +5,12 @@
<text class="title">{{ title }}</text>
<text class="desc">{{ subtitle }}</text>
</view>
<view class="study-count">{{ studyCount }}万人已学习</view>
<view
v-if="formattedStudyCount"
class="study-count"
>
{{ formattedStudyCount }}人已学习
</view>
</view>
<view class="course-list">
......@@ -13,17 +18,18 @@
v-for="(item, index) in showCourseList"
:key="index"
class="course-item"
@tap="handleCourseClick(item)"
>
<image
class="course-img"
:src="item.image || '/static/images/course-placeholder.png'"
:src="item.homeCover"
mode="aspectFill"
/>
<view class="course-info">
<view class="course-title">{{ item.title }}</view>
<view class="course-desc">{{ item.desc }}</view>
<view class="course-desc">{{ item.subTitle }}</view>
<view class="course-meta">
<text class="enroll-count">{{ item.enrollCount }}人已报名</text>
<text class="enroll-count">{{ item.applyNum }}人已报名</text>
<button class="study-btn">去学习</button>
</view>
</view>
......@@ -36,12 +42,16 @@
@tap="toggleShowMore"
>
<text>{{ isExpanded ? '收起' : '展开更多' }}</text>
<text :class="['arrow', isExpanded ? 'up' : '']"></text>
<image
:class="isExpanded ? 'arrow up' : 'arrow'"
src="https://static.ydlcdn.com/miniapp/ydl-group-course/arrow.png"
/>
</view>
</view>
</template>
<script>
import { hostPrefix } from '@/config'
export default {
name: 'CourseBlock',
props: {
......@@ -71,8 +81,26 @@ export default {
showCourseList() {
return this.isExpanded ? this.courseList : this.courseList.slice(0, 2)
},
formattedStudyCount() {
const count = this.studyCount
if (count >= 10000) {
let formatted = (count / 10000).toFixed(1)
formatted = formatted.replace(/\.0$/, '')
return `${formatted}万`
} else {
return count
}
},
},
methods: {
handleCourseClick(item) {
// console.log(item)/h5-course/detail/
uni.navigateTo({
url: `/pages/web/web?title=${encodeURIComponent(item.title)}&loadUrl=${encodeURIComponent(
`${hostPrefix}/h5-course/detail/${item.id}`,
)}`,
})
},
toggleShowMore() {
this.isExpanded = !this.isExpanded
},
......@@ -85,7 +113,7 @@ export default {
margin: 12px;
padding: 12px 10px;
background: #fff;
border-radius: 16px;
border-radius: 12px;
.block-header {
display: flex;
......@@ -138,12 +166,16 @@ export default {
margin-right: 8px;
border-radius: 4px;
background-color: #d8d8d8;
flex-shrink: 0;
}
.course-info {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.course-title {
color: #000000;
......@@ -154,6 +186,7 @@ export default {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 0;
}
.course-desc {
......@@ -201,14 +234,19 @@ export default {
}
.show-more {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding-top: 20rpx;
font-size: 26rpx;
color: #999;
padding-top: 20px;
color: #999999;
font-weight: 400;
font-size: 12px;
.arrow {
margin-left: 8rpx;
font-size: 20rpx;
width: 8px;
height: 8px;
margin-left: 8px;
display: inline-block;
transition: transform 0.3s ease;
......
......@@ -56,7 +56,7 @@
},
"tabBar": {
"color": "#76787C",
"selectedColor": "#55B5F3",
"selectedColor": "#0092FF",
"iconWidth": "24px",
"spacing": "9px",
"list": [
......
......@@ -5,8 +5,21 @@
<!-- 使用计算后的总导航栏高度 -->
<view
class="status-bar"
:style="{ height: totalNavHeight + 'px' }"
:style="{ height: statusBarHeight + 'px' }"
></view>
<view
class="slogen"
:style="{ height: navBarHeight + 'px' }"
>
<img
class="slogen_img"
src="https://static.ydlcdn.com/miniapp/ydl-group-course/slogen.png"
/>
</view>
<view class="tip">
<text class="tip-blue">3万+心理从业者</text>
<text>选择的学习成长平台</text>
</view>
<view class="search-tags">
<text class="tag">体系化专业课程</text>
<text class="tag">·</text>
......@@ -14,55 +27,41 @@
<text class="tag">·</text>
<text class="tag">平台服务保障</text>
</view>
</view>
<!-- 导航菜单 -->
<view class="nav-menu">
<view class="nav-item">
<view class="nav-icon dark"></view>
<text>新手入门</text>
</view>
<view class="nav-item">
<view class="nav-icon dark"></view>
<text>实操进阶</text>
</view>
<view class="nav-item">
<view class="nav-icon dark"></view>
<text>咨询流派</text>
</view>
<view class="nav-item">
<view class="nav-icon dark"></view>
<text>公开课</text>
</view>
<view class="nav-item">
<view class="nav-icon dark"></view>
<text>全部课程</text>
</view>
</view>
<!-- 会员提示区 -->
<view class="vip-tips">
<view class="left-content">
<view class="tag-wrapper">
<image
class="tag-bg"
src="/static/images/tag-bg.png"
mode="aspectFit"
/>
<text class="tag-text">免费资料</text>
</view>
<view class="text-content">
<text class="main-text">100G 资料包已送达...</text>
<text class="sub-text">AI实战进阶超全资料包免费领取</text>
<!-- 导航菜单 -->
<view class="nav-menu">
<view
v-for="(item, index) in navData"
:key="index"
class="nav-item"
@tap="jumpTo(item.linkUrl, item.name)"
>
<view class="nav-icon">
<img
:src="item.icon"
mode="aspectFit"
/>
</view>
<text>{{ item.name }}</text>
</view>
</view>
<view class="right-action">
<text class="action-text">去领福利</text>
<!-- 会员提示区 -->
<view class="vip-tips">
<img
class="vip-tips-img"
:src="clueData.img"
mode="widthFix"
@tap="jumpTo(clueData.url)"
/>
</view>
</view>
<!-- 执业入驻区域 -->
<view class="career-section">
<view
v-if="careerData.isShow"
class="career-section"
>
<view class="section-header">
<view class="title-wrapper">
<text class="title">执业入驻</text>
......@@ -73,12 +72,12 @@
<view class="career-tabs">
<view class="tab-items">
<view
v-for="(tab, index) in tabs"
:key="index"
v-for="(tab, index) in careerData.cardList"
:key="tab.id"
:class="['tab-item', currentTab === index ? 'active' : '']"
@tap="switchTab(index)"
@click="switchTab(index)"
>
{{ tab }}
{{ tab.name }}
</view>
</view>
<view
......@@ -88,83 +87,54 @@
</view>
<!-- 内容区域 -->
<swiper
<view
v-if="careerData.isShow"
class="content-swiper"
:current="currentTab"
:autoplay="true"
:autoplay="autoPlayConfig"
:style="{ height: `${imgHeights[currentTab]}px` }"
@change="handleSwiperChange"
>
<swiper-item
v-for="(tab, index) in tabs"
:key="index"
<view
v-for="(tab, index) in careerData.cardList"
:key="tab.id"
>
<view class="consultant-card">
<!-- <view class="card-title">心理咨询师一对一从业规划</view>
<view class="card-subtitle">专业老师1v1教你入行</view>
<view class="card-features">
<view class="feature-item">
<image
src="/static/icons/doc.png"
mode="aspectFit"
/>
<text>入行资料</text>
</view>
<view class="feature-item">
<image
src="/static/icons/group.png"
mode="aspectFit"
/>
<text>社群加餐</text>
</view>
<view class="feature-item">
<image
src="/static/icons/guide.png"
mode="aspectFit"
/>
<text>学习指导</text>
</view>
<view class="feature-item">
<image
src="/static/icons/plan.png"
mode="aspectFit"
/>
<text>职业规划</text>
</view>
</view> -->
<view
v-show="currentTab === index"
class="consultant-card"
:style="{ height: `${imgHeights[currentTab]}px`, overflow: 'hidden' }"
@tap="jumpTo(tab.url)"
>
<img
class="card-img"
:src="tab.cardImg"
mode="widthFix"
@load="handleImgLoad($event, index)"
/>
<view class="card-footer">
<text class="footer-text">壹点灵成长规划师,1V1教你入行</text>
<text class="footer-text">{{ tab.cardDesc }}</text>
<button class="consult-btn">立即咨询</button>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
</view>
<!-- 课程列表区域 -->
<view class="course-section">
<!-- 权威证书 -->
<course-block
title="权威证书"
subtitle="收获成功道路的通行证"
:study-count="2.1"
:course-list="certificateList"
></course-block>
<!-- 咨询伦理系列 -->
<course-block
title="咨询伦理系列"
subtitle="专业伦理规范指导"
:study-count="1.8"
:course-list="ethicsList"
></course-block>
<!-- 认知行为系列 -->
<course-block
title="认知行为系列"
subtitle="CBT理论与实操"
:study-count="1.8"
:course-list="cbtList"
></course-block>
<view
v-for="(item, index) in channelList"
:key="index"
>
<course-block
v-if="item.list.length > 0"
:title="item.name"
:subtitle="item.intro"
:study-count="item.applyNum"
:course-list="item.list"
></course-block>
</view>
</view>
</view>
</template>
......@@ -187,50 +157,37 @@ export default {
navBarHeight: 0,
totalNavHeight: 0,
currentTab: 0,
tabs: ['入行分析', '成为咨询师', '咨询师进阶'],
certificateList: [
{
title: '社会心理服务中级·人社部能建中心',
desc: '解开关系中的结,告别恨、消耗...',
enrollCount: 3240,
image: '/static/images/course-placeholder.png',
},
{
title: '社会心理服务中级·人社部能建中心',
desc: '解开关系中的结,告别恨、消耗...',
enrollCount: 3240,
image: '/static/images/course-placeholder.png',
},
{
title: '社会心理服务中级·人社部能建中心',
desc: '解开关系中的结,告别恨、消耗...',
enrollCount: 3240,
image: '/static/images/course-placeholder.png',
},
// ... 其他证书课程
],
ethicsList: [
{
title: '咨询伦理基础课程',
desc: '建立专业伦理意识,提升职业素养...',
enrollCount: 2156,
image: '/static/images/course-placeholder.png',
},
// ... 其他伦理课程
],
cbtList: [
{
title: 'CBT理论基础与应用',
desc: '认知行为疗法的核心理论与技术...',
enrollCount: 1892,
image: '/static/images/course-placeholder.png',
},
// ... 其他CBT课程
],
careerData: {},
navData: [],
studyCountList: [],
channelList: [],
clueData: {},
autoPlayConfig: {
delay: 3000,
disableOnInteraction: false,
},
imgHeights: {},
timer: null, // 新增定时器实例
}
},
// 分享给朋友
onShareAppMessage() {
return {
title: `壹点灵心理学课程`,
path: `/pages/home/home`,
}
},
mounted() {
// this.startAutoPlay()
},
beforeDestroy() {
// this.clearAutoPlay()
},
onLoad() {
this.getCourseList()
this.getNavData()
this.getCareerData()
this.getStudyCount()
this.initChannels()
// 获取系统信息和胶囊按钮位置信息
const systemInfo = uni.getSystemInfoSync()
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
......@@ -245,17 +202,143 @@ export default {
this.totalNavHeight = this.statusBarHeight + this.navBarHeight
},
methods: {
async initChannels() {
try {
const certificateChannelsList = await this.getRelatedChannels(29)
const ethicsChannelsList = await this.getRelatedChannels(30)
const cbtChannelsList = await this.getRelatedChannels(31)
// 权威证书系列频道
const certificateChannelsSourceData = {
...certificateChannelsList,
...this.filterStudyCountList(29),
}
// 咨询伦理系列频道
const ethicsChannelsSourceData = {
...ethicsChannelsList,
...this.filterStudyCountList(30),
}
// 认知行为系列频道
const cbtChannelsSourceData = {
...cbtChannelsList,
...this.filterStudyCountList(31),
}
this.channelList = [
certificateChannelsSourceData,
ethicsChannelsSourceData,
cbtChannelsSourceData,
]
console.log('🚀 ~ initChannels ~ this.channelList:', this.channelList)
} catch (error) {
console.log('initChannels', error)
}
},
// 获取频道学习人数列表
filterStudyCountList(channelId) {
return this.studyCountList.find(item => item.id === channelId)
},
jumpTo(url, title = '') {
uni.navigateTo({
url: `/pages/web/web?title=${title}&loadUrl=${encodeURIComponent(url)}`,
})
},
// 获取已学的统计人数
getStudyCount() {
console.log('getStudyCount')
// /course/v1/courses/study_count
this.$request
.post('/course/v1/channels/query', {
clientType: 6,
})
.then(res => {
console.log('getStudyCount', res)
this.studyCountList = res
})
},
// 获取相关频道数据
getRelatedChannels(channelsId) {
console.log('getRelatedChannels')
// /course/v1/courses/related_channels
return this.$request.post('course/v1/channels/courses/query', {
clientType: 6,
pageNo: 1,
channelsId,
pageSize: 9999,
})
},
// 获取导航区域数据
getNavData() {
console.log('getNavData')
// /course/v1/courses/nav_menu
this.$request.get('/course/v1/courses/home/config?clientType=6').then(res => {
console.log('🚀 ~ getNavData ~ res:', res)
const { homeGuideList, homeClue } = res
this.navData = homeGuideList
this.clueData = homeClue
})
},
// 获取执业内容
getCareerData() {
console.log('getCareerData')
// /course/v1/courses/learn_growth_card
this.$request.get('/course/v1/courses/learn_growth_card?clientType=6').then(res => {
console.log('getCareerData', res)
this.careerData = res
this.currentTab = res.cardList.findIndex(item => item.id === res.defaultCardId)
})
},
getCourseList() {
console.log('getCourseList')
},
getBannerList() {
console.log('getBannerList')
},
// 新增自动播放方法
startAutoPlay() {
this.clearAutoPlay()
this.timer = setInterval(() => {
this.nextTab()
}, 5000)
},
// 新增清除自动播放
clearAutoPlay() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
// 新增切换逻辑
nextTab() {
const newIndex = (this.currentTab + 1) % this.careerData.cardList.length
this.currentTab = newIndex
},
switchTab(index) {
// this.clearAutoPlay()
this.currentTab = index
// this.startAutoPlay()
},
handleSwiperChange(e) {
this.currentTab = e.detail.current
// 滑动后重置自动播放
// this.clearAutoPlay()
// this.startAutoPlay()
},
handleImgLoad(e, index) {
const query = uni.createSelectorQuery().in(this)
query
.select('.card-img')
.boundingClientRect(res => {
if (res) {
// 获取图片实际渲染尺寸
const systemInfo = uni.getSystemInfoSync()
const ratio = res.height / res.width
const actualWidth = systemInfo.windowWidth - 48 // 24*2的边距
const actualHeight = actualWidth * ratio
this.$set(this.imgHeights, index, actualHeight + 70) // 70是底部信息栏的高度
}
})
.exec()
},
},
}
......@@ -268,23 +351,46 @@ export default {
}
.search-area {
background: #fff;
background: url(https://static.ydlcdn.com/miniapp/ydl-group-course/top_bg.png) top no-repeat;
background-size: 100%;
.status-bar {
width: 100%;
}
.slogen {
display: flex;
align-items: center;
.slogen_img {
width: 59px;
height: 20px;
margin-left: 15px;
}
}
.tip {
margin-top: 15px;
padding: 0 15px;
color: #1c1f28;
font-weight: 600;
font-size: 19px;
font-style: normal;
.tip-blue {
color: #1da1f2;
padding-right: 2px;
}
}
.search-tags {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx;
padding: 8px 15px 0 15px;
.tag {
font-size: 24rpx;
color: #666;
color: #96a8b0;
font-weight: 400;
font-size: 11px;
letter-spacing: 1px;
&:nth-child(even) {
margin: 0 10rpx;
color: #999;
margin: 0 2px;
color: #96a8b0;
}
}
}
......@@ -294,92 +400,44 @@ export default {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 40rpx;
background: #fff;
padding: 0 26px;
margin-top: 26px;
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 12rpx;
.nav-icon {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: #fff;
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.05);
&.dark {
background: #4a5b67;
width: 40px;
height: 40px;
img {
width: 100%;
height: 100%;
}
}
text {
font-size: 26rpx;
color: #666;
margin-top: 8px;
color: #1c1f28;
font-weight: 400;
font-size: 11px;
}
}
}
.vip-tips {
margin: 20rpx;
padding: 30rpx;
background: #fff;
border-radius: 16rpx;
margin: 23px 12px 4px 12px;
border-radius: 12px;
background-color: #fff6ef;
// border: 1px solid #ffffff;
display: flex;
justify-content: space-between;
align-items: center;
.left-content {
flex: 1;
.tag-wrapper {
position: relative;
display: inline-flex;
align-items: center;
margin-bottom: 16rpx;
.tag-bg {
width: 140rpx;
height: 40rpx;
}
.tag-text {
position: absolute;
left: 16rpx;
color: #fff;
font-size: 22rpx;
font-weight: 500;
}
}
.text-content {
display: flex;
flex-direction: column;
gap: 8rpx;
.main-text {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
.sub-text {
font-size: 24rpx;
color: #999;
}
}
}
.right-action {
.action-text {
font-size: 26rpx;
color: #666;
background: #f5f6f8;
padding: 12rpx 24rpx;
border-radius: 30rpx;
}
height: auto;
.vip-tips-img {
width: 100%;
height: 100%;
border-radius: 12px;
}
}
......@@ -408,7 +466,7 @@ export default {
.career-tabs {
position: relative;
border-radius: 18px;
// padding: 4px;
padding: 0 4px;
margin-bottom: 10px;
height: 36px;
background: #f2f2f8;
......@@ -426,7 +484,7 @@ export default {
.tab-item {
flex: 1;
text-align: center;
color: #212123;
color: rgba(33, 33, 35, 0.7);
font-weight: 400;
font-size: 13px;
position: relative;
......@@ -435,9 +493,11 @@ export default {
display: flex;
align-items: center;
justify-content: center;
// border: 1px solid #333333;
&.active {
color: #333;
font-weight: 500;
position: relative;
}
}
......@@ -445,7 +505,7 @@ export default {
position: absolute;
left: 4px;
top: 4px;
width: calc(33.33% - 3px);
width: calc(100% / 3 - 2.7px);
height: calc(100% - 8px);
background: #fff;
border-radius: 16px;
......@@ -455,54 +515,20 @@ export default {
}
.content-swiper {
height: 500rpx; // 根据实际内容调整高度
width: 100%;
height: auto;
.consultant-card {
height: 100%;
background: #f7f8fa;
border-radius: 12rpx;
// padding: 30rpx;
// .card-title {
// font-size: 36rpx;
// font-weight: bold;
// color: #333;
// margin-bottom: 8rpx;
// }
// .card-subtitle {
// font-size: 26rpx;
// color: #666;
// margin-bottom: 40rpx;
// }
// .card-features {
// display: grid;
// grid-template-columns: repeat(4, 1fr);
// gap: 20rpx;
// margin-bottom: 40rpx;
// .feature-item {
// display: flex;
// flex-direction: column;
// align-items: center;
// gap: 8rpx;
// image {
// width: 64rpx;
// height: 64rpx;
// background: #fff;
// border-radius: 16rpx;
// padding: 12rpx;
// }
// text {
// font-size: 24rpx;
// color: #666;
// }
// }
// }
width: 100%;
height: auto;
// background: #f7f8fa;
position: relative;
// min-height: 306px;
.card-img {
display: block;
width: 100%;
height: auto;
border-radius: 12px;
}
.card-footer {
position: absolute;
height: 51px;
......@@ -529,9 +555,9 @@ export default {
line-height: 29px;
border-radius: 8px;
background-color: #212123;
min-width: 87px;
min-width: 80px;
text-align: center;
padding: 0 10px;
padding: 0 8px;
color: #ffffff;
font-weight: 600;
font-size: 12px;
......
src/static/tab_home.png

2.39 KB | W: | H:

src/static/tab_home.png

2.38 KB | W: | H:

src/static/tab_home.png
src/static/tab_home.png
src/static/tab_home.png
src/static/tab_home.png
  • 2-up
  • Swipe
  • Onion skin
src/static/tab_home_selected.png

1.63 KB | W: | H:

src/static/tab_home_selected.png

1.64 KB | W: | H:

src/static/tab_home_selected.png
src/static/tab_home_selected.png
src/static/tab_home_selected.png
src/static/tab_home_selected.png
  • 2-up
  • Swipe
  • Onion skin
src/static/tab_my.png

2.56 KB | W: | H:

src/static/tab_my.png

2.61 KB | W: | H:

src/static/tab_my.png
src/static/tab_my.png
src/static/tab_my.png
src/static/tab_my.png
  • 2-up
  • Swipe
  • Onion skin
src/static/tab_my_selected.png

1.6 KB | W: | H:

src/static/tab_my_selected.png

1.74 KB | W: | H:

src/static/tab_my_selected.png
src/static/tab_my_selected.png
src/static/tab_my_selected.png
src/static/tab_my_selected.png
  • 2-up
  • Swipe
  • Onion skin
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment