300 lines
7.2 KiB
Vue
300 lines
7.2 KiB
Vue
<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>
|