272 lines
6.3 KiB
Vue
272 lines
6.3 KiB
Vue
<template>
|
||
<view v-if="visible" class="payment-popup-mask" @tap="handleMaskClick">
|
||
<view class="payment-popup-content" @tap.stop>
|
||
<!-- 顶部提示 -->
|
||
<view class="risk-warning">
|
||
<text>盲盒具有随机性,请理性消费,购买即表示同意</text>
|
||
<text class="agreement-link" @tap="openAgreement">《购买协议》</text>
|
||
</view>
|
||
|
||
<view class="popup-header">
|
||
<text class="popup-title">确认支付</text>
|
||
<view class="close-icon" @tap="handleClose">×</view>
|
||
</view>
|
||
|
||
<view class="popup-body">
|
||
<view class="amount-section" v-if="amount !== undefined && amount !== null">
|
||
<text class="label">支付金额</text>
|
||
<text class="amount">¥{{ amount }}</text>
|
||
</view>
|
||
|
||
<view class="form-item">
|
||
<text class="label">优惠券</text>
|
||
<picker
|
||
mode="selector"
|
||
:range="coupons"
|
||
range-key="name"
|
||
@change="onCouponChange"
|
||
:value="couponIndex"
|
||
:disabled="!coupons || coupons.length === 0"
|
||
>
|
||
<view class="picker-display">
|
||
<text v-if="selectedCoupon" class="selected-text">{{ selectedCoupon.name }} (-¥{{ selectedCoupon.amount }})</text>
|
||
<text v-else-if="!coupons || coupons.length === 0" class="placeholder">暂无优惠券可用</text>
|
||
<text v-else class="placeholder">请选择优惠券</text>
|
||
<text class="arrow"></text>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
|
||
<view class="form-item" v-if="showCards">
|
||
<text class="label">道具卡</text>
|
||
<picker
|
||
mode="selector"
|
||
:range="propCards"
|
||
range-key="name"
|
||
@change="onCardChange"
|
||
:value="cardIndex"
|
||
:disabled="!propCards || propCards.length === 0"
|
||
>
|
||
<view class="picker-display">
|
||
<text v-if="selectedCard" class="selected-text">{{ selectedCard.name }}</text>
|
||
<text v-else-if="!propCards || propCards.length === 0" class="placeholder">暂无道具卡可用</text>
|
||
<text v-else class="placeholder">请选择道具卡</text>
|
||
<text class="arrow"></text>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="popup-footer">
|
||
<button class="btn-cancel" @tap="handleClose">取消</button>
|
||
<button class="btn-confirm" @tap="handleConfirm">确认支付</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, watch } from 'vue'
|
||
|
||
const props = defineProps({
|
||
visible: { type: Boolean, default: false },
|
||
amount: { type: [Number, String], default: 0 },
|
||
coupons: { type: Array, default: () => [] },
|
||
propCards: { type: Array, default: () => [] },
|
||
showCards: { type: Boolean, default: true }
|
||
})
|
||
|
||
const emit = defineEmits(['update:visible', 'confirm', 'cancel'])
|
||
|
||
const couponIndex = ref(-1)
|
||
const cardIndex = ref(-1)
|
||
|
||
const selectedCoupon = computed(() => {
|
||
if (couponIndex.value >= 0 && props.coupons[couponIndex.value]) {
|
||
return props.coupons[couponIndex.value]
|
||
}
|
||
return null
|
||
})
|
||
|
||
const selectedCard = computed(() => {
|
||
if (cardIndex.value >= 0 && props.propCards[cardIndex.value]) {
|
||
return props.propCards[cardIndex.value]
|
||
}
|
||
return null
|
||
})
|
||
|
||
watch(() => props.visible, (val) => {
|
||
if (val) {
|
||
couponIndex.value = -1
|
||
cardIndex.value = -1
|
||
}
|
||
})
|
||
|
||
function onCouponChange(e) {
|
||
couponIndex.value = e.detail.value
|
||
}
|
||
|
||
function onCardChange(e) {
|
||
cardIndex.value = e.detail.value
|
||
}
|
||
|
||
function openAgreement() {
|
||
uni.navigateTo({
|
||
url: '/pages/agreement/purchase' // 假设协议页面路径,如果没有请替换为实际路径
|
||
})
|
||
}
|
||
|
||
function handleMaskClick() {
|
||
handleClose()
|
||
}
|
||
|
||
function handleClose() {
|
||
emit('update:visible', false)
|
||
emit('cancel')
|
||
}
|
||
|
||
function handleConfirm() {
|
||
emit('confirm', {
|
||
coupon: selectedCoupon.value,
|
||
card: props.showCards ? selectedCard.value : null
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.payment-popup-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.6);
|
||
z-index: 999;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.payment-popup-content {
|
||
width: 100%;
|
||
background-color: #fff;
|
||
border-radius: 24rpx 24rpx 0 0;
|
||
padding: 30rpx;
|
||
padding-bottom: calc(30rpx + constant(safe-area-inset-bottom));
|
||
padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
.risk-warning {
|
||
background-color: #fffbe6;
|
||
color: #ed6a0c;
|
||
font-size: 24rpx;
|
||
padding: 16rpx 24rpx;
|
||
border-radius: 8rpx;
|
||
margin-bottom: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
line-height: 1.4;
|
||
text-align: center;
|
||
}
|
||
|
||
.agreement-link {
|
||
color: #1890ff;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.popup-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
.popup-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
}
|
||
.close-icon {
|
||
position: absolute;
|
||
right: 30rpx;
|
||
font-size: 40rpx;
|
||
color: #999;
|
||
line-height: 1;
|
||
padding: 10rpx;
|
||
}
|
||
.popup-body {
|
||
padding: 30rpx;
|
||
}
|
||
.amount-section {
|
||
text-align: center;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
.amount-section .label {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
margin-right: 10rpx;
|
||
}
|
||
.amount-section .amount {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #ff4d4f;
|
||
}
|
||
.form-item {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
.form-item .label {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
.picker-display {
|
||
border: 1rpx solid #ddd;
|
||
border-radius: 8rpx;
|
||
padding: 20rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 28rpx;
|
||
background: #f9f9f9;
|
||
}
|
||
.selected-text {
|
||
color: #333;
|
||
}
|
||
.placeholder {
|
||
color: #999;
|
||
}
|
||
.arrow {
|
||
color: #ccc;
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-right: 2rpx solid #ccc;
|
||
border-bottom: 2rpx solid #ccc;
|
||
transform: rotate(-45deg);
|
||
margin-right: 8rpx;
|
||
}
|
||
.popup-footer {
|
||
display: flex;
|
||
border-top: 1rpx solid #eee;
|
||
}
|
||
.btn-cancel, .btn-confirm {
|
||
flex: 1;
|
||
border: none;
|
||
background: #fff;
|
||
border-radius: 0;
|
||
font-size: 30rpx;
|
||
padding: 24rpx 0;
|
||
line-height: 1.5;
|
||
}
|
||
.btn-cancel::after, .btn-confirm::after {
|
||
border: none;
|
||
}
|
||
.btn-cancel {
|
||
color: #666;
|
||
border-right: 1rpx solid #eee;
|
||
}
|
||
.btn-confirm {
|
||
color: #007AFF;
|
||
font-weight: bold;
|
||
}
|
||
</style>
|