172 lines
3.3 KiB
Vue
172 lines
3.3 KiB
Vue
<template>
|
|
<view class="coupons-page">
|
|
<!-- Tab切换 -->
|
|
<view class="tab-bar">
|
|
<view
|
|
v-for="tab in tabs"
|
|
:key="tab.value"
|
|
class="tab-item"
|
|
:class="{ active: currentTab === tab.value }"
|
|
@click="switchTab(tab.value)"
|
|
>
|
|
<text class="tab-text">{{ t(tab.label) }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 优惠券列表 -->
|
|
<view class="coupon-list">
|
|
<view
|
|
v-for="coupon in coupons"
|
|
:key="coupon.couponId"
|
|
class="coupon-item"
|
|
>
|
|
<CouponCard :coupon="coupon" :redeemed="true" />
|
|
<!-- 状态标识 -->
|
|
<view v-if="coupon.status === 'used'" class="status-badge used">
|
|
<text class="status-text">{{ t('coupons.usedLabel') }}</text>
|
|
</view>
|
|
<view v-if="coupon.status === 'expired'" class="status-badge expired">
|
|
<text class="status-text">{{ t('coupons.expiredLabel') }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view v-if="!loading && coupons.length === 0" class="empty-tip">
|
|
<text>{{ t('common.noMore') }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { getMyCoupons } from '../../api/coupon.js'
|
|
import CouponCard from '../../components/CouponCard.vue'
|
|
|
|
const { t } = useI18n()
|
|
|
|
// Tab配置
|
|
const tabs = [
|
|
{ label: 'coupons.availableTab', value: 'available' },
|
|
{ label: 'coupons.usedTab', value: 'used' },
|
|
{ label: 'coupons.expiredTab', value: 'expired' }
|
|
]
|
|
|
|
const currentTab = ref('available')
|
|
const coupons = ref([])
|
|
const loading = ref(false)
|
|
|
|
// 加载优惠券列表
|
|
async function loadCoupons() {
|
|
loading.value = true
|
|
try {
|
|
const res = await getMyCoupons(currentTab.value)
|
|
coupons.value = res.data || []
|
|
} catch (e) {
|
|
// 错误已统一处理
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 切换Tab
|
|
function switchTab(tab) {
|
|
if (currentTab.value === tab) return
|
|
currentTab.value = tab
|
|
coupons.value = []
|
|
loadCoupons()
|
|
}
|
|
|
|
// 初始加载
|
|
loadCoupons()
|
|
</script>
|
|
|
|
<style scoped>
|
|
.coupons-page {
|
|
min-height: 100vh;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.tab-bar {
|
|
display: flex;
|
|
background-color: #ffffff;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
}
|
|
|
|
.tab-item {
|
|
flex: 1;
|
|
height: 88rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
}
|
|
|
|
.tab-item.active::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 60rpx;
|
|
height: 4rpx;
|
|
background-color: #007aff;
|
|
border-radius: 2rpx;
|
|
}
|
|
|
|
.tab-text {
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.tab-item.active .tab-text {
|
|
color: #007aff;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.coupon-list {
|
|
padding: 20rpx 24rpx;
|
|
}
|
|
|
|
.coupon-item {
|
|
position: relative;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.status-badge {
|
|
position: absolute;
|
|
top: 20rpx;
|
|
right: 20rpx;
|
|
padding: 6rpx 16rpx;
|
|
border-radius: 8rpx;
|
|
}
|
|
|
|
.status-badge.used {
|
|
background-color: rgba(153, 153, 153, 0.15);
|
|
}
|
|
|
|
.status-badge.expired {
|
|
background-color: rgba(255, 59, 48, 0.1);
|
|
}
|
|
|
|
.status-text {
|
|
font-size: 22rpx;
|
|
}
|
|
|
|
.status-badge.used .status-text {
|
|
color: #999;
|
|
}
|
|
|
|
.status-badge.expired .status-text {
|
|
color: #ff3b30;
|
|
}
|
|
|
|
.empty-tip {
|
|
text-align: center;
|
|
padding: 60rpx;
|
|
font-size: 28rpx;
|
|
color: #999;
|
|
}
|
|
</style>
|