335 lines
7.7 KiB
Vue
335 lines
7.7 KiB
Vue
<template>
|
||
<view class="coupon-center-page">
|
||
<!-- 顶部统计 -->
|
||
<view class="header-stats">
|
||
<view class="stat-item" @click="goToMyCoupons">
|
||
<view class="value">{{ myCouponCount }}</view>
|
||
<view class="label">æˆ‘çš„ä¼˜æƒ åˆ?/view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- ä¼˜æƒ åˆ¸åˆ—è¡?-->
|
||
<view class="coupon-list">
|
||
<view class="coupon-item" v-for="item in list" :key="item.id">
|
||
<view class="coupon-left" :class="'type-' + item.type">
|
||
<view class="coupon-amount">
|
||
<text class="symbol">Â¥</text>
|
||
<text class="value">{{ item.amount }}</text>
|
||
</view>
|
||
<view class="coupon-condition">{{ item.condition }}</view>
|
||
</view>
|
||
<view class="coupon-right">
|
||
<view class="coupon-info">
|
||
<view class="coupon-name">{{ item.name }}</view>
|
||
<view class="coupon-desc">{{ item.description }}</view>
|
||
<view class="coupon-time">
|
||
有效� {{ item.startTime }} �{{ item.endTime }}
|
||
</view>
|
||
</view>
|
||
<view class="coupon-action">
|
||
<button
|
||
class="receive-btn"
|
||
:class="{ disabled: item.received || item.stock <= 0 }"
|
||
@click="receiveCoupon(item)"
|
||
:disabled="item.received || item.stock <= 0"
|
||
>
|
||
{{ item.received ? '已领å<E280A0>? : (item.stock <= 0 ? '已抢å…? : 'ç«‹å<E280B9>³é¢†å<E280A0>–') }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- åŠ è½½æ›´å¤š -->
|
||
<view class="load-more" v-if="hasMore">
|
||
<text v-if="loading">åŠ è½½ä¸?..</text>
|
||
<text v-else @click="loadMore">åŠ è½½æ›´å¤š</text>
|
||
</view>
|
||
|
||
<!-- 没有更多 -->
|
||
<view class="no-more" v-if="!hasMore && list.length > 0">
|
||
<text>没有更多�/text>
|
||
</view>
|
||
|
||
<!-- 空状�-->
|
||
<view class="empty" v-if="list.length === 0 && !loading">
|
||
<image class="empty-img" src="/static/images/empty-coupon.png" mode="aspectFit"></image>
|
||
<text class="empty-text">æš‚æ— å<EFBFBD>¯é¢†å<EFBFBD>–çš„ä¼˜æƒ åˆ?/text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { couponApi } from '@/api/index.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
myCouponCount: 0,
|
||
list: [],
|
||
page: 1,
|
||
pageSize: 20,
|
||
hasMore: true,
|
||
loading: false
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.loadMyCouponCount()
|
||
this.loadList()
|
||
},
|
||
onShow() {
|
||
// ä»Žæˆ‘çš„ä¼˜æƒ åˆ¸é¡µé<C2B5>¢è¿”回时刷æ–?
|
||
this.loadMyCouponCount()
|
||
},
|
||
onReachBottom() {
|
||
if (this.hasMore && !this.loading) {
|
||
this.loadMore()
|
||
}
|
||
},
|
||
onPullDownRefresh() {
|
||
this.page = 1
|
||
this.list = []
|
||
this.hasMore = true
|
||
this.loadMyCouponCount()
|
||
this.loadList().then(() => {
|
||
uni.stopPullDownRefresh()
|
||
})
|
||
},
|
||
methods: {
|
||
async loadMyCouponCount() {
|
||
try {
|
||
const res = await couponApi.getMyCouponCount()
|
||
this.myCouponCount = res.data.count || 0
|
||
} catch (e) {
|
||
console.error('åŠ è½½ä¼˜æƒ åˆ¸æ•°é‡<C3A9>失è´?, e)
|
||
}
|
||
},
|
||
async loadList() {
|
||
if (this.loading) return
|
||
|
||
this.loading = true
|
||
try {
|
||
const res = await couponApi.getAvailableCoupons({
|
||
page: this.page,
|
||
pageSize: this.pageSize
|
||
})
|
||
|
||
if (this.page === 1) {
|
||
this.list = res.data.records || []
|
||
} else {
|
||
this.list = [...this.list, ...(res.data.records || [])]
|
||
}
|
||
|
||
this.hasMore = this.list.length < res.data.total
|
||
} catch (e) {
|
||
console.error('åŠ è½½ä¼˜æƒ åˆ¸åˆ—è¡¨å¤±è´?, e)
|
||
uni.showToast({ title: 'åŠ è½½å¤±è´¥', icon: 'none' })
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
loadMore() {
|
||
this.page++
|
||
this.loadList()
|
||
},
|
||
async receiveCoupon(item) {
|
||
if (item.received) {
|
||
uni.showToast({ title: 'å·²ç»<C3A7>领å<E280A0>–过了', icon: 'none' })
|
||
return
|
||
}
|
||
if (item.stock <= 0) {
|
||
uni.showToast({ title: 'ä¼˜æƒ åˆ¸å·²æŠ¢å…‰', icon: 'none' })
|
||
return
|
||
}
|
||
|
||
try {
|
||
uni.showLoading({ title: '领å<E280A0>–ä¸?..' })
|
||
await couponApi.receiveCoupon({ couponId: item.id })
|
||
uni.hideLoading()
|
||
uni.showToast({ title: '领å<E280A0>–æˆ<C3A6>功', icon: 'success' })
|
||
|
||
// 更新状�
|
||
item.received = true
|
||
item.stock--
|
||
this.myCouponCount++
|
||
} catch (e) {
|
||
uni.hideLoading()
|
||
uni.showToast({ title: e.message || '领å<E280A0>–失败', icon: 'none' })
|
||
}
|
||
},
|
||
goToMyCoupons() {
|
||
uni.navigateTo({
|
||
url: '/pages/user/coupon'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.coupon-center-page {
|
||
min-height: 100vh;
|
||
background: #f0f9f7;
|
||
}
|
||
|
||
.header-stats {
|
||
background: linear-gradient(135deg, #5fc9ba 0%, #7dd3c0 100%);
|
||
padding: 60rpx 40rpx;
|
||
|
||
.stat-item {
|
||
text-align: center;
|
||
color: #fff;
|
||
|
||
.value {
|
||
font-size: 60rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.label {
|
||
font-size: 28rpx;
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
}
|
||
|
||
.coupon-list {
|
||
padding: 20rpx;
|
||
|
||
.coupon-item {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
overflow: hidden;
|
||
|
||
.coupon-left {
|
||
width: 200rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 30rpx 20rpx;
|
||
position: relative;
|
||
|
||
&.type-discount {
|
||
background: linear-gradient(135deg, #ff6b6b 0%, #ff8e8e 100%);
|
||
}
|
||
|
||
&.type-cash {
|
||
background: linear-gradient(135deg, #5fc9ba 0%, #7dd3c0 100%);
|
||
}
|
||
|
||
&.type-gift {
|
||
background: linear-gradient(135deg, #ffa726 0%, #ffb74d 100%);
|
||
}
|
||
|
||
&::after {
|
||
content: '';
|
||
position: absolute;
|
||
right: -10rpx;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 20rpx;
|
||
height: 20rpx;
|
||
background: #f0f9f7;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.coupon-amount {
|
||
color: #fff;
|
||
margin-bottom: 10rpx;
|
||
|
||
.symbol {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.value {
|
||
font-size: 56rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
|
||
.coupon-condition {
|
||
color: #fff;
|
||
font-size: 24rpx;
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
|
||
.coupon-right {
|
||
flex: 1;
|
||
padding: 30rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
|
||
.coupon-info {
|
||
.coupon-name {
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.coupon-desc {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.coupon-time {
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.coupon-action {
|
||
margin-top: 20rpx;
|
||
|
||
.receive-btn {
|
||
width: 160rpx;
|
||
height: 60rpx;
|
||
line-height: 60rpx;
|
||
background: linear-gradient(135deg, #5fc9ba 0%, #7dd3c0 100%);
|
||
color: #fff;
|
||
border-radius: 30rpx;
|
||
font-size: 24rpx;
|
||
border: none;
|
||
padding: 0;
|
||
|
||
&.disabled {
|
||
background: #e0e0e0;
|
||
color: #999;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.load-more, .no-more {
|
||
text-align: center;
|
||
padding: 40rpx 0;
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.empty {
|
||
text-align: center;
|
||
padding: 200rpx 0;
|
||
|
||
.empty-img {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.empty-text {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|