Files
yxe-mp/packageUser/coupon/index.vue
T
2026-09-29 15:17:13 +08:00

300 lines
7.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="coupon-page">
<view class="page-hero">
<AppNavbar title="优惠券中心" show-back/>
<view class="intro-card">
<view class="card-title">
<view class="title-bar"></view>
<text>优惠券中心</text>
</view>
<text class="intro-text">领券大厅与我的优惠券</text>
</view>
</view>
<view class="card subsection">
<view class="tabs">
<view
v-for="tab in tabs"
:key="tab.value"
:class="['tab', activeTab === tab.value ? 'active' : '']"
@tap="changeTab(tab.value)"
>
{{ tab.label }}
</view>
</view>
</view>
<view class="card block">
<view class="section-title">{{ activeTab === 'lobby' ? '领券大厅' : '我的优惠券' }}</view>
<view v-if="loading" class="empty">加载中...</view>
<view v-else-if="currentCoupons.length === 0" class="empty">暂无优惠券</view>
<view v-else class="coupon-list">
<view class="coupon-card" v-for="coupon in currentCoupons" :key="coupon.id">
<view class="coupon-main">
<!-- <view class="coupon-amount">¥{{ coupon.amount }}</view>-->
<view class="coupon-info">
<view class="coupon-title">{{ coupon.title }}</view>
<!-- <view class="coupon-meta">{{ coupon.desc }}</view>-->
<view class="coupon-meta">
有效期:{{ coupon.expireType === 1 ? coupon.expireEndDate : `领取后${coupon.expireDay}天过期` }}
</view>
</view>
</view>
<view v-if="activeTab === 'lobby'" class="coupon-action">
<view class="primary-btn" @tap="receiveCoupon(coupon)">领取</view>
</view>
<view v-else class="coupon-status">{{ coupon.statusText }}</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {couponListReq, userCouponAddReq, userCouponListReq} from "@/api/coupon";
import AppNavbar from "@/components/AppNavbar.vue";
export default {
components: {AppNavbar},
data() {
return {
tabs: [
{label: '领券大厅', value: 'lobby'},
{label: '我的优惠券', value: 'mine'}
],
activeTab: 'lobby',
lobbyCoupons: [],
myCoupons: [],
loading: false
}
},
computed: {
currentCoupons() {
return this.activeTab === 'lobby' ? this.lobbyCoupons : this.myCoupons
}
},
onShow() {
this.fetchCoupons()
},
methods: {
changeTab(value) {
this.activeTab = value
this.fetchCoupons()
},
async fetchCoupons() {
this.loading = true
try {
if (this.activeTab === 'lobby') {
const {data} = await couponListReq()
const list = Array.isArray(data) ? data : (data && data.list ? data.list : [])
this.lobbyCoupons = list.map(this.normalizeCoupon)
} else {
const {data} = await userCouponListReq()
const list = Array.isArray(data) ? data : (data && data.list ? data.list : [])
this.myCoupons = list.map(this.normalizeUserCoupon)
}
} catch (err) {
uni.showToast({
title: '加载失败',
icon: 'none'
})
} finally {
this.loading = false
}
},
normalizeCoupon(item) {
const amount = Number(item.amount || item.faceValue || item.money || 0)
return {
id: item.id || item.couponId || item.coupon_id,
amount: amount.toFixed(2),
title: item.title || item.name || '优惠券',
desc: item.desc || item.description || item.useRule || '无门槛使用',
expire: item.expire || item.expireTime || item.endTime || '-',
expireType: item.expireType,
expireEndDate: item.expireEndDate,
expireDay: item.expireDay,
}
},
normalizeUserCoupon(item) {
const amount = Number(item.amount || item.faceValue || item.money || 0)
const statusValue = Number(item.used || item.status)
let statusText = '未使用'
if (statusValue === 1) statusText = '已使用'
if (statusValue === 2) statusText = '已过期'
return {
id: item.id || item.userCouponId || item.couponId,
amount: amount.toFixed(2),
title: item.coupon.title || item.name || '优惠券',
desc: item.desc || item.description || item.useRule || '无门槛使用',
expire: item.expire || item.expireTime || item.endTime || '-',
statusText,
expireType: item.coupon.expireType,
expireEndDate: item.coupon.expireEndDate,
expireDay: item.coupon.expireDay,
}
},
async receiveCoupon(coupon) {
if (!coupon.id) {
uni.showToast({
title: '缺少优惠券ID',
icon: 'none'
})
return
}
const res = await userCouponAddReq({
couponId: coupon.id
}).catch(e => {
uni.showToast({
title: e.message,
icon: 'none'
})
})
if (res) {
uni.showToast({
title: '领取成功',
icon: 'success'
})
this.fetchCoupons()
}
}
}
}
</script>
<style lang="scss" scoped>
.coupon-page {
min-height: 100vh;
//padding: 0 20rpx 40rpx;
background: #f5f5f5;
}
.page-hero {
//padding: 30rpx 6rpx 18rpx;
background: url('https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/462bfa04cf0eff8698884c38b9d17519.png') no-repeat top center / 100% auto;
}
.page-navbar {
padding: 0 6rpx;
}
.intro-card {
margin: 18rpx 20rpx 0;
padding: 20rpx 18rpx;
border-radius: 20rpx;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.08);
}
.card-title {
display: flex;
align-items: center;
gap: 12rpx;
font-size: 28rpx;
font-weight: 700;
color: #1f2937;
}
.title-bar {
width: 6rpx;
height: 30rpx;
border-radius: 999rpx;
background: #2fc6a7;
}
.intro-text {
margin-top: 12rpx;
font-size: 26rpx;
color: #6b7280;
line-height: 1.6;
}
.subsection {
margin: 18rpx 20rpx 0;
}
.tabs {
display: flex;
gap: 12rpx;
}
.tab {
padding: 10rpx 18rpx;
border-radius: 999rpx;
background: #f5f8ff;
color: var(--text-sub);
font-size: 24rpx;
border: 1rpx solid #e1e8f5;
}
.tab.active {
color: #ffffff;
background: var(--brand-primary);
border-color: var(--brand-primary);
}
.block {
margin: 18rpx 20rpx 0;
}
.coupon-list {
display: flex;
flex-direction: column;
gap: 14rpx;
}
.coupon-card {
border: 1rpx solid #e7eef8;
border-radius: 16rpx;
padding: 16rpx;
background: #ffffff;
}
.coupon-main {
display: flex;
align-items: center;
gap: 14rpx;
}
.coupon-amount {
font-size: 34rpx;
font-weight: 800;
color: #ff3b30;
min-width: 110rpx;
text-align: center;
}
.coupon-info {
flex: 1;
}
.coupon-title {
font-weight: 700;
color: var(--text-main);
}
.coupon-meta {
color: var(--text-sub);
font-size: 24rpx;
margin-top: 4rpx;
}
.coupon-action {
margin-top: 12rpx;
display: flex;
justify-content: flex-end;
}
.coupon-status {
margin-top: 12rpx;
color: var(--text-sub);
font-size: 24rpx;
text-align: right;
}
.empty {
color: var(--text-sub);
text-align: center;
padding: 16rpx 0;
}
</style>