935 lines
22 KiB
Vue
935 lines
22 KiB
Vue
<template>
|
||
<view>
|
||
<!-- 祝福动画 -->
|
||
<view v-if="showBlessing" class="blessing-container">
|
||
<view class="blessing-animation" :class="currentBlessing.type">
|
||
<view class="blessing-emoji">{{ currentBlessing.emoji }}</view>
|
||
<view v-if="currentBlessing.type === 'sheep'" class="blessing-subtitle">小羊祝你</view>
|
||
<view class="blessing-text">
|
||
<text v-for="(char, index) in currentBlessing.chars"
|
||
:key="index"
|
||
class="char"
|
||
:class="{ 'from-left': index % 2 === 0, 'from-right': index % 2 === 1 }"
|
||
:style="{ animationDelay: index * 0.15 + 's' }">
|
||
{{ char }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 支付弹窗 -->
|
||
<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 v-if="gamePasses" class="game-pass-section">
|
||
<view
|
||
class="game-pass-option"
|
||
:class="{ active: useGamePass, disabled: gamePassRemaining <= 0 }"
|
||
@tap="gamePassRemaining > 0 ? toggleGamePass() : null"
|
||
>
|
||
<view class="game-pass-radio">
|
||
<view v-if="useGamePass" class="radio-checked">✓</view>
|
||
<view v-else-if="gamePassRemaining <= 0" class="radio-disabled" />
|
||
</view>
|
||
<view class="game-pass-info">
|
||
<text class="game-pass-label" :class="{ 'text-disabled': gamePassRemaining <= 0 }">剩余次数</text>
|
||
<text class="game-pass-count" v-if="gamePassRemaining > 0">{{ gamePassRemaining }} 次</text>
|
||
<text class="game-pass-count text-disabled" v-else>暂无可用次数卡</text>
|
||
</view>
|
||
</view>
|
||
<view v-if="!useGamePass" class="divider-line">
|
||
<text class="divider-text">或选择其他支付方式</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="amount-section" v-if="!useGamePass && amount !== undefined && amount !== null">
|
||
<text class="label">支付金额</text>
|
||
<text class="amount">¥{{ finalPayAmount }}</text>
|
||
<text v-if="finalPayAmount < amount" class="original-amount" style="text-decoration: line-through; color: #999; font-size: 24rpx; margin-left: 10rpx;">¥{{ amount }}</text>
|
||
</view>
|
||
|
||
<view class="form-item">
|
||
<text class="label">优惠券</text>
|
||
<picker
|
||
class="picker-full"
|
||
mode="selector"
|
||
:range="coupons"
|
||
range-key="name"
|
||
@change="onCouponChange"
|
||
:value="couponIndex"
|
||
:disabled="(!coupons || coupons.length === 0) || useGamePass"
|
||
>
|
||
<view class="picker-display" :class="{ 'picker-disabled': useGamePass }">
|
||
<text v-if="useGamePass" class="placeholder" style="color: #666;">
|
||
多次卡不可与优惠券同享
|
||
</text>
|
||
<text v-if="selectedCoupon" class="selected-text">
|
||
{{ selectedCoupon.name }} (-¥{{ effectiveCouponDiscount.toFixed(2) }})
|
||
<text v-if="selectedCoupon.amount > maxDeductible" style="font-size: 20rpx; color: #FF9800;">(最高抵扣50%)</text>
|
||
</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
|
||
class="picker-full"
|
||
mode="selector"
|
||
:range="displayCards"
|
||
range-key="displayName"
|
||
@change="onCardChange"
|
||
:value="cardIndex"
|
||
:disabled="!displayCards || displayCards.length === 0"
|
||
>
|
||
<view class="picker-display">
|
||
<text v-if="selectedCard" class="selected-text">
|
||
{{ selectedCard.name }}
|
||
<text v-if="Number(selectedCard.count) > 1" style="color: #999; font-size: 24rpx; margin-left: 6rpx;">(拥有: {{ selectedCard.count }})</text>
|
||
</text>
|
||
<text v-else-if="!displayCards || displayCards.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 v-if="useGamePass" class="btn-confirm btn-game-pass" @tap="handleConfirm">🎮 使用次数卡</button>
|
||
<button v-else class="btn-confirm" @tap="handleConfirm">确认支付</button>
|
||
</view>
|
||
</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 },
|
||
gamePasses: { type: Object, default: () => null } // { total_remaining, passes }
|
||
})
|
||
|
||
const emit = defineEmits(['update:visible', 'confirm', 'cancel'])
|
||
|
||
// 祝福动画相关
|
||
const showBlessing = ref(false)
|
||
const blessings = [
|
||
{
|
||
emoji: '🐏',
|
||
chars: ['三', '羊', '开', '泰'],
|
||
type: 'sheep'
|
||
},
|
||
{
|
||
emoji: '🐴',
|
||
chars: ['一', '马', '当', '先'],
|
||
type: 'horse'
|
||
},
|
||
{
|
||
emoji: '🍊',
|
||
chars: ['心', '想', '事', '橙'],
|
||
type: 'orange'
|
||
},
|
||
{
|
||
emoji: '🐵',
|
||
chars: ['财', '源', '广', '进'],
|
||
type: 'monkey'
|
||
},
|
||
{
|
||
emoji: '🐮',
|
||
chars: ['牛', '气', '冲', '天'],
|
||
type: 'ox'
|
||
},
|
||
{
|
||
emoji: '🐶',
|
||
chars: ['旺', '旺', '旺', '旺'],
|
||
type: 'dog'
|
||
},
|
||
{
|
||
emoji: '🐔',
|
||
chars: ['吉', '祥', '如', '意'],
|
||
type: 'chicken'
|
||
}
|
||
]
|
||
const currentBlessing = ref(blessings[0])
|
||
|
||
// 监听弹窗打开,显示祝福动画
|
||
watch(() => props.visible, (newVal) => {
|
||
console.log('[PaymentPopup] visible changed:', newVal)
|
||
if (newVal) {
|
||
// 随机选择祝福语
|
||
const index = Math.floor(Math.random() * blessings.length)
|
||
currentBlessing.value = blessings[index]
|
||
|
||
// 延迟显示祝福动画
|
||
setTimeout(() => {
|
||
console.log('[PaymentPopup] 显示祝福动画')
|
||
showBlessing.value = true
|
||
|
||
// 3秒后隐藏祝福动画
|
||
setTimeout(() => {
|
||
showBlessing.value = false
|
||
console.log('[PaymentPopup] 隐藏祝福动画')
|
||
}, 3000)
|
||
}, 300) // 延迟300ms,让支付弹窗先滑入
|
||
} else {
|
||
showBlessing.value = false
|
||
}
|
||
})
|
||
|
||
const couponIndex = ref(-1)
|
||
const cardIndex = ref(-1)
|
||
const useGamePass = ref(false)
|
||
|
||
// 次数卡余额
|
||
const gamePassRemaining = computed(() => {
|
||
return props.gamePasses?.total_remaining || 0
|
||
})
|
||
|
||
// 监听弹窗打开,若有次数卡则默认选中
|
||
watch(() => props.visible, (newVal) => {
|
||
if (newVal) {
|
||
// 若有次数卡,默认选中
|
||
useGamePass.value = gamePassRemaining.value > 0
|
||
}
|
||
})
|
||
|
||
function toggleGamePass() {
|
||
useGamePass.value = !useGamePass.value
|
||
// Mutually Exclusive: If Game Pass is ON, clear Coupon.
|
||
if (useGamePass.value) {
|
||
couponIndex.value = -1
|
||
}
|
||
}
|
||
|
||
const selectedCoupon = computed(() => {
|
||
if (couponIndex.value >= 0 && props.coupons[couponIndex.value]) {
|
||
return props.coupons[couponIndex.value]
|
||
}
|
||
return null
|
||
})
|
||
|
||
const maxDeductible = computed(() => {
|
||
const amt = Number(props.amount) || 0
|
||
return amt * 0.5
|
||
})
|
||
|
||
const effectiveCouponDiscount = computed(() => {
|
||
if (!selectedCoupon.value) return 0
|
||
const couponAmt = Number(selectedCoupon.value.amount) || 0
|
||
return Math.min(couponAmt, maxDeductible.value)
|
||
})
|
||
|
||
const displayCards = computed(() => {
|
||
if (!Array.isArray(props.propCards)) return []
|
||
return props.propCards.map(c => ({
|
||
...c,
|
||
displayName: (c.count && Number(c.count) > 1) ? `${c.name} (x${c.count})` : c.name
|
||
}))
|
||
})
|
||
|
||
const selectedCard = computed(() => {
|
||
if (cardIndex.value >= 0 && displayCards.value[cardIndex.value]) {
|
||
return displayCards.value[cardIndex.value]
|
||
}
|
||
return null
|
||
})
|
||
|
||
const finalPayAmount = computed(() => {
|
||
const amt = Number(props.amount) || 0
|
||
return Math.max(0, amt - effectiveCouponDiscount.value).toFixed(2)
|
||
})
|
||
|
||
watch(
|
||
[() => props.visible, () => (Array.isArray(props.coupons) ? props.coupons.length : 0)],
|
||
([vis, len]) => {
|
||
if (!vis) return
|
||
cardIndex.value = -1
|
||
if (len <= 0) {
|
||
couponIndex.value = -1
|
||
return
|
||
}
|
||
if (couponIndex.value < 0) {
|
||
couponIndex.value = 0
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
)
|
||
|
||
function onCouponChange(e) {
|
||
couponIndex.value = e.detail.value
|
||
}
|
||
|
||
function onCardChange(e) {
|
||
cardIndex.value = e.detail.value
|
||
}
|
||
|
||
function openAgreement() {
|
||
uni.navigateTo({
|
||
url: '/pages-user/agreement/purchase'
|
||
})
|
||
}
|
||
|
||
function handleMaskClick() {
|
||
handleClose()
|
||
}
|
||
|
||
function handleClose() {
|
||
emit('update:visible', false)
|
||
emit('cancel')
|
||
}
|
||
|
||
function handleConfirm() {
|
||
emit('confirm', {
|
||
coupon: useGamePass.value ? null : selectedCoupon.value,
|
||
card: (props.showCards && !useGamePass.value) ? selectedCard.value : null,
|
||
useGamePass: useGamePass.value
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
/* ============================================
|
||
祝福动画样式
|
||
============================================ */
|
||
|
||
.blessing-container {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 10000;
|
||
pointer-events: none;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.blessing-animation {
|
||
text-align: center;
|
||
animation: blessingFadeIn 0.5s ease-out;
|
||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(255, 248, 243, 0.98));
|
||
padding: 40rpx 30rpx;
|
||
border-radius: 24rpx;
|
||
box-shadow: 0 12rpx 48rpx rgba(255, 107, 0, 0.3);
|
||
backdrop-filter: blur(20rpx);
|
||
border: 2rpx solid rgba(255, 159, 67, 0.3);
|
||
}
|
||
|
||
@keyframes blessingFadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-30rpx);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.blessing-emoji {
|
||
font-size: 100rpx;
|
||
line-height: 1;
|
||
margin-bottom: 16rpx;
|
||
display: block;
|
||
}
|
||
|
||
// 小羊动画 - 弹跳出现
|
||
.blessing-animation.sheep .blessing-emoji {
|
||
animation: emojiBounce 1.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||
}
|
||
|
||
// 小马动画 - 从左边跑步进场
|
||
.blessing-animation.horse .blessing-emoji {
|
||
animation: emojiRun 1.5s ease-out;
|
||
}
|
||
|
||
// 橙子动画 - 缩放旋转出现(微信小程序优化版)
|
||
.blessing-animation.orange .blessing-emoji {
|
||
animation: emojiRotate 1.5s ease-out;
|
||
}
|
||
|
||
// 猴子动画 - 跳跃摇摆出现
|
||
.blessing-animation.monkey .blessing-emoji {
|
||
animation: emojiSwing 1.5s ease-out;
|
||
}
|
||
|
||
// 牛动画 - 冲撞弹跳出现
|
||
.blessing-animation.ox .blessing-emoji {
|
||
animation: emojiCharge 1.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||
}
|
||
|
||
// 狗动画 - 摇尾巴跳动出现
|
||
.blessing-animation.dog .blessing-emoji {
|
||
animation: emojiWag 1.5s ease-in-out;
|
||
}
|
||
|
||
// 鸡动画 - 啄米点头出现
|
||
.blessing-animation.chicken .blessing-emoji {
|
||
animation: emojiPeck 1.5s ease-in-out;
|
||
}
|
||
|
||
@keyframes emojiBounce {
|
||
0% {
|
||
transform: scale(0) rotate(-180deg);
|
||
opacity: 0;
|
||
}
|
||
50% {
|
||
transform: scale(1.2) rotate(10deg);
|
||
}
|
||
100% {
|
||
transform: scale(1) rotate(0deg);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
@keyframes emojiRun {
|
||
0% {
|
||
transform: translateX(-300rpx) scale(0.8);
|
||
opacity: 0;
|
||
}
|
||
60% {
|
||
transform: translateX(30rpx) scale(1.1);
|
||
}
|
||
80% {
|
||
transform: translateX(-15rpx) scale(0.95);
|
||
}
|
||
100% {
|
||
transform: translateX(0) scale(1);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
@keyframes emojiRotate {
|
||
0% {
|
||
transform: scale(0) rotate(0deg);
|
||
opacity: 0;
|
||
}
|
||
40% {
|
||
transform: scale(1.2) rotate(180deg);
|
||
opacity: 1;
|
||
}
|
||
60% {
|
||
transform: scale(0.95) rotate(360deg);
|
||
}
|
||
80% {
|
||
transform: scale(1.05) rotate(360deg);
|
||
}
|
||
100% {
|
||
transform: scale(1) rotate(360deg);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
@keyframes emojiSwing {
|
||
0% {
|
||
transform: scale(0) translateY(-50rpx) rotate(-30deg);
|
||
opacity: 0;
|
||
}
|
||
40% {
|
||
transform: scale(1.15) translateY(10rpx) rotate(20deg);
|
||
opacity: 1;
|
||
}
|
||
60% {
|
||
transform: scale(0.9) translateY(-5rpx) rotate(-10deg);
|
||
}
|
||
80% {
|
||
transform: scale(1.05) translateY(3rpx) rotate(5deg);
|
||
}
|
||
100% {
|
||
transform: scale(1) translateY(0) rotate(0deg);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
@keyframes emojiCharge {
|
||
0% {
|
||
transform: scale(0) translateX(-100rpx) rotate(45deg);
|
||
opacity: 0;
|
||
}
|
||
50% {
|
||
transform: scale(1.3) translateX(20rpx) rotate(-20deg);
|
||
opacity: 1;
|
||
}
|
||
70% {
|
||
transform: scale(0.85) translateX(-10rpx) rotate(10deg);
|
||
}
|
||
85% {
|
||
transform: scale(1.08) translateX(5rpx) rotate(-5deg);
|
||
}
|
||
100% {
|
||
transform: scale(1) translateX(0) rotate(0deg);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
@keyframes emojiWag {
|
||
0% {
|
||
transform: scale(0) translateY(-30rpx) rotate(-15deg);
|
||
opacity: 0;
|
||
}
|
||
30% {
|
||
transform: scale(1.2) translateY(0) rotate(15deg);
|
||
opacity: 1;
|
||
}
|
||
50% {
|
||
transform: scale(0.9) translateY(-15rpx) rotate(-15deg);
|
||
}
|
||
70% {
|
||
transform: scale(1.1) translateY(0) rotate(15deg);
|
||
}
|
||
85% {
|
||
transform: scale(0.95) translateY(-5rpx) rotate(-5deg);
|
||
}
|
||
100% {
|
||
transform: scale(1) translateY(0) rotate(0deg);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
@keyframes emojiPeck {
|
||
0% {
|
||
transform: scale(0) translateY(-40rpx) rotate(0deg);
|
||
opacity: 0;
|
||
}
|
||
25% {
|
||
transform: scale(1.15) translateY(10rpx) rotate(10deg);
|
||
opacity: 1;
|
||
}
|
||
40% {
|
||
transform: scale(0.85) translateY(-5rpx) rotate(-10deg);
|
||
}
|
||
55% {
|
||
transform: scale(1.1) translateY(8rpx) rotate(8deg);
|
||
}
|
||
70% {
|
||
transform: scale(0.9) translateY(-3rpx) rotate(-8deg);
|
||
}
|
||
85% {
|
||
transform: scale(1.05) translateY(2rpx) rotate(3deg);
|
||
}
|
||
100% {
|
||
transform: scale(1) translateY(0) rotate(0deg);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.blessing-subtitle {
|
||
font-size: 28rpx;
|
||
color: #FF9500;
|
||
font-weight: 700;
|
||
margin-top: 12rpx;
|
||
margin-bottom: 8rpx;
|
||
opacity: 0;
|
||
animation: subtitleFadeIn 0.5s ease-out 0.3s forwards;
|
||
}
|
||
|
||
@keyframes subtitleFadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(10rpx);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.blessing-text {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 12rpx;
|
||
margin-top: 16rpx;
|
||
|
||
.char {
|
||
font-size: 48rpx;
|
||
font-weight: 900;
|
||
color: #FF6B00;
|
||
text-shadow: 0 4rpx 12rpx rgba(255, 107, 0, 0.3);
|
||
opacity: 0;
|
||
animation: charAppear 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
||
}
|
||
|
||
.char.from-left {
|
||
animation-name: charAppearFromLeft;
|
||
}
|
||
|
||
.char.from-right {
|
||
animation-name: charAppearFromRight;
|
||
}
|
||
}
|
||
|
||
@keyframes charAppear {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateY(30rpx) scale(0.5);
|
||
}
|
||
60% {
|
||
transform: translateY(-8rpx) scale(1.1);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateY(0) scale(1);
|
||
}
|
||
}
|
||
|
||
@keyframes charAppearFromLeft {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateX(-80rpx) scale(0.5);
|
||
}
|
||
60% {
|
||
transform: translateX(10rpx) scale(1.1);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateX(0) scale(1);
|
||
}
|
||
}
|
||
|
||
@keyframes charAppearFromRight {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateX(80rpx) scale(0.5);
|
||
}
|
||
60% {
|
||
transform: translateX(-10rpx) scale(1.1);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateX(0) scale(1);
|
||
}
|
||
}
|
||
|
||
/* ============================================
|
||
柯大鸭潮玩 - 支付弹窗组件
|
||
采用暖橙色调的底部弹窗设计
|
||
============================================ */
|
||
|
||
.payment-popup-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.55);
|
||
z-index: 999;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.payment-popup-content {
|
||
width: 100%;
|
||
background: $bg-card;
|
||
border-radius: $radius-xl $radius-xl 0 0;
|
||
padding: $spacing-lg;
|
||
padding-bottom: calc($spacing-lg + constant(safe-area-inset-bottom));
|
||
padding-bottom: calc($spacing-lg + env(safe-area-inset-bottom));
|
||
animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
position: relative;
|
||
}
|
||
|
||
@keyframes slideUp {
|
||
from { transform: translateY(100%); }
|
||
to { transform: translateY(0); }
|
||
}
|
||
|
||
.risk-warning {
|
||
background: linear-gradient(135deg, #FFF8F3, #FFF4E6);
|
||
color: #B45309;
|
||
font-size: $font-xs;
|
||
padding: $spacing-sm $spacing-md;
|
||
border-radius: $radius-md;
|
||
margin-bottom: $spacing-md;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
line-height: 1.5;
|
||
text-align: center;
|
||
border: 1rpx solid rgba(255, 159, 67, 0.2);
|
||
}
|
||
|
||
.agreement-link {
|
||
color: $brand-primary;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.popup-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: $spacing-lg;
|
||
position: relative;
|
||
}
|
||
.popup-title {
|
||
font-size: $font-lg;
|
||
font-weight: 700;
|
||
color: $text-main;
|
||
}
|
||
.close-icon {
|
||
position: absolute;
|
||
right: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
font-size: 48rpx;
|
||
color: $text-placeholder;
|
||
line-height: 1;
|
||
padding: 10rpx;
|
||
transition: color 0.2s ease;
|
||
}
|
||
.close-icon:active {
|
||
color: $text-secondary;
|
||
}
|
||
|
||
.popup-body {
|
||
padding: $spacing-sm 0 $spacing-md;
|
||
}
|
||
|
||
.amount-section {
|
||
text-align: center;
|
||
margin-bottom: $spacing-xl;
|
||
padding: $spacing-md;
|
||
background: linear-gradient(145deg, #FFFFFF, #FFF8F3);
|
||
border-radius: $radius-lg;
|
||
border: 1rpx solid rgba(255, 159, 67, 0.1);
|
||
}
|
||
.amount-section .label {
|
||
font-size: $font-sm;
|
||
color: $text-secondary;
|
||
margin-right: $spacing-xs;
|
||
}
|
||
.amount-section .amount {
|
||
font-size: 56rpx;
|
||
font-weight: 800;
|
||
background: $gradient-brand;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
.form-item {
|
||
margin-bottom: $spacing-md;
|
||
}
|
||
.form-item .label {
|
||
display: block;
|
||
font-size: $font-sm;
|
||
color: $text-main;
|
||
font-weight: 600;
|
||
margin-bottom: $spacing-xs;
|
||
}
|
||
|
||
.picker-full {
|
||
width: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.picker-display {
|
||
border: 2rpx solid $border-color-light;
|
||
border-radius: $radius-md;
|
||
padding: $spacing-md;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: $font-sm;
|
||
background: $bg-page;
|
||
transition: all 0.2s ease;
|
||
}
|
||
.picker-display:active {
|
||
border-color: $brand-primary;
|
||
background: #FFF8F3;
|
||
}
|
||
|
||
.selected-text {
|
||
color: $text-main;
|
||
font-weight: 500;
|
||
}
|
||
.placeholder {
|
||
color: $text-placeholder;
|
||
}
|
||
.arrow {
|
||
color: $text-placeholder;
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-right: 3rpx solid $text-placeholder;
|
||
border-bottom: 3rpx solid $text-placeholder;
|
||
transform: rotate(-45deg);
|
||
margin-right: $spacing-xs;
|
||
}
|
||
|
||
.popup-footer {
|
||
display: flex;
|
||
gap: $spacing-md;
|
||
margin-top: $spacing-sm;
|
||
}
|
||
.btn-cancel, .btn-confirm {
|
||
flex: 1;
|
||
border: none;
|
||
border-radius: $radius-lg;
|
||
font-size: $font-md;
|
||
padding: $spacing-md 0;
|
||
line-height: 1.5;
|
||
font-weight: 600;
|
||
transition: all 0.2s ease;
|
||
}
|
||
.btn-cancel::after, .btn-confirm::after {
|
||
border: none;
|
||
}
|
||
.btn-cancel {
|
||
color: $text-secondary;
|
||
background: #F3F4F6;
|
||
}
|
||
.btn-cancel:active {
|
||
background: $border-color-light;
|
||
}
|
||
.btn-confirm {
|
||
color: #FFFFFF;
|
||
background: $gradient-brand;
|
||
box-shadow: $shadow-lg;
|
||
}
|
||
.btn-confirm:active {
|
||
transform: scale(0.97);
|
||
box-shadow: $shadow-md;
|
||
}
|
||
|
||
/* 次数卡使用按钮特殊样式 */
|
||
.btn-game-pass {
|
||
background: linear-gradient(135deg, #10B981, #059669);
|
||
}
|
||
|
||
/* ============================================
|
||
次数卡选项样式
|
||
============================================ */
|
||
.game-pass-section {
|
||
margin-bottom: $spacing-md;
|
||
}
|
||
|
||
.game-pass-option {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: $spacing-md;
|
||
background: linear-gradient(135deg, #ECFDF5, #D1FAE5);
|
||
border: 2rpx solid #10B981;
|
||
border-radius: $radius-lg;
|
||
transition: all 0.2s ease;
|
||
|
||
&.active {
|
||
background: linear-gradient(135deg, #10B981, #059669);
|
||
border-color: #059669;
|
||
|
||
.game-pass-label, .game-pass-count {
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.game-pass-radio {
|
||
background: #FFFFFF;
|
||
border-color: #FFFFFF;
|
||
}
|
||
|
||
.radio-checked {
|
||
color: #10B981;
|
||
}
|
||
}
|
||
|
||
&.disabled {
|
||
background: #F9FAFB;
|
||
border-color: #E5E7EB;
|
||
|
||
.game-pass-radio {
|
||
border-color: #D1D5DB;
|
||
background: #F3F4F6;
|
||
}
|
||
}
|
||
}
|
||
|
||
.game-pass-radio {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
border-radius: 50%;
|
||
border: 3rpx solid #10B981;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: $spacing-sm;
|
||
}
|
||
|
||
.radio-checked {
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
color: #10B981;
|
||
}
|
||
|
||
.game-pass-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.game-pass-label {
|
||
font-size: $font-md;
|
||
font-weight: 600;
|
||
color: #059669;
|
||
}
|
||
|
||
.game-pass-count {
|
||
font-size: $font-sm;
|
||
color: #10B981;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.divider-line {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: $spacing-md;
|
||
|
||
&::before, &::after {
|
||
content: '';
|
||
flex: 1;
|
||
height: 1rpx;
|
||
background: $border-color-light;
|
||
}
|
||
}
|
||
|
||
.divider-text {
|
||
font-size: $font-xs;
|
||
color: $text-placeholder;
|
||
padding: 0 $spacing-sm;
|
||
}
|
||
|
||
.radio-disabled {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
background: #D1D5DB;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.text-disabled {
|
||
color: #9CA3AF !important;
|
||
}
|
||
</style>
|
||
|