Files
venue-miniapp/miniprogram/src/pages/comprehensive/home/index.vue
T
2026-06-08 20:54:25 +08:00

296 lines
6.6 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="home-container">
<view class="banner-wrapper">
<swiper
v-if="banners.length"
class="banner-swiper"
circular
autoplay
interval="4000"
duration="600"
indicator-dots
indicator-color="rgba(15, 23, 42, 0.1)"
indicator-active-color="#0F172A"
>
<swiper-item v-for="banner in banners" :key="banner.id">
<view class="banner-item">
<image :src="banner.image" mode="aspectFill" class="banner-img" />
<view class="banner-overlay">
<text class="banner-title">{{ banner.title }}</text>
</view>
</view>
</swiper-item>
</swiper>
</view>
<view class="section-container">
<view class="section-header">
<text class="section-title">近期课程</text>
</view>
<view v-if="upcomingCourses.length" class="course-list">
<view v-for="course in upcomingCourses" :key="course.id" class="course-item" @tap="go(`/pages/comprehensive/courses/detail?id=${course.id}`)">
<image :src="course.cover_image" mode="aspectFill" class="course-cover" />
<view class="course-info-wrap">
<view class="course-title-row">
<text class="course-name">{{ course.title }}</text>
</view>
<text class="course-time highlight-blue">时间{{ formatTimeRange(course.start_at, course.end_at) }}</text>
<view class="course-bottom-meta">
<text class="course-meta-text"> 教练{{ course.coach_name }}</text>
<text class="course-meta-text"> 人数已约 {{ course.booked_count }}/{{ course.capacity }}</text>
</view>
</view>
</view>
</view>
<view v-else class="empty-placeholder">今日暂无课程排期</view>
</view>
<view class="section-container last-section">
<view class="section-header">
<text class="section-title">公告活动</text>
</view>
<view v-if="articles.length" class="activity-grid">
<view v-for="article in articles" :key="article.id" class="activity-card" @tap="go(`/pages/comprehensive/activities/detail?id=${article.id}`)">
<image :src="article.cover_image" mode="aspectFill" class="activity-cover" />
<view class="activity-info">
<text class="activity-title">{{ article.title }}</text>
<text class="activity-date">{{ formatDate(article.published_at || article.created_at) }}</text>
</view>
</view>
</view>
<view v-else class="empty-placeholder">暂无公告活动</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onPullDownRefresh } from '@dcloudio/uni-app'
import { contentApi } from '@/modules/comprehensive/api/content'
import { formatDate, formatTimeRange } from '@/modules/comprehensive/utils/date'
const banners = ref([])
const upcomingCourses = ref([])
const articles = ref([])
onMounted(() => {
loadPage()
})
onPullDownRefresh(() => {
loadPage().finally(() => uni.stopPullDownRefresh())
})
const loadPage = async () => {
const home = await contentApi.getHomeContent({ banner_limit: 5, article_limit: 3 })
banners.value = home.banners || []
upcomingCourses.value = (home.upcoming_courses || []).slice(0, 2)
articles.value = home.articles || []
}
const go = (url) => {
uni.navigateTo({ url })
}
</script>
<style lang="scss" scoped>
.home-container {
min-height: 100vh;
padding: $spacing-lg $spacing-md;
background-color: $bg-color-soft;
}
.banner-wrapper {
margin-bottom: $spacing-lg;
}
.banner-swiper {
height: 320rpx;
border-radius: $border-radius-base;
overflow: hidden;
}
.banner-item {
position: relative;
width: 100%;
height: 100%;
}
.banner-img {
width: 100%;
height: 100%;
background-color: $bg-color-hover;
}
.banner-overlay {
position: absolute;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: flex-end;
padding: $spacing-md;
background: linear-gradient(to top, rgba(15, 23, 42, 0.6), transparent);
}
.banner-title {
color: #FFFFFF;
font-size: 24rpx;
font-weight: 400;
line-height: 1.4;
}
.section-container {
margin-bottom: $spacing-xl;
}
.section-container.last-section {
margin-bottom: 0;
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: $spacing-md;
padding: 0 4rpx;
}
.section-title {
position: relative;
padding-left: $spacing-sm;
color: $text-color-main;
font-size: 28rpx;
font-weight: 700;
letter-spacing: 0.5rpx;
}
.section-title::before {
content: '';
position: absolute;
left: 0;
top: 10%;
bottom: 10%;
width: 4rpx;
background-color: $text-color-main;
}
.course-list,
.activity-grid {
display: flex;
flex-direction: column;
gap: $spacing-sm;
}
.course-item,
.activity-card {
display: flex;
overflow: hidden;
border: 1rpx solid $bg-color-hover;
border-radius: $border-radius-base;
background-color: $bg-color-main;
transition: all 0.2s ease;
}
.course-item:active,
.activity-card:active {
background-color: $bg-color-hover;
}
.course-cover {
width: 180rpx;
height: 130rpx;
flex-shrink: 0;
background-color: $bg-color-hover;
}
.course-info-wrap {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: $spacing-sm $spacing-md;
}
.course-title-row {
display: flex;
justify-content: space-between;
gap: $spacing-sm;
}
.course-name {
flex: 1;
color: $text-color-main;
font-size: 26rpx;
font-weight: 600;
line-height: 1.3;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.course-time {
color: $text-color-muted;
font-size: 22rpx;
font-weight: 500;
}
.course-time.highlight-blue {
color: $color-primary;
font-weight: 600;
}
.course-bottom-meta {
display: flex;
align-items: center;
gap: $spacing-xl;
}
.course-meta-text {
color: $text-color-muted;
font-size: 22rpx;
}
.activity-cover {
width: 180rpx;
height: 130rpx;
background-color: $bg-color-hover;
}
.activity-info {
display: flex;
flex: 1;
flex-direction: column;
justify-content: space-between;
padding: $spacing-sm $spacing-md;
}
.activity-title {
display: block;
color: $text-color-main;
font-size: 26rpx;
font-weight: 600;
line-height: 1.3;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.activity-date {
color: $text-color-light;
font-size: 20rpx;
}
.empty-placeholder {
padding: $spacing-xl 0;
color: $text-color-light;
font-size: 24rpx;
text-align: center;
}
</style>