vending-machine/mobile/pages/coupons/coupons.vue
2026-04-08 20:45:41 +08:00

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>