consumer-app/pages/profileSub/couponDetail.vue

404 lines
11 KiB
Vue

<template>
<view class="coupon-detail-page">
<view class="header-fixed-wrapper" :style="{ height: headerHeight + 'px' }">
<NavHeader title="优惠卷详情" />
</view>
<view class="main-wrap" :style="{ paddingTop: headerHeight + 'px' }">
<view v-if="!loading && detail" class="content">
<!-- 优惠卷基础信息卡片 -->
<view class="coupon-card">
<view class="coupon-left">
<view class="coupon-price" v-if="detail.type === 2">
<text class="amount">{{ (detail.discountPercent / 10).toFixed(1).replace(/\.0$/, '') }}</text>
<text class="symbol" style="font-size: 24rpx; margin-left: 4rpx;">折</text>
</view>
<view class="coupon-price" v-else>
<text class="symbol">¥</text>
<text class="amount">{{ formatAmount(detail.discountAmount || detail.discountPrice || detail.price || 0) }}</text>
</view>
<view class="coupon-condition" v-if="detail.usePrice">满{{ formatAmount(detail.usePrice) }}可用</view>
<view class="coupon-condition" v-else>无门槛</view>
</view>
<view class="coupon-right">
<view class="coupon-name">{{ detail.name }}</view>
<view class="coupon-time" v-if="detail.type === 2 && detail.discountLimit > 0">最多抵扣: ¥{{ formatAmount(detail.discountLimit) }}</view>
<view class="coupon-time" v-if="detail.validEndTime">有效期至: {{ formatTimeStr(detail.validEndTime) }}</view>
</view>
<view class="coupon-status-stamp" v-if="detail.status === 1">已使用</view>
<view class="coupon-status-stamp" v-else-if="detail.status === 2">已过期</view>
<view class="coupon-status-stamp" v-else-if="detail.status === 3">已作废</view>
</view>
<!-- 详细信息 -->
<view class="info-section">
<view class="info-title">使用说明</view>
<view class="info-item">
<text class="label">可用范围:</text>
<text class="value">{{ detail.productScope === 1 ? '全部代金券通用' : '指定代金券可用' }}</text>
</view>
<view class="info-item" v-if="detail.validStartTime && detail.validEndTime">
<text class="label">有效期限:</text>
<text class="value">{{ formatTimeStr(detail.validStartTime) }} 至 {{ formatTimeStr(detail.validEndTime) }}</text>
</view>
</view>
<!-- 适用商品列表 -->
<view class="goods-section" v-if="detail.productScope === 2 && detail.voucherList && detail.voucherList.length > 0">
<view class="section-title">可用代金卷</view>
<view class="goods-list">
<view class="goods-item" v-for="(item, index) in detail.voucherList" :key="index">
<image class="goods-img" :src="item.coverUrl || item.picUrl || '/static/home/entry_icon.png'" mode="aspectFill"></image>
<view class="goods-info">
<view class="goods-name">{{ item.name }}</view>
<view class="goods-shop-name" v-if="item.shopName">: {{ item.shopName }}</view>
<view class="goods-meta-list">
<view class="goods-meta-item" v-if="item.stock !== undefined">
<text class="meta-label">库存:</text>
<text class="meta-value">{{ item.stock }}份</text>
</view>
<view class="goods-meta-item" v-if="item.useRule">
<text class="meta-label">使用规则:</text>
<text class="meta-value">{{ item.useRule }}</text>
</view>
<view class="goods-meta-item" v-if="item.validDays">
<text class="meta-label">有效天数:</text>
<text class="meta-value">{{ item.validDays }}天</text>
</view>
</view>
<view class="goods-price-row">
<text class="goods-price">¥{{ formatAmount(item.salePrice || item.sellPrice) }}</text>
<text class="goods-original-price" v-if="item.originalPrice">¥{{ formatAmount(item.originalPrice) }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
<view v-if="loading" class="loading-state">
<text>加载中...</text>
</view>
</view>
</view>
</template>
<script>
import NavHeader from "@/components/NavHeader/NavHeader.vue";
import { getLuCouponDetail } from "@/api/service.js";
import { formatTime } from "@/utils/date.js";
export default {
components: {
NavHeader,
},
data() {
return {
statusBarHeight: 0,
couponId: null,
detail: null,
loading: true,
};
},
computed: {
headerHeight() {
return this.statusBarHeight + 44;
},
},
onLoad(options) {
const systemInfo = uni.getSystemInfoSync();
this.statusBarHeight = systemInfo.statusBarHeight || 0;
if (options.id) {
this.couponId = options.id;
this.loadDetail();
} else {
uni.showToast({
title: '参数错误',
icon: 'none'
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
},
methods: {
async loadDetail() {
this.loading = true;
try {
const res = await getLuCouponDetail(this.couponId);
if (res) {
this.detail = res;
} else {
uni.showToast({
title: '获取详情失败',
icon: 'none'
});
}
} catch (error) {
console.error("加载优惠卷详情失败:", error);
uni.showToast({
title: '加载失败',
icon: 'none'
});
} finally {
this.loading = false;
}
},
formatTimeStr(timestamp) {
if (!timestamp) return '';
return formatTime(timestamp, 'YYYY-MM-DD HH:mm:ss');
},
formatAmount(amount) {
if (!amount) return '0';
const yuan = amount / 100;
return Number.isInteger(yuan) ? yuan.toString() : yuan.toFixed(2).replace(/\.?0+$/, '');
}
}
}
</script>
<style lang="scss" scoped>
.coupon-detail-page {
min-height: 100vh;
background-color: #f5f5f5;
}
.header-fixed-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 100;
background-color: #fff;
}
.main-wrap {
padding: 20rpx;
box-sizing: border-box;
}
.loading-state {
display: flex;
justify-content: center;
padding-top: 100rpx;
color: #999;
font-size: 28rpx;
}
.coupon-card {
position: relative;
display: flex;
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 30rpx;
padding: 40rpx 30rpx;
align-items: center;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
.coupon-left {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 180rpx;
border-right: 2rpx dashed #eee;
padding-right: 20rpx;
.coupon-price {
color: #d51c3c;
.symbol {
font-size: 28rpx;
font-weight: bold;
}
.amount {
font-size: 56rpx;
font-weight: bold;
}
}
.coupon-condition {
font-size: 22rpx;
color: #666;
margin-top: 10rpx;
}
}
.coupon-right {
flex: 1;
padding-left: 30rpx;
display: flex;
flex-direction: column;
justify-content: center;
.coupon-name {
font-size: 34rpx;
color: #333;
font-weight: bold;
margin-bottom: 20rpx;
}
.coupon-time {
font-size: 24rpx;
color: #999;
margin-bottom: 6rpx;
}
}
.coupon-status-stamp {
position: absolute;
right: -20rpx;
top: 20rpx;
width: 120rpx;
height: 40rpx;
line-height: 40rpx;
text-align: center;
background-color: rgba(153, 153, 153, 0.1);
color: #999;
font-size: 20rpx;
transform: rotate(45deg);
transform-origin: center;
border: 1rpx solid #999;
}
}
.info-section {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.info-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 24rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #eee;
}
.info-item {
display: flex;
margin-bottom: 16rpx;
font-size: 28rpx;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
.label {
color: #666;
width: 140rpx;
flex-shrink: 0;
}
.value {
color: #333;
flex: 1;
}
}
}
.goods-section {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 24rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #eee;
}
.goods-list {
.goods-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
.goods-img {
width: 160rpx;
height: 160rpx;
border-radius: 12rpx;
margin-right: 20rpx;
background-color: #f5f5f5;
flex-shrink: 0;
}
.goods-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
.goods-name {
font-size: 28rpx;
color: #333;
font-weight: bold;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
margin-bottom: 8rpx;
}
.goods-shop-name {
font-size: 24rpx;
color: #666;
margin-bottom: 8rpx;
}
.goods-meta-list {
display: flex;
flex-direction: column;
margin-bottom: 12rpx;
.goods-meta-item {
font-size: 22rpx;
color: #999;
margin-bottom: 4rpx;
.meta-label {
color: #999;
}
.meta-value {
color: #666;
}
}
}
.goods-price-row {
display: flex;
align-items: baseline;
margin-top: auto;
}
.goods-price {
font-size: 32rpx;
color: #d51c3c;
font-weight: bold;
margin-right: 12rpx;
}
.goods-original-price {
font-size: 24rpx;
color: #999;
text-decoration: line-through;
}
}
}
}
}
</style>