Files
frontend-app/pages/other_package/coupon/coupon.vue
T
2026-08-17 11:32:40 +08:00

350 lines
7.4 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="content">
<TopSafe></TopSafe>
<Header title="优惠券" />
<!-- 顶部分类 Tab 栏 -->
<view class="tab-container">
<view
v-for="(item, index) in tabs"
:key="index"
class="tab-item"
:class="{ active: currentTab === index }"
@click="switchTab(index)"
>
<text class="tab-text">{{ item }}</text>
<view class="active-line" v-if="currentTab === index"></view>
</view>
</view>
<!-- 优惠券列表区域 -->
<view class="coupon-list">
<view
v-for="(coupon, index) in filteredCoupons"
:key="index"
class="coupon-card"
:class="{ 'disabled': coupon.status === 'expired' }"
>
<!-- 左侧:金额与门槛 -->
<view class="card-left">
<view class="price-box">
<text class="currency">¥</text>
<text class="amount">{{ coupon.amount }}</text>
</view>
<text class="condition">{{ coupon.condition }}</text>
</view>
<!-- 带有上下半圆凹槽的虚线分割线 -->
<view class="divider-wrapper">
<view class="notch top-notch"></view>
<view class="divider-line"></view>
<view class="notch bottom-notch"></view>
</view>
<!-- 右侧:详细内容 -->
<view class="card-right">
<view class="info-content">
<view class="title">{{ coupon.title }}</view>
<view class="description">{{ coupon.description }}</view>
<!-- 状态/倒计时文本 -->
<view v-if="coupon.status === 'active'" class="countdown">
仅剩 {{ coupon.timeLeft }}
</view>
<view v-else class="expired-text">
已失效
</view>
</view>
<!-- 按钮:仅在有效状态下显示 -->
<view v-if="coupon.status === 'active'" class="use-btn" @click="useCoupon(coupon)">
使用
</view>
</view>
</view>
</view>
<up-toast ref="uToastRef"></up-toast>
<qiaobao-assistant page-key="pages/other_package/coupon/coupon" title="优惠券" />
</view>
</template>
<script>
import Header from '@/components/common/header.vue';
import TopSafe from '@/components/common/top-safe.nvue'
import MyBtn from '@/components/common/my-btn.vue'
export default {
components: { Header, TopSafe, MyBtn },
data() {
return {
currentTab: 0,
tabs: ['全部', '可使用', '已失效'],
coupons: [
{
amount: 12,
condition: '无门槛',
title: '限时秒杀优惠券',
description: '云南白药牙膏儿膏儿膏儿...',
timeLeft: '14:20:55',
status: 'active'
},
{
amount: 8,
condition: '无门槛',
title: '限时秒杀优惠券',
description: '云南白药牙膏儿膏儿膏儿...',
timeLeft: '14:20:55',
status: 'active'
},
{
amount: 12,
condition: '无门槛',
title: '限时秒杀优惠券',
description: '牛肉干儿牛肉干儿牛肉干',
timeLeft: '',
status: 'expired'
}
]
};
},
computed: {
filteredCoupons() {
return this.coupons;
}
},
methods: {
switchTab(index) {
this.currentTab = index;
},
useCoupon(coupon) {
uni.showToast({
title: `去使用 ${coupon.amount} 元券`,
icon: 'none'
});
}
}
}
</script>
<style lang="scss" scoped>
.content {
background-color: #F5F5F5;
min-height: 100vh;
}
.tab-container {
display: flex;
width: 100%;
background-color: #ffffff;
height: 88rpx;
align-items: center;
padding-left: 28rpx; /* 关键:左侧对齐优惠券卡片的边距 */
box-sizing: border-box;
border-top: 2rpx solid #f6f6f6; /* 隐约的底部分割线 */
.tab-item {
margin-right: 48rpx; /* 增大字与字之间的间距 */
position: relative;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
.tab-text {
font-size: 28rpx;
color: #7f7f7f; /* 未激活时是略深一点的灰色 */
transition: all 0.2s ease;
}
&.active {
.tab-text {
color: #7A35F6; /* 完美还原原图中的亮紫色 */
font-weight: bold;
}
}
/* 底部指示线:缩短宽度并适当下移 */
.active-line {
position: absolute;
bottom: 4rpx; /* 贴近底部边缘 */
width: 44rpx; /* 缩短下划线宽度,原图横线比“全部”两个字还要窄一点 */
height: 4rpx; /* 适中的粗细 */
background-color: #7A35F6;
border-radius: 2rpx;
}
}
}
.coupon-list {
padding: 28rpx 28rpx;
box-sizing: border-box;
display: flex;
background-color: #ffffff;
flex-direction: column;
gap: 32rpx;
}
.coupon-card {
background: rgba(102,102,102,0.06);
border-radius: 16rpx;
display: flex;
height: 196rpx;
position: relative;
/* 左侧面:金额区 */
.card-left {
width: 190rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-shrink: 0;
.price-box {
display: flex;
align-items: flex-end;
color: #ff1224;
font-weight: bold;
margin-bottom: 10rpx;
.currency {
font-size: 32rpx;
margin-right: 2rpx;
}
.amount {
font-size: 64rpx;
line-height: 64rpx;
}
}
.condition {
font-size: 24rpx;
color: #ff1224;
margin-top: 10rpx;
}
}
/* 带有上下半圆凹槽的虚线分割线组件 */
.divider-wrapper {
width: 2rpx;
position: relative;
margin: 10rpx 0;
display: flex;
justify-content: center;
.divider-line {
width: 0;
height: 100%;
border-left: 2rpx dashed rgba(253,28,36,0.3);
}
/* 模拟卡片边缘剪票口的半圆凹槽 */
.notch {
position: absolute;
width: 16rpx;
height: 16rpx;
background-color: #f7f8fa; /* 颜色和页面大背景融为一体 */
border-radius: 50%;
left: 50%;
transform: translateX(-50%);
}
.top-notch {
top: -18rpx;
}
.bottom-notch {
bottom: -18rpx;
}
}
/* 右侧面:内容与按钮区 */
.card-right {
flex: 1;
padding: 26rpx 24rpx 24rpx 36rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
.info-content {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1;
overflow: hidden;
.title {
font-size: 36rpx;
color: #2c2c2c;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.description {
font-size: 28rpx;
color: #6a6a6a;
margin-top: 8rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.countdown {
font-size: 24rpx;
color: #ff5260;
margin-top: 14rpx;
}
}
/* 立即使用按钮 */
.use-btn {
width: 116rpx;
height: 56rpx;
background-color: #FD1C24;
color: #ffffff;
font-size: 28rpx;
border-radius: 8rpx; /* 原图接近微圆角矩形,而非纯半圆 */
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-left: 16rpx;
font-weight: 500;
&:active {
opacity: 0.8;
}
}
}
/* ======= 已失效状态覆盖 ======= */
&.disabled {
background-color: #f4f4f4; /* 换成失效灰底 */
.card-left {
.price-box { color: #9c9c9c; }
.condition { color: #9c9c9c; }
}
.divider-wrapper {
.divider-line { border-left-color: #e2e2e2; }
}
.card-right {
.info-content {
.title { color: #2c2c2c; } /* 失效标题依然清晰 */
.description { color: #9c9c9c; }
}
.expired-text {
font-size: 22rpx;
color: #bcbcbc;
margin-top: 14rpx;
}
}
}
}
</style>