Zuncle 2895c2d5b7 fix(activity): 完善福利活动前台展示与参与体验
补齐福利活动前台页面与请求接入,优化奖品展示、参与进度、中奖概览与无图占位文案。
同时修复奖品文字重叠问题,提升福利活动详情页的可读性。
2026-04-29 17:22:05 +08:00

109 lines
4.9 KiB
Vue

<template>
<view class="welfare-list-page">
<view class="page-head">
<text class="page-title">{{ mode === 'finished' ? '往期活动' : '福利活动' }}</text>
<text class="page-subtitle">{{ mode === 'finished' ? '查看已结束活动' : '当前仅展示进行中的活动' }}</text>
</view>
<view class="toolbar">
<view class="toolbar-btn" :class="{ active: mode === 'active' }" @tap="switchMode('active')">进行中</view>
<view class="toolbar-btn" :class="{ active: mode === 'finished' }" @tap="switchMode('finished')">往期活动</view>
</view>
<view v-if="loading" class="state">加载中...</view>
<view v-else-if="activities.length === 0" class="state">{{ mode === 'finished' ? '暂无往期活动' : '暂无进行中的活动' }}</view>
<view v-else class="activity-grid">
<view v-for="item in activities" :key="item.id" class="activity-card" @tap="goDetail(item.id)">
<image v-if="item.cover_image" class="activity-cover" :src="item.cover_image" mode="aspectFill" />
<view v-else class="activity-cover empty">暂无图片</view>
<view class="activity-meta">
<text class="activity-name">{{ item.title }}</text>
<view class="activity-type-row">
<text class="activity-type" :class="typeClass(item.type)">{{ typeLabel(item.type) }}</text>
<text class="activity-status" :class="mode === 'finished' ? 'status-finished' : 'status-active'">
{{ mode === 'finished' ? '已结束' : '进行中' }}
</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { request } from '@/utils/request.js'
export default {
data() {
return {
loading: false,
mode: 'active',
activities: []
}
},
onLoad(options) {
this.mode = options?.mode === 'finished' ? 'finished' : 'active'
this.loadData()
},
methods: {
async loadData() {
this.loading = true
try {
const status = this.mode === 'finished' ? 'finished' : 'active'
const res = await request({ url: `/api/app/welfare-activities?status=${status}&page=1&page_size=50` })
this.activities = Array.isArray(res?.list) ? res.list : []
} catch (e) {
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
} finally {
this.loading = false
}
},
switchMode(mode) {
if (this.mode === mode) return
this.mode = mode
this.loadData()
},
goDetail(id) {
uni.navigateTo({ url: `/pages-activity/activity/welfare/detail?id=${id}` })
},
typeLabel(type) {
return { daily: '每日福利', weekly: '每周福利', monthly: '每月福利' }[type] || '福利活动'
},
typeClass(type) {
return {
daily: 'type-daily',
weekly: 'type-weekly',
monthly: 'type-monthly'
}[type] || 'type-default'
}
}
}
</script>
<style lang="scss">
.welfare-list-page { min-height: 100vh; padding: 28rpx; background: #fff7ed; }
.page-head { margin-bottom: 28rpx; }
.page-title { display: block; font-size: 46rpx; font-weight: 900; color: #1f2937; }
.page-subtitle { display: block; margin-top: 10rpx; font-size: 24rpx; color: #9ca3af; }
.toolbar { display: flex; gap: 16rpx; margin-bottom: 28rpx; }
.toolbar-btn { flex: 1; text-align: center; padding: 20rpx 0; background: #fff; border-radius: 999rpx; color: #9a5b24; font-weight: 800; }
.toolbar-btn.active { background: #ff8a3d; color: #fff; }
.state { padding: 120rpx 0; text-align: center; color: #9ca3af; }
.activity-grid { display: flex; flex-direction: column; gap: 24rpx; }
.activity-card { display: flex; overflow: hidden; border-radius: 28rpx; background: #fff; box-shadow: 0 12rpx 30rpx rgba(0,0,0,.06); min-height: 220rpx; }
.activity-cover { width: 240rpx; height: 220rpx; display: block; background: #f3f4f6; flex-shrink: 0; }
.activity-cover.empty { display: flex; align-items: center; justify-content: center; color: #9ca3af; }
.activity-meta { flex: 1; padding: 24rpx 22rpx; display: flex; flex-direction: column; justify-content: space-between; min-width: 0; }
.activity-name { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-size: 30rpx; font-weight: 800; color: #1f2937; line-height: 1.4; }
.activity-type-row { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; margin-top: 12rpx; flex-wrap: wrap; }
.activity-type { display: inline-flex; align-items: center; padding: 8rpx 18rpx; border-radius: 999rpx; font-size: 22rpx; font-weight: 800; }
.type-daily { background: rgba(249, 115, 22, .12); color: #f97316; }
.type-weekly { background: rgba(239, 68, 68, .12); color: #ef4444; }
.type-monthly { background: linear-gradient(135deg, #a855f7, #ec4899, #f59e0b); color: #fff; }
.type-default { background: rgba(148, 163, 184, .12); color: #64748b; }
.activity-status { font-size: 22rpx; font-weight: 700; }
.status-active { color: #10b981; }
.status-finished { color: #94a3b8; }
</style>