peixue-dev/peidu/uniapp/user-package/pages/coupon/center.vue

335 lines
7.7 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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-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>