5 changed files with 641 additions and 62 deletions
@ -0,0 +1,552 @@ |
|||||
|
<template> |
||||
|
<view class="coupon-list-container"> |
||||
|
<!-- 状态筛选 --> |
||||
|
<view class="filter-tabs"> |
||||
|
<view |
||||
|
class="tab-item" |
||||
|
:class="[{ active: activeTab === 'all' }]" |
||||
|
@click="switchTab('all')" |
||||
|
> |
||||
|
全部 |
||||
|
</view> |
||||
|
<view |
||||
|
class="tab-item" |
||||
|
:class="[{ active: activeTab === 'unused' }]" |
||||
|
@click="switchTab('unused')" |
||||
|
> |
||||
|
未使用 |
||||
|
</view> |
||||
|
<view |
||||
|
class="tab-item" |
||||
|
:class="[{ active: activeTab === 'used' }]" |
||||
|
@click="switchTab('used')" |
||||
|
> |
||||
|
已使用 |
||||
|
</view> |
||||
|
<view |
||||
|
class="tab-item" |
||||
|
:class="[{ active: activeTab === 'expired' }]" |
||||
|
@click="switchTab('expired')" |
||||
|
> |
||||
|
已过期 |
||||
|
</view> |
||||
|
</view> |
||||
|
<!-- 优惠券列表 --> |
||||
|
<view class="coupon-list"> |
||||
|
<view |
||||
|
v-for="(coupon, index) in filteredCoupons" |
||||
|
:key="index" |
||||
|
class="coupon-item" |
||||
|
:class="[ |
||||
|
{ |
||||
|
used: coupon.status === 1, |
||||
|
expired: coupon.status === 2, |
||||
|
}, |
||||
|
]" |
||||
|
> |
||||
|
<!-- 优惠券主体 --> |
||||
|
<view class="coupon-main"> |
||||
|
<!-- 左侧金额区域 --> |
||||
|
<view class="coupon-amount"> |
||||
|
<view class="amount-value"> |
||||
|
<text class="currency">¥</text> |
||||
|
<text class="value">{{ formatAmount(coupon) }}</text> |
||||
|
</view> |
||||
|
<view class="amount-desc" v-if="coupon.minAmount > 0"> |
||||
|
满{{ coupon.minAmount }}可用 |
||||
|
</view> |
||||
|
<view class="amount-desc" v-else> 无门槛 </view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 右侧信息区域 --> |
||||
|
<view class="coupon-info"> |
||||
|
<view class="coupon-type">{{ |
||||
|
getCouponTypeName(coupon.type) |
||||
|
}}</view> |
||||
|
<view class="coupon-scope" v-if="coupon.scope === 0"> |
||||
|
全场通用 |
||||
|
</view> |
||||
|
<view class="coupon-scope" v-else> |
||||
|
<view class="scope-title" @click="toggleProductList(coupon.id)"> |
||||
|
指定商品可用 |
||||
|
<text |
||||
|
class="expand-icon" |
||||
|
:class="{ expanded: coupon.showProducts }" |
||||
|
>▼</text |
||||
|
> |
||||
|
</view> |
||||
|
<view class="product-list" v-if="coupon.showProducts"> |
||||
|
<view |
||||
|
class="product-item" |
||||
|
v-for="product in coupon.products" |
||||
|
:key="product.id" |
||||
|
> |
||||
|
{{ product.name }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 状态标识 --> |
||||
|
<view class="coupon-status"> |
||||
|
<view class="status-tag" :class="[getStatusClass(coupon.status)]"> |
||||
|
{{ getStatusText(coupon.status) }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 有效期和使用按钮 --> |
||||
|
<view class="coupon-bottom"> |
||||
|
<view class="coupon-validity"> |
||||
|
<text class="validity-label">有效期:</text> |
||||
|
<text class="validity-date" |
||||
|
>{{ coupon.startDate }} - {{ coupon.endDate }}</text |
||||
|
> |
||||
|
</view> |
||||
|
<view class="coupon-action" v-if="coupon.status === 0"> |
||||
|
<button class="use-btn" @click="useCoupon(coupon)">立即使用</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 空状态 --> |
||||
|
<view class="empty-state" v-if="filteredCoupons.length === 0"> |
||||
|
<view class="empty-icon">📋</view> |
||||
|
<view class="empty-text">暂无优惠券</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
activeTab: "all", |
||||
|
coupons: [ |
||||
|
{ |
||||
|
id: 1, |
||||
|
type: 1, // 满减券 |
||||
|
amount: 20, |
||||
|
minAmount: 100, |
||||
|
status: 0, // 0:未使用 1:已使用 2:已过期 |
||||
|
startDate: "2024-01-01", |
||||
|
endDate: "2024-12-31", |
||||
|
scope: 0, // 0:不限商品 1:指定商品 |
||||
|
showProducts: false, |
||||
|
}, |
||||
|
{ |
||||
|
id: 2, |
||||
|
type: 2, // 折扣券 |
||||
|
discount: 8.5, // 8.5折 |
||||
|
minAmount: 50, |
||||
|
status: 1, |
||||
|
startDate: "2024-01-01", |
||||
|
endDate: "2024-06-30", |
||||
|
scope: 1, |
||||
|
showProducts: false, |
||||
|
products: [ |
||||
|
{ id: 1, name: "iPhone 15 Pro" }, |
||||
|
{ id: 2, name: "MacBook Air M2" }, |
||||
|
{ id: 3, name: "AirPods Pro" }, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
id: 3, |
||||
|
type: 3, // 立减券 |
||||
|
amount: 10, |
||||
|
minAmount: 0, |
||||
|
status: 2, |
||||
|
startDate: "2023-12-01", |
||||
|
endDate: "2023-12-31", |
||||
|
scope: 0, |
||||
|
showProducts: false, |
||||
|
}, |
||||
|
{ |
||||
|
id: 4, |
||||
|
type: 4, // 兑换券 |
||||
|
amount: 0, |
||||
|
minAmount: 0, |
||||
|
status: 0, |
||||
|
startDate: "2024-01-01", |
||||
|
endDate: "2024-12-31", |
||||
|
scope: 1, |
||||
|
showProducts: false, |
||||
|
products: [ |
||||
|
{ id: 4, name: "星巴克咖啡券" }, |
||||
|
{ id: 5, name: "肯德基套餐券" }, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
}, |
||||
|
computed: { |
||||
|
filteredCoupons() { |
||||
|
if (this.activeTab === "all") { |
||||
|
return this.coupons; |
||||
|
} |
||||
|
if (this.activeTab === "unused") { |
||||
|
return this.coupons.filter((coupon) => coupon.status === 0); |
||||
|
} |
||||
|
if (this.activeTab === "used") { |
||||
|
return this.coupons.filter((coupon) => coupon.status === 1); |
||||
|
} |
||||
|
if (this.activeTab === "expired") { |
||||
|
return this.coupons.filter((coupon) => coupon.status === 2); |
||||
|
} |
||||
|
return []; |
||||
|
}, |
||||
|
}, |
||||
|
mounted() { |
||||
|
console.log("couponList mounted"); |
||||
|
console.log("activeTab:", this.activeTab); |
||||
|
console.log("coupons:", this.coupons); |
||||
|
console.log("filteredCoupons:", this.filteredCoupons); |
||||
|
}, |
||||
|
methods: { |
||||
|
switchTab(tab) { |
||||
|
this.activeTab = tab; |
||||
|
}, |
||||
|
getCouponTypeName(type) { |
||||
|
const typeMap = { |
||||
|
1: "满减券", |
||||
|
2: "折扣券", |
||||
|
3: "立减券", |
||||
|
4: "兑换券", |
||||
|
}; |
||||
|
return typeMap[type] || "未知类型"; |
||||
|
}, |
||||
|
formatAmount(coupon) { |
||||
|
if (coupon.type === 2) { |
||||
|
// 折扣券显示折扣 |
||||
|
return coupon.discount + "折"; |
||||
|
} else if (coupon.type === 4) { |
||||
|
// 兑换券 |
||||
|
return "兑换"; |
||||
|
} else { |
||||
|
// 满减券和立减券显示金额 |
||||
|
return coupon.amount; |
||||
|
} |
||||
|
}, |
||||
|
getStatusText(status) { |
||||
|
const statusMap = { |
||||
|
0: "未使用", |
||||
|
1: "已使用", |
||||
|
2: "已过期", |
||||
|
}; |
||||
|
return statusMap[status] || "未知状态"; |
||||
|
}, |
||||
|
getStatusClass(status) { |
||||
|
const classMap = { |
||||
|
0: "unused", |
||||
|
1: "used", |
||||
|
2: "expired", |
||||
|
}; |
||||
|
return classMap[status] || ""; |
||||
|
}, |
||||
|
useCoupon(coupon) { |
||||
|
// 跳转到商品页面或购物车 |
||||
|
uni.showToast({ |
||||
|
title: "跳转到商品页面", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
}, |
||||
|
toggleProductList(couponId) { |
||||
|
console.log("toggleProductList called with couponId:", couponId); |
||||
|
const couponIndex = this.coupons.findIndex((c) => c.id === couponId); |
||||
|
console.log("found coupon index:", couponIndex); |
||||
|
if (couponIndex !== -1) { |
||||
|
const newShowProducts = !this.coupons[couponIndex].showProducts; |
||||
|
console.log( |
||||
|
"toggling showProducts from", |
||||
|
this.coupons[couponIndex].showProducts, |
||||
|
"to", |
||||
|
newShowProducts |
||||
|
); |
||||
|
// 使用 Vue.set 确保响应式更新 |
||||
|
this.$set(this.coupons[couponIndex], "showProducts", newShowProducts); |
||||
|
console.log( |
||||
|
"after toggle, showProducts is:", |
||||
|
this.coupons[couponIndex].showProducts |
||||
|
); |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
onLoad() { |
||||
|
// 页面加载时获取优惠券数据 |
||||
|
// this.loadCoupons(); |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.coupon-list-container { |
||||
|
min-height: 100vh; |
||||
|
background-color: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
background: #fff; |
||||
|
padding: 20rpx 30rpx; |
||||
|
border-bottom: 1rpx solid #eee; |
||||
|
|
||||
|
.header-title { |
||||
|
font-size: 36rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
text-align: center; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.filter-tabs { |
||||
|
display: flex; |
||||
|
background: #fff; |
||||
|
padding: 0 30rpx; |
||||
|
border-bottom: 1rpx solid #eee; |
||||
|
|
||||
|
.tab-item { |
||||
|
flex: 1; |
||||
|
padding: 30rpx 0; |
||||
|
text-align: center; |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
position: relative; |
||||
|
|
||||
|
&.active { |
||||
|
color: #77f3f9; |
||||
|
font-weight: 600; |
||||
|
|
||||
|
&::after { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
width: 60rpx; |
||||
|
height: 4rpx; |
||||
|
background: #77f3f9; |
||||
|
border-radius: 2rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.coupon-list { |
||||
|
padding: 20rpx 30rpx; |
||||
|
} |
||||
|
|
||||
|
.coupon-item { |
||||
|
background: #fff; |
||||
|
border-radius: 16rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
overflow: hidden; |
||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); |
||||
|
position: relative; |
||||
|
|
||||
|
&.used, |
||||
|
&.expired { |
||||
|
opacity: 0.6; |
||||
|
|
||||
|
&::after { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background: rgba(0, 0, 0, 0.1); |
||||
|
pointer-events: none; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.coupon-main { |
||||
|
display: flex; |
||||
|
padding: 30rpx; |
||||
|
position: relative; |
||||
|
|
||||
|
&::after { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
right: 200rpx; |
||||
|
top: 20rpx; |
||||
|
bottom: 20rpx; |
||||
|
width: 2rpx; |
||||
|
background: linear-gradient( |
||||
|
to bottom, |
||||
|
transparent 0%, |
||||
|
#ddd 20%, |
||||
|
#ddd 80%, |
||||
|
transparent 100% |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.coupon-amount { |
||||
|
width: 200rpx; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
|
||||
|
.amount-value { |
||||
|
display: flex; |
||||
|
align-items: baseline; |
||||
|
margin-bottom: 10rpx; |
||||
|
|
||||
|
.currency { |
||||
|
font-size: 24rpx; |
||||
|
color: #ff4d4f; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
.value { |
||||
|
font-size: 48rpx; |
||||
|
color: #ff4d4f; |
||||
|
font-weight: 700; |
||||
|
margin-left: 4rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.amount-desc { |
||||
|
font-size: 22rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.coupon-info { |
||||
|
flex: 1; |
||||
|
padding-left: 30rpx; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
|
||||
|
.coupon-type { |
||||
|
font-size: 32rpx; |
||||
|
color: #333; |
||||
|
font-weight: 600; |
||||
|
margin-bottom: 12rpx; |
||||
|
} |
||||
|
|
||||
|
.coupon-scope { |
||||
|
font-size: 24rpx; |
||||
|
color: #666; |
||||
|
margin-bottom: 8rpx; |
||||
|
} |
||||
|
|
||||
|
.coupon-scope { |
||||
|
.scope-title { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
.expand-icon { |
||||
|
margin-left: 8rpx; |
||||
|
font-size: 20rpx; |
||||
|
transition: transform 0.3s ease; |
||||
|
|
||||
|
&.expanded { |
||||
|
transform: rotate(180deg); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.product-list { |
||||
|
margin-top: 8rpx; |
||||
|
padding: 8rpx 12rpx; |
||||
|
background: #f8f8f8; |
||||
|
border-radius: 8rpx; |
||||
|
|
||||
|
.product-item { |
||||
|
font-size: 20rpx; |
||||
|
color: #666; |
||||
|
line-height: 1.5; |
||||
|
margin-bottom: 4rpx; |
||||
|
|
||||
|
&:last-child { |
||||
|
margin-bottom: 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.coupon-status { |
||||
|
position: absolute; |
||||
|
top: 20rpx; |
||||
|
right: 20rpx; |
||||
|
|
||||
|
.status-tag { |
||||
|
padding: 8rpx 16rpx; |
||||
|
border-radius: 20rpx; |
||||
|
font-size: 20rpx; |
||||
|
color: #fff; |
||||
|
|
||||
|
&.unused { |
||||
|
background: #52c41a; |
||||
|
} |
||||
|
|
||||
|
&.used { |
||||
|
background: #999; |
||||
|
} |
||||
|
|
||||
|
&.expired { |
||||
|
background: #ff4d4f; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.coupon-bottom { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 20rpx 30rpx; |
||||
|
border-top: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
.coupon-validity { |
||||
|
flex: 1; |
||||
|
font-size: 22rpx; |
||||
|
color: #999; |
||||
|
|
||||
|
.validity-label { |
||||
|
margin-right: 8rpx; |
||||
|
} |
||||
|
|
||||
|
.validity-date { |
||||
|
line-height: 1.4; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.coupon-action { |
||||
|
.use-btn { |
||||
|
width: 160rpx; |
||||
|
height: 60rpx; |
||||
|
background: linear-gradient(135deg, #fffdb7 0%, #97fffa 100%); |
||||
|
color: #000; |
||||
|
border: none; |
||||
|
border-radius: 20rpx; |
||||
|
font-size: 24rpx; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.empty-state { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
padding: 120rpx 0; |
||||
|
|
||||
|
.empty-icon { |
||||
|
font-size: 120rpx; |
||||
|
margin-bottom: 30rpx; |
||||
|
opacity: 0.3; |
||||
|
} |
||||
|
|
||||
|
.empty-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue