06488f0237
功能: - Go后端 (Gin + GORM + PostgreSQL) - UniApp用户端 (iOS/Android/小程序) - DaisyUI5后台管理 - JWT认证 + 微信登录 - 盲选加权算法 - 会员系统 + 优惠券 - 打分评价 + 偏好学习
155 lines
3.9 KiB
Vue
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>
|