Files
blind-select/frontend-app/pages/coupon/list.vue
T
admin 06488f0237 Initial commit: 帮我选盲选应用
功能:
- Go后端 (Gin + GORM + PostgreSQL)
- UniApp用户端 (iOS/Android/小程序)
- DaisyUI5后台管理
- JWT认证 + 微信登录
- 盲选加权算法
- 会员系统 + 优惠券
- 打分评价 + 偏好学习
2026-06-08 20:18:31 +00:00

155 lines
3.9 KiB
Vue

<template>
<view class="page-coupon">
<view class="header">
<text class="title">🎫 我的优惠券</text>
</view>
<!-- Tab切换 -->
<view class="tabs">
<view class="tab" :class="{ active: activeTab === 'all' }" @click="activeTab = 'all'">全部</view>
<view class="tab" :class="{ active: activeTab === 'available' }" @click="activeTab = 'available'">未使用</view>
<view class="tab" :class="{ active: activeTab === 'used' }" @click="activeTab = 'used'">已使用</view>
</view>
<!-- 优惠券列表 -->
<view class="coupon-list">
<view class="coupon-card" v-for="coupon in filteredCoupons" :key="coupon.id">
<view class="coupon-left">
<text class="coupon-value">¥{{ coupon.value }}</text>
<text class="coupon-min" v-if="coupon.min_amount">{{ coupon.min_amount }}可用</text>
</view>
<view class="coupon-right">
<text class="coupon-shop">{{ coupon.merchant_name || '指定商家' }}</text>
<text class="coupon-code">{{ coupon.user_code || coupon.pool_code }}</text>
<view class="coupon-status" :class="coupon.status">
{{ statusText(coupon.status) }}
</view>
</view>
</view>
</view>
<view class="empty" v-if="filteredCoupons.length === 0">
<text class="empty-icon">🎫</text>
<text class="empty-text">暂无优惠券</text>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
const activeTab = ref('all')
const coupons = ref([
{ id: 1, value: 15, min_amount: 80, merchant_name: '松阪牛料理', user_code: 'UCP1234567890', status: 'available', valid_end: '2026-07-01' },
{ id: 2, value: 20, min_amount: 100, merchant_name: '渝味晓宇火锅', user_code: 'UCP0987654321', status: 'available', valid_end: '2026-06-20' },
{ id: 3, value: 30, min_amount: 200, merchant_name: 'Bistro', user_code: 'UCP1122334455', status: 'used', status_text: '已使用' },
])
const filteredCoupons = computed(() => {
if (activeTab.value === 'all') return coupons.value
return coupons.value.filter(c => c.status === activeTab.value)
})
function statusText(status) {
const map = { available: '未使用', claimed: '未使用', used: '已使用', expired: '已过期' }
return map[status] || status
}
</script>
<style lang="scss" scoped>
.page-coupon {
min-height: 100vh;
background: #f5f5f5;
}
.header {
background: linear-gradient(135deg, #FF6B35, #FF8C42);
padding: 80rpx 30rpx 30rpx;
color: #fff;
.title { font-size: 36rpx; font-weight: 700; }
}
.tabs {
display: flex;
background: #fff;
margin-bottom: 16rpx;
.tab {
flex: 1;
text-align: center;
padding: 20rpx 0;
font-size: 26rpx;
color: #666;
border-bottom: 3rpx solid transparent;
&.active {
color: #FF6B35;
border-bottom-color: #FF6B35;
}
}
}
.coupon-list {
padding: 0 24rpx;
}
.coupon-card {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 16rpx;
display: flex;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
}
.coupon-left {
width: 160rpx;
text-align: center;
border-right: 2rpx dashed #eee;
margin-right: 20rpx;
.coupon-value {
font-size: 40rpx;
font-weight: 700;
color: #FF6B35;
display: block;
}
.coupon-min {
font-size: 20rpx;
color: #999;
margin-top: 4rpx;
display: block;
}
}
.coupon-right {
flex: 1;
.coupon-shop {
font-size: 26rpx;
font-weight: 600;
display: block;
}
.coupon-code {
font-size: 20rpx;
color: #999;
margin-top: 8rpx;
display: block;
}
}
.coupon-status {
font-size: 20rpx;
padding: 2rpx 12rpx;
border-radius: 8rpx;
margin-top: 8rpx;
display: inline-block;
&.available { background: #E8F5E9; color: #4CAF50; }
&.used { background: #f0f0f0; color: #999; }
}
.empty {
text-align: center;
padding: 100rpx 0;
.empty-icon { font-size: 80rpx; display: block; }
.empty-text { font-size: 26rpx; color: #999; }
}
</style>