Files
gym-manage/gym-manage-uniapp/components/index/RecommendCourses.vue
T

517 lines
12 KiB
Vue
Raw 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="recommend-courses">
<!-- 区域标题栏 -->
<view class="section-header">
<!-- 区域标题 -->
<text class="section-title">推荐课程</text>
<!-- 查看更多按钮 -->
<view class="view-more">
<text>查看更多</text>
<text class="arrow">
<uni-icons type="right" size="20" color="#94a3b8"/>
</text>
</view>
</view>
<!-- 课程横向滚动容器 -->
<scroll-view class="courses-scroll" scroll-x="true" :show-scrollbar="false">
<!-- 课程列表 -->
<view class="courses-list">
<!-- 课程卡片 -->
<view
v-for="(course, index) in courses"
:key="course.id || index"
class="course-card"
>
<!-- 课程图片区域 -->
<view class="course-image">
<!-- 课程封面图片 -->
<image :src="course.image" mode="aspectFill" class="img" />
<!-- 图片渐变遮罩 -->
<view class="course-overlay"></view>
<!-- 课程标签 -->
<text :class="['course-tag', course.tagType]">{{ course.tag }}</text>
<!-- 课程信息区域 -->
<view class="course-info">
<!-- 课程名称 -->
<text class="course-name">{{ course.name }}</text>
<!-- 课程元信息时长难度 -->
<view class="course-meta">
<!-- 时长信息 -->
<view class="meta-item">
<text class="meta-icon">
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/time.png"/>
</text>
<text>{{ course.duration }}</text>
</view>
<!-- 难度信息 -->
<view class="meta-item">
<text class="meta-icon">
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/intensity.png"/>
</text>
<text>{{ course.level }}</text>
</view>
</view>
</view>
</view>
<!-- 课程底部区域 -->
<view class="course-footer">
<!-- 参与人数信息 -->
<view class="participants">
<text class="fire-icon">
<image src="https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/hot.png"/>
</text>
<text>{{ course.participants }}人参与</text>
</view>
<!-- 去参与按钮 -->
<view class="join-btn" @click="handleJoinCourse(course)">
<text>去参与</text>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getGroupCoursePage } from '@/api/main.js'
// 推荐课程数据列表
const courses = ref([])
// 课程类型映射(用于显示标签)
const getCourseTypeName = (type) => {
const typeMap = {
'1': '瑜伽',
'2': '搏击',
'3': '塑形'
}
return typeMap[type] || '课程'
}
// 根据课程信息获取标签文本
const getTag = (course) => {
// 满员标签
if (course.currentMembers >= course.maxMembers) {
return '已满员'
}
// 已结束的课程
if (course.status === '2') {
return '已结束'
}
// 高人气标签(参与人数超过最大人数的80%)
if (course.currentMembers / course.maxMembers >= 0.8) {
return '热门'
}
// 课程类型标签
return getCourseTypeName(course.courseType)
}
// 根据课程信息获取标签样式类型
const getTagType = (course) => {
// 满员标签样式
if (course.currentMembers >= course.maxMembers) {
return 'full'
}
// 已结束标签样式
if (course.status === '2') {
return 'ended'
}
// 热门标签样式
if (course.currentMembers / course.maxMembers >= 0.8) {
return 'hot'
}
// 默认样式
return 'default'
}
// 计算课程时长(从startTime和endTime计算)
const calculateDuration = (startTime, endTime) => {
if (!startTime || !endTime) return '60分钟'
const start = new Date(startTime)
const end = new Date(endTime)
const durationMinutes = Math.floor((end - start) / (1000 * 60))
return `${durationMinutes}分钟`
}
// 获取课程难度(基于课程类型和描述简单判断)
const getCourseLevel = (course) => {
// 可以根据实际需求调整逻辑
if (course.courseType === '2') return '中级'
if (course.courseType === '3') return '高级'
if (course.courseType === '1') return '初级'
return '初级'
}
// 处理图片URL
const getImageUrl = (coverImage) => {
if (!coverImage) {
return 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=400&q=80'
}
// 如果已经是完整URL直接返回,否则拼接基础路径
if (coverImage.startsWith('http')) {
return coverImage
}
// 这里需要根据您的实际图片基础路径配置
return `https://your-domain.com${coverImage}`
}
// 获取推荐课程(按最火排序,返回5条)
const fetchRecommendCourses = async () => {
try {
const res = await getGroupCoursePage({
page: 0,
size: 5,
sort: 'current_members', // 按参与人数排序
order: 'desc' // 降序,即最火的在前
}, { cache: true, cacheTime: 5 * 60 * 1000 })
if (res && res.content && Array.isArray(res.content)) {
// 将后端数据转换为组件所需格式
courses.value = res.content.map(course => ({
id: course.id,
image: getImageUrl(course.coverImage),
tag: getTag(course),
tagType: getTagType(course),
name: course.courseName || '未知课程',
duration: calculateDuration(course.startTime, course.endTime),
level: getCourseLevel(course),
participants: course.currentMembers || 0,
// 保存原始数据供点击事件使用
rawData: course
}))
} else {
// 如果没有数据,使用提供的示例数据作为fallback
useFallbackData()
}
} catch (err) {
// console.error('获取推荐课程失败:', err)
// 使用提供的示例数据作为fallback
useFallbackData()
}
}
// 使用提供的响应数据作为默认数据
const useFallbackData = () => {
const fallbackContent = [
{
id: "3",
courseName: "燃脂搏击",
courseType: "2",
startTime: "2026-06-10T18:30:00",
endTime: "2026-06-10T19:30:00",
maxMembers: 20,
currentMembers: 20,
status: "0",
coverImage: "/images/kickboxing.jpg",
description: "高强度间歇训练,配合音乐快速燃脂,释放压力。名额已满,无法预约。"
},
{
id: "2",
courseName: "清晨流瑜伽",
courseType: "1",
startTime: "2026-06-12T09:00:00",
endTime: "2026-06-12T10:30:00",
maxMembers: 15,
currentMembers: 5,
status: "0",
coverImage: "/images/yoga_flow.jpg",
description: "适合有一定基础的学员,通过流畅的体式连接呼吸,唤醒身体能量。"
},
{
id: "4",
courseName: "哈他瑜伽",
courseType: "1",
startTime: "2026-06-01T15:20:00",
endTime: "2026-06-01T16:50:00",
maxMembers: 12,
currentMembers: 3,
status: "0",
coverImage: "/images/hatha_yoga.jpg",
description: "基础哈他瑜伽,适合所有级别。距开始不足30分钟,已停止预约。"
},
{
id: "6",
courseName: "蜜桃臀塑造",
courseType: "3",
startTime: "2026-05-30T19:00:00",
endTime: "2026-05-30T20:00:00",
maxMembers: 10,
currentMembers: 8,
status: "2",
coverImage: "/images/glute.jpg",
description: "针对性训练臀部肌肉群,课程已于5月30日结束,无法预约。"
},
{
id: "7",
courseName: "午间冥想放松",
courseType: "1",
startTime: "2026-05-31T12:00:00",
endTime: "2026-05-31T13:00:00",
maxMembers: 15,
currentMembers: 6,
status: "2",
coverImage: "/images/meditation_noon.jpg",
description: "午间冥想课程,已于5月31日结束。"
}
]
courses.value = fallbackContent.map(course => ({
id: course.id,
image: getImageUrl(course.coverImage),
tag: getTag(course),
tagType: getTagType(course),
name: course.courseName || '未知课程',
duration: calculateDuration(course.startTime, course.endTime),
level: getCourseLevel(course),
participants: course.currentMembers || 0,
rawData: course
}))
}
// 处理参与课程点击
const handleJoinCourse = (course) => {
// 根据课程状态判断是否可以参与
if (course.rawData.status === '2') {
uni.showToast({
title: '课程已结束',
icon: 'none'
})
return
}
if (course.rawData.currentMembers >= course.rawData.maxMembers) {
uni.showToast({
title: '课程已满员',
icon: 'none'
})
return
}
// 跳转到课程详情页
uni.navigateTo({
url: `/pages/course/detail?id=${course.id}`
})
}
// 组件挂载时获取数据
onMounted(() => {
fetchRecommendCourses()
})
</script>
<style lang="scss">
/* 推荐课程容器样式 */
.recommend-courses {
padding: 0 24rpx;
margin-bottom: 32rpx;
}
/* 区域标题栏样式 */
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
/* 区域标题样式 */
.section-title {
font-size: 34rpx;
font-weight: 700;
color: #1a202c;
}
/* 查看更多按钮样式 */
.view-more {
display: flex;
align-items: center;
gap: 4rpx;
font-size: 26rpx;
color: #94a3b8;
}
/* 箭头图标样式 */
.arrow {
font-size: 32rpx;
}
/* 课程横向滚动容器样式 */
.courses-scroll {
white-space: nowrap;
}
/* 课程列表样式 */
.courses-list {
display: inline-flex;
gap: 48rpx;
}
/* 课程卡片样式 */
.course-card {
width: 320rpx;
background: #ffffff;
border-radius: 24rpx;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
display: inline-block;
vertical-align: top;
}
/* 课程图片区域样式 */
.course-image {
height: 280rpx;
position: relative;
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 20rpx;
}
/* 课程封面图片样式 */
.img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
/* 图片渐变遮罩样式 */
.course-overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%);
}
/* 课程标签样式 */
.course-tag {
position: absolute;
top: 16rpx;
right: 16rpx;
padding: 8rpx 16rpx;
border-radius: 12rpx;
font-size: 20rpx;
font-weight: 600;
color: #ffffff;
background: #f97316;
z-index: 2;
/* 热门标签 */
&.hot {
background: #ef4444;
}
/* 新课标签 */
&.new {
background: #10b981;
}
/* 免费标签 */
&.free {
background: #3b82f6;
}
/* 满员标签 */
&.full {
background: #64748b;
}
/* 已结束标签 */
&.ended {
background: #94a3b8;
}
/* 默认标签 */
&.default {
background: #f97316;
}
}
/* 课程信息区域样式 */
.course-info {
position: relative;
z-index: 2;
}
/* 课程名称样式 */
.course-name {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #ffffff;
margin-bottom: 8rpx;
}
/* 课程元信息容器样式 */
.course-meta {
display: flex;
gap: 16rpx;
align-items: center;
}
/* 课程元信息项样式 */
.meta-item {
display: flex;
align-items: end;
gap: 6rpx;
font-size: 22rpx;
color: rgba(255, 255, 255, 0.8);
}
/* 元信息图标样式 */
.meta-icon {
font-size: 20rpx;
image{
display: flex;
align-items: center;
width: 25rpx;
height: 25rpx;
}
}
/* 课程底部区域样式 */
.course-footer {
padding: 16rpx 10rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 参与人数信息样式 */
.participants {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 22rpx;
color: #94a3b8;
}
/* 火热图标样式 */
.fire-icon {
font-size: 24rpx;
image{
display: flex;
align-items: center;
width: 30rpx;
height: 30rpx;
}
}
/* 去参与按钮样式 */
.join-btn {
padding: 12rpx 28rpx;
background: transparent;
border: 2rpx solid #f97316;
border-radius: 9999rpx;
font-size: 22rpx;
font-weight: 600;
color: #f97316;
}
</style>