224 lines
5.5 KiB
Vue
224 lines
5.5 KiB
Vue
<template>
|
|
<!-- 今日推荐容器 -->
|
|
<view class="today-recommend">
|
|
<!-- 区域标题栏 -->
|
|
<view class="section-header">
|
|
<!-- 区域标题 -->
|
|
<text class="section-title">今日推荐</text>
|
|
</view>
|
|
|
|
<!-- 推荐列表 -->
|
|
<view class="recommend-list">
|
|
<!-- 推荐项 -->
|
|
<view
|
|
v-for="(item, index) in recommends"
|
|
:key="item.id || index"
|
|
class="recommend-item"
|
|
@click="handleItemClick(item)"
|
|
>
|
|
<!-- 推荐项图片 -->
|
|
<image :src="item.image" mode="aspectFill" class="item-image" />
|
|
<!-- 推荐项内容区域 -->
|
|
<view class="item-content">
|
|
<!-- 推荐项标题 -->
|
|
<text class="item-title">{{ item.title }}</text>
|
|
<!-- 推荐项标签列表 -->
|
|
<view class="item-tags">
|
|
<text v-for="(tag, tagIndex) in item.tags" :key="tagIndex" class="tag">{{ tag }}</text>
|
|
</view>
|
|
<!-- 推荐项描述 -->
|
|
<text class="item-desc">{{ item.desc }}</text>
|
|
</view>
|
|
<!-- 推荐项操作区域 -->
|
|
<view class="item-action">
|
|
<!-- 开始训练按钮 -->
|
|
<view class="start-btn" @click.stop="handleItemClick(item)">
|
|
<text class="start-btn-text">开始训练</text>
|
|
</view>
|
|
<!-- 参与人数 -->
|
|
<text class="participants">{{ item.participants }}人参与</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import { getGroupCoursePage } from '@/api/main.js'
|
|
|
|
// 今日推荐数据列表
|
|
const recommends = ref([])
|
|
|
|
// 计算课程时长
|
|
const calculateDuration = (startTime, endTime) => {
|
|
if (!startTime || !endTime) return '60分钟'
|
|
const start = new Date(startTime)
|
|
const end = new Date(endTime)
|
|
const diffMs = end - start
|
|
if (diffMs <= 0) return ''
|
|
const durationMinutes = Math.floor(diffMs / (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-1571019613454-1cb2f99b2d8b?w=300&q=80'
|
|
if (coverImage.startsWith('http')) return coverImage
|
|
return `https://your-domain.com${coverImage}`
|
|
}
|
|
|
|
// 获取今日推荐
|
|
const fetchTodayRecommend = async () => {
|
|
try {
|
|
const res = await getGroupCoursePage({
|
|
page: 0, size: 10, sort: 'current_members', order: 'desc'
|
|
}, { cache: true, cacheTime: 5 * 60 * 1000 })
|
|
if (res && res.content && Array.isArray(res.content)) {
|
|
const filteredCourses = res.content.filter(course => {
|
|
return course.status !== '2' && course.currentMembers < course.maxMembers
|
|
})
|
|
|
|
recommends.value = filteredCourses.slice(0, 3).map(course => {
|
|
return {
|
|
id: course.id,
|
|
image: getImageUrl(course.coverImage),
|
|
title: course.courseName || '未知课程',
|
|
tags: [calculateDuration(course.startTime, course.endTime), getCourseLevel(course)],
|
|
desc: course.description || '精彩课程,不容错过',
|
|
participants: String(course.currentMembers || 0)
|
|
}
|
|
})
|
|
}
|
|
} catch (err) {
|
|
console.error('获取今日推荐失败:', err)
|
|
}
|
|
}
|
|
|
|
const handleItemClick = (item) => {
|
|
if (!item.id) { uni.showToast({ title: '课程信息不完整', icon: 'none' }); return }
|
|
uni.navigateTo({ url: `/pages/groupCourse/detail?id=${item.id}` })
|
|
}
|
|
|
|
onMounted(() => { fetchTodayRecommend() })
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.today-recommend {
|
|
padding: 0 24rpx;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 34rpx;
|
|
font-weight: 700;
|
|
color: #2D4A5A;
|
|
}
|
|
|
|
.recommend-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24rpx;
|
|
}
|
|
|
|
.recommend-item {
|
|
display: flex;
|
|
gap: 24rpx;
|
|
background: rgba(255, 255, 255, 0.6);
|
|
backdrop-filter: blur(16px);
|
|
-webkit-backdrop-filter: blur(16px);
|
|
border-radius: 24rpx;
|
|
padding: 20rpx;
|
|
box-shadow: 0 8rpx 28rpx var(--shadow-blue-light);
|
|
border: 1rpx solid rgba(255, 255, 255, 0.6);
|
|
}
|
|
|
|
.item-image {
|
|
width: 200rpx;
|
|
height: 160rpx;
|
|
border-radius: 16rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.item-content {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
min-width: 0;
|
|
}
|
|
|
|
.item-title {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #2D4A5A;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.item-tags {
|
|
display: flex;
|
|
gap: 12rpx;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.tag {
|
|
padding: 6rpx 16rpx;
|
|
background: rgba(122, 181, 204, 0.12);
|
|
border-radius: 8rpx;
|
|
font-size: 22rpx;
|
|
color: #6BA8C0;
|
|
}
|
|
|
|
.item-desc {
|
|
font-size: 24rpx;
|
|
color: var(--tabbar-text-inactive);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.item-action {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end;
|
|
justify-content: center;
|
|
gap: 16rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.start-btn {
|
|
padding: 16rpx 28rpx;
|
|
background: rgba(130, 220, 130, 0.9);
|
|
border-radius: 9999rpx;
|
|
box-shadow: 0 6rpx 20rpx rgba(130, 220, 130, 0.4);
|
|
}
|
|
|
|
.start-btn-text {
|
|
font-size: 24rpx;
|
|
font-weight: 600;
|
|
color: #ffffff;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.participants {
|
|
font-size: 22rpx;
|
|
color: var(--tabbar-text-inactive);
|
|
white-space: nowrap;
|
|
}
|
|
</style> |