2025-08-25 14:17:06 +08:00

892 lines
21 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="course-page">
<!-- 自定义导航栏 -->
<view class="navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="nav-content">
<view class="nav-left" @click="goBack">
<uni-icons type="left" size="24" color="#333"></uni-icons>
</view>
<view class="nav-title">肝胆相照精品课</view>
<view class="nav-right" @click="goSearch">
<uni-icons type="search" size="24" color="#333"></uni-icons>
</view>
</view>
</view>
<!-- 页面内容 -->
<view class="page-content" :style="{ paddingTop: navBarHeight + 'px' }">
<!-- 主横幅 -->
<view class="main-banner">
<swiper class="banner-swiper"
:indicator-dots="true"
:autoplay="true"
:interval="3000"
:duration="500"
indicator-color="rgba(255,255,255,0.3)"
indicator-active-color="#FF4757">
<swiper-item v-for="(banner, index) in bannerList" :key="banner.id || index" @click="goBannerDetail(banner)">
<image :src="banner.sroll_img || banner.image || '/static/lunbo_bg.png'" mode="aspectFill" class="banner-image"></image>
<view class="banner-content">
<text class="banner-title">{{ banner.title || '课程标题' }}</text>
</view>
</swiper-item>
</swiper>
</view>
<!-- 分类导航 -->
<view class="category-nav">
<view class="category-item"
v-for="(category, index) in firstTypeList"
:key="category.id"
@click="goCategory(category.id, category.name)">
<view class="category-icon" :class="getCategoryIconClass(index)">
<image :src="category.img" mode="aspectFit"></image>
</view>
<text class="category-text">{{ category.name }}</text>
</view>
</view>
<!-- 功能按钮 -->
<view class="function-nav">
<view class="function-item"
v-for="(typeItem, index) in specialTypeList"
:key="typeItem.id"
@click="goVideoType(typeItem.id, typeItem.name)">
<view class="function-icon">
<image style="height: 50rpx;" :src="typeItem.img" mode="aspectFit"></image>
<!-- <uni-icons :type="getFunctionIconType(index)" size="24" :color="getFunctionIconColor(index)"></uni-icons> -->
</view>
<text class="function-text">{{ typeItem.name }}</text>
</view>
</view>
<!-- 精品小课 -->
<view class="section">
<view class="section-header">
<text class="section-title">精品小课</text>
<view class="more-btn" @click="goMorePremium('精品小课')">
<text>更多</text>
<uni-icons type="arrowright" size="14" color="#999"></uni-icons>
</view>
</view>
<view v-if="premiumCourseList.length > 0">
<view class="premium-course"
v-for="(course, index) in premiumCourseList"
:key="course.id"
@click="goPremiumCourse(course)">
<image :src="course.index_img || '/static/jingpingke.png'" mode="aspectFill" class="course-image"></image>
<view class="course-info">
<text class="course-title">{{ course.title }}</text>
<view class="course-meta">
<view class="participant-count">{{ course.study_num }}</view>
<text class="course-price" v-if="course.discount_price > 0">¥{{ (course.discount_price / 100).toFixed(2) }}</text>
<text class="course-price free" v-else>免费</text>
</view>
</view>
</view>
</view>
<view v-else class="empty-state">
<text class="empty-text">暂无精品小课</text>
</view>
</view>
<!-- 学完返现 -->
<view class="section">
<view class="section-header">
<text class="section-title">学完返现</text>
<view class="more-btn" @click="goMoreRewards('学完返现')">
<text>更多</text>
<uni-icons type="arrowright" size="14" color="#999"></uni-icons>
</view>
</view>
<view class="rewards-grid">
<view class="reward-card"
v-for="(course, index) in rewardCourseList.slice(0, 4)"
:key="course.id"
@click="goRewardCourse(course)">
<image :src="course.index_img || '/static/paper_bg.png'" mode="aspectFill" class="reward-image"></image>
</view>
</view>
</view>
<!-- 福利课堂 -->
<view class="section">
<view class="section-header">
<text class="section-title">福利课堂</text>
<view class="more-btn" @click="goMoreWelfare('福利课堂')">
<text>更多</text>
<uni-icons type="arrowright" size="14" color="#999"></uni-icons>
</view>
</view>
<scroll-view class="welfare-scroll" scroll-x="true" show-scrollbar="false">
<view class="welfare-list">
<view class="welfare-item" v-for="(course, index) in welfareCourseList" :key="course.id" @click="goWelfareDetail(course)">
<view class="welfare-card">
<image :src="course.index_img || '/static/fulicard.png'" mode="aspectFill" class="welfare-image"></image>
<view class="welfare-content">
<text class="welfare-title">{{ course.title }}</text>
<text class="welfare-subtitle">{{ course.special_type_name || '福利课堂' }}</text>
<view class="welfare-meta">
<text class="welfare-teacher">{{ course.study_num }}人学习</text>
<text class="welfare-price" v-if="course.fuli_bon > 0">+{{ course.fuli_bon }}积分</text>
<text class="welfare-price" v-else>免费</text>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 课程推荐 -->
<view class="section">
<view class="section-header">
<text class="section-title">课程推荐</text>
<view class="more-btn" @click="goMoreHot('课程推荐')">
<text>更多</text>
<uni-icons type="arrowright" size="14" color="#999"></uni-icons>
</view>
</view>
<view class="hot-courses">
<view class="course-item" v-for="(course, index) in recommendedCourseList" :key="course.id" @click="goCourseDetail(course)">
<image :src="course.index_img || '/static/jingpinkecheng.png'" mode="aspectFill" class="course-thumb"></image>
<view class="course-content">
<text class="course-name">{{ course.title }}</text>
<text class="course-desc">{{ course.tags || '' }}</text>
<text class="course-cost">¥{{ (course.discount_price / 100).toFixed(2) }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 底部固定栏 -->
<view class="bottom-tab">
<view class="tab-item active">
<uni-icons type="home" size="24" color="#FF4757"></uni-icons>
<text class="tab-text active-text">精品课</text>
</view>
<view class="tab-item" @click="goToMyCourses">
<uni-icons type="chatboxes" size="24" color="#999"></uni-icons>
<text class="tab-text">我的课程</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import course_api from "@/api/course_api.js"
// 响应式数据
const statusBarHeight = ref(0)
const navBarHeight = ref(88)
const firstTypeList = ref([])
const specialTypeList = ref([])
const premiumCourseList = ref([]) // 新增:精品小课数据
const rewardCourseList = ref([]) // 新增:学完返现数据
const welfareCourseList = ref([]) // 新增:福利课堂数据
const recommendedCourseList = ref([]) // 新增:课程推荐数据
const bannerList = ref([])
// 方法
const getSystemInfo = () => {
const systemInfo = uni.getSystemInfoSync()
statusBarHeight.value = systemInfo.statusBarHeight
// #ifdef MP-WEIXIN
navBarHeight.value = systemInfo.statusBarHeight + 44
// #endif
// #ifdef APP-PLUS
navBarHeight.value = systemInfo.statusBarHeight + 44
// #endif
}
const goBack = () => {
uni.navigateTo({
url: '/pages/index/index'
})
}
const goSearch = () => {
uni.navigateTo({
url: '/pages_app/search/search'
})
}
const goCategory = (type, name) => {
console.log('跳转分类:', type, name)
uni.navigateTo({
url: `/pages_course/course_filter/course_filter?type=${type}`
})
}
const getCategoryIconClass = (index) => {
switch (index) {
case 0:
return 'liver-icon';
case 1:
return 'tumor-icon';
case 2:
return 'infection-icon';
default:
return '';
}
}
const goPremiumCourse = (course) => {
console.log('跳转精品小课详情:', course)
// 跳转到课程详情页面传递课程ID
uni.navigateTo({
url: `/pages_course/course_detail/course_detail?id=${course.id}`
})
}
const goRewardCourse = (course) => {
console.log('跳转返现课程:', course)
// 跳转到课程详情页面传递课程ID
uni.navigateTo({
url: `/pages_course/course_detail/course_detail?id=${course.id}`
})
}
const goMorePremium = (name) => {
console.log('查看更多精品课程')
uni.navigateTo({
url: `/pages_course/course_filter/course_filter?special_type=${specialTypeList.value.find(item => item.name == name).id}&special_name=${name}`
})
}
const goMoreRewards = (name) => {
console.log('查看更多返现')
uni.navigateTo({
url: `/pages_course/course_filter/course_filter?special_type=${specialTypeList.value.find(item => item.name == name).id}&special_name=${name}`
})
}
const goMoreWelfare = (name) => {
console.log('查看更多福利')
uni.navigateTo({
url: `/pages_course/course_filter/course_filter?special_type=${specialTypeList.value.find(item => item.name == name).id}&special_name=${name}`
})
}
const goMoreHot = (name) => {
console.log('查看更多热门')
uni.navigateTo({
url: `/pages_course/course_filter/course_filter?special_type=${specialTypeList.value.find(item => item.name == name).id}&special_name=${name}`
})
}
const goCourseDetail = (course) => {
console.log('课程详情:', course)
// 跳转到课程详情页面传递课程ID
uni.navigateTo({
url: `/pages_course/course_detail/course_detail?id=${course.id}`
})
}
const goWelfareDetail = (course) => {
console.log('福利课堂详情:', course)
// 跳转到课程详情页面传递课程ID
uni.navigateTo({
url: `/pages_course/course_detail/course_detail?id=${course.id}`
})
}
const goBannerDetail = (banner) => {
console.log('横幅详情:', banner)
// 跳转到课程详情页面
uni.navigateTo({
url: '/pages_course/course_detail/course_detail?id=' + banner.id
})
}
const goToMyCourses = () => {
console.log('跳转到我的课程页面')
uni.navigateTo({
url: '/pages_course/my_courses/my_courses'
})
}
const getIndex = async () => {
try {
const res = await course_api.index()
console.log('API响应:', res)
if (res.code === 200 && res.data) {
// 处理轮播图数据
if (res.data.scroll_list) {
bannerList.value = res.data.scroll_list
console.log('轮播图数据已更新:', bannerList.value)
}
// 处理分类数据
if (res.data.first_type_list) {
firstTypeList.value = res.data.first_type_list
console.log('分类数据已更新:', firstTypeList.value)
}
// 处理功能按钮数据
if (res.data.special_type_list) {
specialTypeList.value = res.data.special_type_list
console.log('功能按钮数据已更新:', specialTypeList.value)
}
// 处理精品小课数据
if (res.data.video_type_List) {
const premiumType = res.data.video_type_List.find(type => type.type_name === "精品小课")
if (premiumType && premiumType.video_list) {
premiumCourseList.value = premiumType.video_list.slice(0, 3) // 只显示前3个
console.log('精品小课数据已更新:', premiumCourseList.value)
}
// 处理学完返现数据
const rewardType = res.data.video_type_List.find(type => type.type_name === "学完返现")
if (rewardType && rewardType.video_list) {
rewardCourseList.value = rewardType.video_list
console.log('学完返现数据已更新:', rewardCourseList.value)
}
// 处理福利课堂数据
const welfareType = res.data.video_type_List.find(type => type.type_name === "福利课堂")
if (welfareType && welfareType.video_list) {
welfareCourseList.value = welfareType.video_list
console.log('福利课堂数据已更新:', welfareCourseList.value)
}
// 处理课程推荐数据
const recommendedType = res.data.video_type_List.find(type => type.type_name === "课程推荐")
if (recommendedType && recommendedType.video_list) {
recommendedCourseList.value = recommendedType.video_list
console.log('课程推荐数据已更新:', recommendedCourseList.value)
}
}
} else {
console.warn('API返回数据格式异常:', res)
}
} catch (error) {
console.error('获取分类数据失败:', error)
}
}
// 设置默认数据
const goVideoType = (typeId, typeName) => {
console.log('跳转视频类型:', typeId, typeName)
// 跳转到视频类型详情页面
uni.navigateTo({
url: `/pages_course/course_filter/course_filter?special_type=${typeId}&special_name=${typeName}`
})
}
// 生命周期
onMounted(() => {
getSystemInfo()
getIndex()
})
</script>
<style lang="scss">
.course-page {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 120rpx;
}
// 导航栏
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
background-color: #fff;
border-bottom: 1rpx solid #e5e5e5;
.nav-content {
height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32rpx;
.nav-left, .nav-right {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.nav-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
}
}
.page-content {
background-color: #f5f5f5;
}
// 主横幅
.main-banner {
margin: 24rpx 24rpx 32rpx;
border-radius: 16rpx;
overflow: hidden;
.banner-swiper {
height: 300rpx;
border-radius: 16rpx;
.banner-image {
width: 100%;
height: 100%;
}
.banner-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 40rpx 24rpx 24rpx;
background: linear-gradient(transparent, rgba(0,0,0,0.7));
.banner-title {
display: block;
font-size: 32rpx;
color: #fff;
font-weight: 600;
margin-bottom: 8rpx;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.5);
}
.banner-subtitle {
display: block;
font-size: 22rpx;
color: rgba(255,255,255,0.9);
line-height: 1.4;
text-shadow: 0 1rpx 2rpx rgba(0,0,0,0.5);
}
}
}
}
// 分类导航
.category-nav {
display: flex;
justify-content: space-around;
padding: 0 60rpx 40rpx;
.category-item {
display: flex;
flex-direction: column;
align-items: center;
.category-icon {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
image {
width: 60rpx;
height: 60rpx;
}
&.liver-icon {
background: linear-gradient(135deg, #FF8A65, #FF5722);
}
&.tumor-icon {
background: linear-gradient(135deg, #FFD54F, #FF9800);
}
&.infection-icon {
background: linear-gradient(135deg, #64B5F6, #2196F3);
}
}
.category-text {
font-size: 28rpx;
color: #333;
}
}
}
// 功能导航
.function-nav {
display: flex;
justify-content: space-around;
padding: 0 60rpx 40rpx;
.function-item {
display: flex;
flex-direction: column;
align-items: center;
.function-icon {
width: 50rpx;
height: 50rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12rpx;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
&.fire-icon {
background: linear-gradient(135deg, #FF6B35, #FF4757);
}
&.star-icon {
background: linear-gradient(135deg, #FFB800, #FFD54F);
}
&.gift-icon {
background: linear-gradient(135deg, #4CAF50, #388E3C);
}
&.heart-icon {
background: linear-gradient(135deg, #E91E63, #D81B60);
}
}
.function-text {
font-size: 24rpx;
color: #666;
}
}
}
// 通用区块
.section {
margin-bottom: 40rpx;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 24rpx 24rpx;
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.more-btn {
display: flex;
align-items: center;
color: #999;
font-size: 24rpx;
}
}
}
// 精品小课
.premium-course {
margin: 0 24rpx 24rpx;
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
display: flex;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
&:last-child {
margin-bottom: 0;
}
.course-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 24rpx;
}
.course-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.course-title {
font-size: 28rpx;
color: #333;
line-height: 1.4;
}
.course-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20rpx;
.participant-count {
background-color: #FF4757;
color: #fff;
font-size: 20rpx;
padding: 4rpx 12rpx;
border-radius: 12rpx;
}
.course-price {
font-size: 32rpx;
color: #FF4757;
font-weight: 600;
&.free {
color: #4CAF50;
font-weight: 600;
}
}
}
}
}
// 空状态
.empty-state {
margin: 0 24rpx;
background-color: #fff;
border-radius: 16rpx;
padding: 80rpx 24rpx;
text-align: center;
.empty-text {
font-size: 28rpx;
color: #999;
}
}
// 学完返现
.rewards-grid {
display: flex;
gap: 24rpx;
flex-wrap: wrap;
padding: 0 24rpx;
.reward-card {
width: calc(50% - 12rpx); // 每行两个,减去间距的一半
border-radius: 16rpx;
overflow: hidden;
position: relative;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
.reward-image {
width: 100%;
height: 200rpx;
}
.reward-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx;
background: linear-gradient(transparent, rgba(0,0,0,0.8));
color: #fff;
display: flex;
flex-direction: column;
justify-content: flex-end;
box-sizing: border-box;
}
.reward-title {
font-size: 28rpx;
font-weight: 500;
line-height: 1.4;
margin-bottom: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.5);
}
.reward-meta {
display: flex;
justify-content: space-between;
align-items: center;
.reward-price {
font-size: 24rpx;
color: #FFD54F;
font-weight: 600;
text-shadow: 0 1rpx 2rpx rgba(0,0,0,0.5);
}
.reward-bonus {
font-size: 22rpx;
color: #4CAF50;
background-color: rgba(255,255,255,0.9);
padding: 4rpx 8rpx;
border-radius: 8rpx;
font-weight: 500;
}
}
}
}
// 福利课堂
.welfare-scroll {
margin: 0 24rpx;
.welfare-list {
display: flex;
gap: 24rpx;
padding: 0 0 16rpx 0;
.welfare-item {
flex-shrink: 0;
width: 400rpx;
.welfare-card {
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
.welfare-image {
width: 100%;
height: 200rpx;
}
.welfare-content {
padding: 20rpx;
.welfare-title {
display: block;
font-size: 28rpx;
color: #333;
font-weight: 500;
line-height: 1.4;
margin-bottom: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.welfare-subtitle {
display: block;
font-size: 24rpx;
color: #666;
line-height: 1.3;
margin-bottom: 16rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.welfare-meta {
display: flex;
justify-content: space-between;
align-items: center;
.welfare-teacher {
font-size: 22rpx;
color: #999;
}
.welfare-price {
font-size: 24rpx;
color: #FF4757;
font-weight: 600;
}
}
}
}
}
}
}
// 热门课程
.hot-courses {
padding: 0 24rpx;
.course-item {
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 16rpx;
display: flex;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
.course-thumb {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 24rpx;
}
.course-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.course-name {
font-size: 28rpx;
color: #333;
font-weight: 500;
line-height: 1.4;
}
.course-desc {
font-size: 24rpx;
color: #666;
margin: 8rpx 0;
line-height: 1.3;
}
.course-cost {
font-size: 32rpx;
color: #FF4757;
font-weight: 600;
align-self: flex-end;
}
}
}
}
// 底部标签栏
.bottom-tab {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 120rpx;
background-color: #fff;
border-top: 1rpx solid #e5e5e5;
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.tab-text {
font-size: 20rpx;
color: #999;
margin-top: 8rpx;
&.active-text {
color: #FF4757;
}
}
&.active {
color: #FF4757;
}
}
}
</style>