Files
uni-fans-score/subPackages/business/purchase/index.vue
T
2026-03-09 09:07:58 +08:00

1171 lines
26 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="purchase-page">
<!-- Tab 切换 -->
<view class="tab-container">
<view class="tab-item" :class="{ active: currentTab === 'card' }" @click="switchTab('card')">
<text class="tab-text">{{ $t('purchase.memberCard') }}</text>
</view>
<view class="tab-item" :class="{ active: currentTab === 'coupon' }" @click="switchTab('coupon')">
<text class="tab-text">{{ $t('purchase.coupon') }}</text>
</view>
</view>
<!-- 内容区域 -->
<scroll-view class="content-area" scroll-y>
<!-- 会员卡列表 -->
<view v-if="currentTab === 'card'" class="product-list">
<view v-for="item in memberCards" :key="item.id" class="product-card"
:class="{ selected: selectedProduct?.id === item.id }" @click="selectProduct(item)">
<view class="card-content">
<view class="card-left">
<view class="card-title-row">
<text class="card-name">{{ item.name }}</text>
<view class="card-type-tag" :class="{ 'type-time': item.type === 'TIME', 'type-count': item.type === 'COUNT' }">
<text class="card-type-text">{{ item.type === 'TIME' ? $t('myCard.durationCard') : $t('myCard.timesCard') }}</text>
</view>
</view>
<text class="card-desc">{{ item.description }}</text>
<!-- 使用限制信息 -->
<view class="card-limits">
<!-- 时长卡展示每日限用次数和单次限时 -->
<view v-if="item.type === 'TIME'" class="limit-tags">
<view class="limit-tag" v-if="item.dailyLimitCount > 0">
<text class="limit-label">{{ $t('myCard.dailyLimit') }}:</text>
<text class="limit-value">{{ item.dailyLimitCount }}{{ $t('myCard.times') }}</text>
</view>
<view class="limit-tag">
<text class="limit-label">{{ $t('myCard.singleTimeLimit') }}:</text>
<text class="limit-value" :class="{ unlimited: item.singleLimitMinutes === 0 }">
{{ item.singleLimitMinutes > 0 ? item.singleLimitMinutes + $t('myCard.minutes') : $t('myCard.unlimited') }}
</text>
</view>
<view class="limit-tag validity-tag" v-if="item.cycleDays">
<text class="limit-value">{{ item.cycleDays }}{{ $t('myCard.daysValid') }}</text>
</view>
</view>
<!-- 次卡展示总次数和单次限时 -->
<view v-if="item.type === 'COUNT'" class="limit-tags">
<view class="limit-tag count-tag" v-if="item.totalCount > 0">
<text class="limit-label">{{ $t('myCard.totalCount') }}:</text>
<text class="limit-value">{{ item.totalCount }}{{ $t('myCard.times') }}</text>
</view>
<view class="limit-tag">
<text class="limit-label">{{ $t('myCard.singleTimeLimit') }}:</text>
<text class="limit-value" :class="{ unlimited: item.singleLimitMinutesForCount === 0 }">
{{ item.singleLimitMinutesForCount > 0 ? item.singleLimitMinutesForCount + $t('myCard.minutes') : $t('myCard.unlimited') }}
</text>
</view>
<view class="limit-tag validity-tag" v-if="item.validDays">
<text class="limit-value">{{ item.validDays }}{{ $t('myCard.daysValid') }}</text>
</view>
</view>
</view>
</view>
<view class="card-right">
<view class="card-price">
<text class="price-currency">¥</text>
<text class="price-value">{{ item.price }}</text>
</view>
<view class="card-original-price" v-if="item.originalPrice">
<text class="original-currency">¥</text>
<text class="original-value">{{ item.originalPrice }}</text>
</view>
</view>
</view>
</view>
<!-- 空数据提示 -->
<uv-empty v-if="memberCards.length === 0" mode="car" :text="$t('purchase.noCards')"></uv-empty>
</view>
<!-- 优惠券列表 -->
<view v-if="currentTab === 'coupon'" class="product-list">
<view v-for="item in coupons" :key="item.id" class="coupon-card-wrapper">
<view class="coupon-card" :class="{ selected: selectedProduct?.id === item.id }"
@click="selectProduct(item)">
<!-- 左侧圆形缺口 -->
<view class="coupon-circle-left"></view>
<!-- 右侧圆形缺口 -->
<view class="coupon-circle-right"></view>
<view class="coupon-left">
<view class="coupon-value-wrapper">
<text class="coupon-value-num">{{ item.type === 'discount' ? item.discount : item.value
}}</text>
<text class="coupon-value-unit">{{ item.type === 'discount' ? '折' : '¥' }}</text>
</view>
<view style="display: flex;flex-direction: column;">
<text class="coupon-condition">{{ item.condition }}</text>
<text class="coupon-validity">{{ item.validity }}</text>
</view>
</view>
<view class="coupon-divider"></view>
<view class="coupon-right">
<view class="coupon-price">
<text class="price-label">¥</text>
<text class="price-value">{{ item.price }}</text>
</view>
</view>
</view>
</view>
<!-- 空数据提示 -->
<uv-empty v-if="coupons.length === 0" mode="coupon" :text="$t('purchase.noCoupons')"></uv-empty>
</view>
<!-- 说明部分 -->
<view class="description-section">
<text class="description-title">{{ currentTab === 'card' ? $t('purchase.cardDescription') :
$t('purchase.couponDescription') }}</text>
<view class="description-content">
<view v-for="(desc, index) in descriptions" :key="index" class="description-item">
<text class="description-subtitle">{{ desc.title }}</text>
<text class="description-text">{{ desc.content }}</text>
</view>
</view>
</view>
</scroll-view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<view class="my-products-wrapper" @click="goToMyProducts">
<view class="" style="display: flex;">
<view class="my-products">
<image class="my-products-icon" src="/static/couponList.png" mode="aspectFit">
</image>
<text class="my-products-text">{{ currentTab === 'card' ? $t('purchase.myCards') :
$t('purchase.myCoupons') }}</text>
</view>
</view>
<view class="" style="width: 40rpx;height: 40rpx;">
<image src="/static/gotoBuy.png" mode="aspectFill" style="width: 40rpx;height: 40rpx;"></image>
</view>
</view>
<view class="action-wrapper">
<view class="price-info">
<text class="current-price">¥{{ selectedProduct?.price || '0.00' }}</text>
<text class="original-price" v-if="selectedProduct?.originalPrice">¥{{
selectedProduct?.originalPrice
}}</text>
</view>
<view class="buy-button" :class="{ disabled: !selectedProduct }" @click="handleBuy">
<text class="buy-button-text">{{ $t('purchase.buyNow') }}</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
computed,
onMounted
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
import {
useI18n
} from '@/utils/i18n.js'
import {
getCouponsByPosition,
createCouponPayment,
cancelCouponPayment
} from '@/config/api/coupon.js'
import {
createMemberCardPayment,
getMemberCardsByPosition,
cancelMemberCardPayment
} from '@/config/api/member.js'
const {
t
} = useI18n()
// 当前选中的 Tab
const currentTab = ref('card') // 'card' 或 'coupon'
// 选中的商品
const selectedProduct = ref(null)
// 当前场地ID(从路由参数获取)
const positionId = ref(null)
// 生命周期 onLoad 钩子 - 获取路由参数
onLoad((options) => {
if (options.positionId) {
positionId.value = options.positionId
console.log('获取到场地ID:', positionId.value)
}
})
// 会员卡列表(从后端加载)
const memberCards = ref([])
// 优惠券列表(从后端加载)
const coupons = ref([])
// 说明内容
const descriptions = computed(() => {
if (currentTab.value === 'card') {
return [
{
title: t('purchase.cardUseInstruction'),
content: t('purchase.cardUseDescription')
},
{
title: t('purchase.cardValidityPeriod'),
content: t('purchase.cardValidityDescription')
},
{
title: t('purchase.cardRefundPolicy'),
content: t('purchase.cardRefundDescription')
}
]
} else {
return [
{
title: t('purchase.couponUseInstruction'),
content: t('purchase.couponUseDescription')
},
{
title: t('purchase.couponValidityPeriod'),
content: t('purchase.couponValidityDescription')
},
{
title: t('purchase.couponUsageScope'),
content: t('purchase.couponUsageDescription')
}
]
}
})
// 加载会员卡列表
const loadMemberCards = async () => {
try {
uni.showLoading({
title: '加载中...'
})
const res = await getMemberCardsByPosition(positionId.value)
uni.hideLoading()
if (res.code === 200 && res.data) {
// 转换为页面需要的格式
memberCards.value = res.data.map(item => ({
id: item.memberCardId,
name: item.cardName,
type: item.cardType,
description: item.positionName || '无描述',
price: item.purchasePrice ? item.purchasePrice.toString() : '0.00',
originalPrice: null,
availablePositions: item.positionName,
cycleDays: item.cycleDays,
dailyLimitCount: item.dailyLimitCount || 0,
singleLimitMinutes: item.singleLimitMinutes || 0,
singleLimitMinutesForCount: item.singleLimitMinutesForCount || 0,
validDays: item.validDays,
totalCount: item.totalCount,
purchaseQuantity: item.purchaseQuantity
}))
}
} catch (error) {
uni.hideLoading()
console.error('加载会员卡失败:', error)
uni.showToast({
title: '加载会员卡失败',
icon: 'none'
})
}
}
// 加载优惠券列表
const loadCoupons = async () => {
try {
uni.showLoading({
title: '加载中...'
})
const res = await getCouponsByPosition(positionId.value)
uni.hideLoading()
if (res.code === 200 && res.data) {
// 转换为页面需要的格式
coupons.value = res.data.map(item => ({
id: item.couponId,
couponId: item.couponId,
name: item.couponName,
type: item.couponType === 'discount_coupon' ? 'discount' : 'cash',
discount: item.discountRate ? (item.discountRate * 10).toFixed(0) : null,
value: item.deductAmount ? item.deductAmount.toString() : null,
condition: item.usableCondition > 0 ? `满${item.usableCondition}元可用` : '无门槛',
validity: item.validDays > 0 ? `从购买日起 有效期${item.validDays}天` : '永久有效',
price: item.purchasePrice ? item.purchasePrice.toString() : '0.00',
originalPrice: null,
usablePositions: item.usablePositionNameMap,
remark: item.remark
}))
}
} catch (error) {
uni.hideLoading()
console.error('加载优惠券失败:', error)
uni.showToast({
title: '加载优惠券失败',
icon: 'none'
})
}
}
// 初始化
onMounted(async () => {
// 加载会员卡列表
if (positionId.value) {
await loadMemberCards()
}
// 加载优惠券列表
if (positionId.value) {
await loadCoupons()
}
// 默认选中第一个会员卡(如果有的话)
if (memberCards.value.length > 0) {
selectedProduct.value = memberCards.value[0]
}
})
const switchTab = (tab) => {
currentTab.value = tab
selectedProduct.value = null
}
// 选择商品
const selectProduct = (product) => {
selectedProduct.value = product
}
const orderNo = ref('')
// 获取当前支付平台(前端维度)
const getPaymentPlatform = () => {
// 小程序环境
// #ifdef MP-WEIXIN
return 'WECHAT'
// #endif
// #ifdef MP-ALIPAY
return 'ALIPAY'
// #endif
// H5 默认使用 ANTOM
// #ifdef H5
return 'ANTOM'
// #endif
return 'WECHAT'
}
// 支付宝 tradePay 兼容:优先 tradeNO,其次 orderStr
const alipayTradePay = ({ tradeNo, orderStr, onSuccess, onFail }) => {
// #ifdef MP-ALIPAY
const tradeNO = tradeNo
if (tradeNO) {
my.tradePay({
tradeNO,
success: onSuccess,
fail: onFail
})
return
}
if (orderStr) {
my.tradePay({
orderStr,
success: onSuccess,
fail: onFail
})
return
}
// #endif
onFail && onFail(new Error('未获取到支付宝支付参数'))
}
// 处理购买(会员卡 / 优惠券),内部使用商品多支付平台方案下的统一思路
const handleBuy = async () => {
if (!selectedProduct.value) {
uni.showToast({
title: t('purchase.pleaseSelect'),
icon: 'none'
})
return
}
const paymentPlatform = getPaymentPlatform()
// 会员卡购买(按接口文档:POST /app/member/pay
if (currentTab.value === 'card') {
try {
uni.showLoading({
title: '正在创建订单...'
})
const res = await createMemberCardPayment(selectedProduct.value.id, paymentPlatform)
uni.hideLoading()
if (res.code === 200 && res.data) {
// 不同平台分别发起支付(字段按文档)
// 微信小程序
// #ifdef MP-WEIXIN
if (paymentPlatform === 'WECHAT') {
// 会员卡订单号:OutOrderNo(文档)
orderNo.value = res.data.OutOrderNo
uni.requestPayment({
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: res.data.signType || 'MD5',
paySign: res.data.paySign,
success: () => {
uni.showToast({ title: '支付成功', icon: 'success' })
setTimeout(() => {
uni.navigateTo({ url: '/subPackages/business/my-card' })
}, 1500)
},
fail: (err) => {
console.error('支付失败:', err)
if (err.errMsg && err.errMsg.includes('cancel')) {
// 取消支付(本项目取消接口走 device 侧 cancel
orderNo.value && cancelMemberCardPayment(orderNo.value).catch(() => {})
uni.showToast({ title: '已取消支付', icon: 'none' })
} else {
uni.showToast({ title: '支付失败', icon: 'none' })
}
}
})
return
}
// #endif
// 支付宝小程序
// #ifdef MP-ALIPAY
if (paymentPlatform === 'ALIPAY') {
// 文档返回:tradeNo / outTradeNo;也兼容 orderStr
const tradeNo = res.data.tradeNo || res.data.tradeNO
const payForm = res.data.payForm || res.data.orderStr
alipayTradePay({
tradeNo,
orderStr: payForm,
onSuccess: (payRes) => {
if (payRes.resultCode === '9000') {
uni.showToast({ title: '支付成功', icon: 'success' })
setTimeout(() => {
uni.navigateTo({ url: '/subPackages/business/my-card' })
}, 1500)
} else {
uni.showToast({ title: '支付失败', icon: 'none' })
}
},
onFail: () => {
uni.showToast({ title: '支付失败', icon: 'none' })
}
})
return
}
// #endif
// H5 + Antom(文档里 Antom 预留,当前后端可能返回 cashierUrl / h5Url 之一)
// #ifdef H5
if (paymentPlatform === 'ANTOM') {
const cashierUrl = res.data.cashierUrl || res.data.h5Url
if (cashierUrl) {
window.location.href = cashierUrl
return
}
}
// #endif
} else {
uni.showToast({
title: res.msg || '创建订单失败',
icon: 'none'
})
}
} catch (error) {
uni.hideLoading()
console.error('购买失败:', error)
uni.showToast({
title: '购买失败,请稍后重试',
icon: 'none'
})
}
return
}
// 优惠券购买(按接口文档:POST /app/coupon/pay
if (currentTab.value === 'coupon') {
try {
uni.showLoading({
title: '正在创建订单...'
})
const res = await createCouponPayment(selectedProduct.value.couponId, paymentPlatform)
uni.hideLoading()
if (res.code === 200 && res.data) {
// 微信小程序
// #ifdef MP-WEIXIN
if (paymentPlatform === 'WECHAT') {
uni.requestPayment({
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: res.data.signType || 'MD5',
paySign: res.data.paySign,
success: () => {
uni.showToast({ title: '支付成功', icon: 'success' })
setTimeout(() => {
uni.navigateTo({ url: '/subPackages/business/my-coupon' })
}, 1500)
},
fail: (err) => {
console.error('支付失败:', err)
if (err.errMsg && err.errMsg.includes('cancel')) {
const outOrderNo = res.data.OutOrderNo || res.data.outOrderNo
outOrderNo && cancelCouponPayment(outOrderNo).catch(() => {})
uni.showToast({ title: '已取消支付', icon: 'none' })
} else {
uni.showToast({ title: '支付失败', icon: 'none' })
}
}
})
return
}
// #endif
// 支付宝小程序
// #ifdef MP-ALIPAY
if (paymentPlatform === 'ALIPAY') {
const tradeNo = res.data.tradeNo || res.data.tradeNO
const payForm = res.data.payForm || res.data.orderStr
alipayTradePay({
tradeNo,
orderStr: payForm,
onSuccess: (payRes) => {
if (payRes.resultCode === '9000') {
uni.showToast({ title: '支付成功', icon: 'success' })
setTimeout(() => {
uni.navigateTo({ url: '/subPackages/business/my-coupon' })
}, 1500)
} else {
uni.showToast({ title: '支付失败', icon: 'none' })
}
},
onFail: () => {
uni.showToast({ title: '支付失败', icon: 'none' })
}
})
return
}
// #endif
// H5 + Antom
// #ifdef H5
if (paymentPlatform === 'ANTOM') {
const cashierUrl = res.data.cashierUrl || res.data.h5Url
if (cashierUrl) {
window.location.href = cashierUrl
return
}
}
// #endif
} else {
uni.showToast({
title: res.msg || '创建订单失败',
icon: 'none'
})
}
} catch (error) {
uni.hideLoading()
console.error('购买失败:', error)
uni.showToast({
title: '购买失败,请稍后重试',
icon: 'none'
})
}
}
}
// 查看我的商品
const goToMyProducts = () => {
if (currentTab.value === 'card') {
uni.navigateTo({
url: '/subPackages/business/my-card'
})
} else if (currentTab.value === 'coupon') {
uni.navigateTo({
url: '/subPackages/business/my-coupon'
})
}
}
</script>
<style lang="scss" scoped>
.purchase-page {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 180rpx;
}
/* Tab 切换 */
.tab-container {
top: 20rpx;
position: fixed;
left: 0;
right: 0;
display: flex;
background-color: #ffffff;
width: 500rpx;
z-index: 999;
padding: 5rpx 0;
margin: 0 auto;
border-radius: 26rpx;
}
.tab-item {
flex: 1;
text-align: center;
padding: 10rpx 30rpx;
margin: 0 10rpx;
width: 120rpx;
position: relative;
.tab-text {
font-size: 28rpx;
color: #A6A6A6;
font-weight: 500;
}
&.active {
background:#FFE2B8;
border-radius: 26rpx;
.tab-text {
color: #A16300;
font-weight: 600;
}
// &::after {
// content: '';
// position: absolute;
// bottom: 0;
// left: 50%;
// transform: translateX(-50%);
// width: 60rpx;
// height: 6rpx;
// background-color: #FFA928;
// border-radius: 3rpx;
// }
}
}
/* 内容区域 */
.content-area {
height: calc(100vh - 180rpx);
padding: 20rpx;
padding-top: 80rpx;
box-sizing: border-box;
}
/* 商品列表 */
.product-list {
margin-bottom: 20rpx;
margin-top: 20rpx;
}
/* 会员卡卡片 */
.product-card {
background-color: #ffffff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
box-sizing: border-box;
&:last-child {
margin-bottom: 0;
}
&.selected {
border-color: #FFA928;
box-shadow: 0 4rpx 20rpx rgba(255, 169, 40, 0.2);
}
.card-content {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.card-left {
flex: 1;
display: flex;
flex-direction: column;
gap: 10rpx;
}
.card-title-row {
display: flex;
align-items: center;
gap: 12rpx;
}
.card-name {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.card-type-tag {
display: inline-flex;
align-items: center;
padding: 4rpx 12rpx;
border-radius: 8rpx;
flex-shrink: 0;
&.type-time {
background-color: #E6F7FF;
border: 1rpx solid #91D5FF;
}
&.type-count {
background-color: #FFF1F0;
border: 1rpx solid #FFCCC7;
}
.card-type-text {
font-size: 20rpx;
font-weight: 500;
}
}
.type-time .card-type-text {
color: #1890FF;
}
.type-count .card-type-text {
color: #FF4D4F;
}
.card-desc {
font-size: 24rpx;
color: #999;
line-height: 1.6;
}
/* 会员卡限制信息样式 */
.card-limits {
margin-top: 12rpx;
}
.limit-tags {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
align-items: center;
}
.limit-tag {
display: inline-flex;
align-items: center;
gap: 4rpx;
padding: 6rpx 12rpx;
background-color: #FFF4E6;
border-radius: 8rpx;
border: 1rpx solid #FFE8CC;
.limit-label {
font-size: 22rpx;
color: #B8741A;
// font-weight: 500;
}
.limit-value {
font-size: 22rpx;
color: #FF6B00;
// font-weight: 600;
&.unlimited {
color: #07c160;
}
}
/* 有效期标签特殊样式 */
&.validity-tag {
background-color: #F0F5FF;
border: 1rpx solid #D6E4FF;
.limit-value {
color: #1890FF;
}
}
/* 总次数标签特殊样式 */
&.count-tag {
background-color: #FFF1F0;
border: 1rpx solid #FFCCC7;
.limit-label {
color: #CF1322;
}
.limit-value {
color: #FF4D4F;
font-weight: 600;
}
}
}
.card-right {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 8rpx;
}
.card-price {
display: flex;
align-items: baseline;
gap: 2rpx;
.price-currency {
font-size: 24rpx;
font-weight: 500;
color: #FF6B00;
}
.price-value {
font-size: 36rpx;
font-weight: 600;
color: #FF6B00;
}
}
.card-original-price {
display: flex;
align-items: baseline;
gap: 2rpx;
text-decoration: line-through;
.original-currency {
font-size: 20rpx;
font-weight: 400;
color: #999;
}
.original-value {
font-size: 24rpx;
font-weight: 400;
color: #999;
}
}
}
/* 优惠券卡片 */
.coupon-card-wrapper {
position: relative;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
}
.coupon-card {
background: linear-gradient(135deg, #FFF4E6 0%, #FFE8CC 100%);
border-radius: 20rpx;
padding: 40rpx 30rpx;
display: flex;
align-items: stretch;
position: relative;
box-sizing: border-box;
border: 2rpx solid transparent;
transition: all 0.3s;
overflow: visible;
min-height: 180rpx;
&.selected {
border-color: #B8741A;
box-shadow: 0 4rpx 20rpx rgba(184, 116, 26, 0.2);
.coupon-circle-left,
.coupon-circle-right {
background-color: #FFF4E6;
border: 2rpx solid #B8741A;
}
}
}
/* 左侧圆形缺口 */
.coupon-circle-left {
position: absolute;
left: -16rpx;
top: 50%;
transform: translateY(-50%);
width: 32rpx;
height: 32rpx;
border-radius: 50%;
background-color: #f5f5f5;
z-index: 10;
transition: all 0.3s;
box-sizing: border-box;
}
/* 右侧圆形缺口 */
.coupon-circle-right {
position: absolute;
right: -16rpx;
top: 50%;
transform: translateY(-50%);
width: 32rpx;
height: 32rpx;
border-radius: 50%;
background-color: #f5f5f5;
z-index: 10;
transition: all 0.3s;
box-sizing: border-box;
}
.coupon-left {
flex: 1;
display: flex;
flex-direction: row;
gap: 8rpx;
align-items: center;
}
/* 优惠券金额显示包裹器 */
.coupon-value-wrapper {
width: 180rpx;
text-align: center;
}
/* 优惠券实际值(数字) */
.coupon-value-num {
font-size: 52rpx;
font-weight: 700;
color: #B8741A;
}
/* 优惠券单位(折/¥) */
.coupon-value-unit {
font-size: 26rpx;
font-weight: 600;
color: #B8741A;
}
.coupon-value {
font-size: 48rpx;
font-weight: 700;
color: #B8741A;
}
.coupon-condition {
font-size: 28rpx;
color: #333;
}
.coupon-validity {
font-size: 24rpx;
color: #999;
}
.coupon-divider {
width: 2rpx;
height: 100%;
position: absolute;
left: 65%;
transform: translateX(-50%);
top: 0;
bottom: 0;
// min-height: 160rpx;
align-self: stretch;
background: repeating-linear-gradient(to bottom,
#B8741A 0rpx,
#B8741A 8rpx,
transparent 8rpx,
transparent 16rpx);
margin: 0 30rpx;
}
.coupon-right {
display: flex;
align-items: center;
justify-content: center;
.coupon-price {
display: flex;
align-items: baseline;
gap: 4rpx;
.price-label {
font-size: 24rpx;
color: #B8741A;
font-weight: 600;
}
.price-value {
font-size: 36rpx;
color: #B8741A;
font-weight: 700;
}
}
}
/* 说明部分 */
.description-section {
background-color: #ffffff;
border-radius: 20rpx;
padding: 30rpx;
margin-top: 20rpx;
box-sizing: border-box;
}
.description-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
display: block;
}
.description-content {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.description-item {
display: flex;
flex-direction: column;
gap: 10rpx;
}
.description-subtitle {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.description-text {
font-size: 24rpx;
color: #666;
line-height: 1.8;
}
/* 底部操作栏 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #ffffff;
padding-bottom: 20rpx;
border-radius: 40rpx 40rpx 0 0;
// padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
z-index: 1000;
}
.my-products-wrapper {
display: flex;
justify-content: space-between;
flex-direction: row;
background: #FFF4E3;
border-radius: 40rpx;
padding: 16rpx 32rpx;
border-radius: 40rpx 40rpx 0 0;
}
.action-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
flex: 1;
margin-left: 20rpx;
margin-right: 20rpx;
padding-top: 20rpx;
}
.my-products {
display: flex;
// flex-direction: column;
align-items: center;
justify-content: center;
gap: 4rpx;
min-width: 120rpx;
cursor: pointer;
&.full {
flex-direction: row;
gap: 8rpx;
padding: 16rpx 32rpx;
background-color: #f5f5f5;
border-radius: 40rpx;
}
.my-products-icon {
width: 40rpx;
height: 40rpx;
flex-shrink: 0;
}
.my-products-text {
margin-left: 10rpx;
font-size: 22rpx;
color: #A16300;
white-space: nowrap;
}
}
.price-info {
display: flex;
flex-direction: column;
// align-items: flex-end;
gap: 4rpx;
flex: 1;
margin: 0 20rpx;
}
.current-price {
font-size: 36rpx;
font-weight: 600;
color: #FF6B00;
}
.original-price {
font-size: 24rpx;
color: #999;
text-decoration: line-through;
}
.buy-button {
padding: 24rpx 60rpx;
background-color: #B8741A;
border-radius: 48rpx;
transition: all 0.3s;
&.disabled {
background-color: #ccc;
opacity: 0.6;
}
.buy-button-text {
font-size: 32rpx;
color: #ffffff;
font-weight: 600;
}
}
</style>