diff --git a/components/GamePassPurchasePopup.vue b/components/GamePassPurchasePopup.vue index fd4f002..0768b4f 100644 --- a/components/GamePassPurchasePopup.vue +++ b/components/GamePassPurchasePopup.vue @@ -211,76 +211,150 @@ function handleClose() { .popup-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.6); + background: rgba(0, 0, 0, 0.65); + backdrop-filter: blur(10rpx); z-index: 999; display: flex; align-items: flex-end; + animation: fadeIn 0.25s ease-out; +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } } .popup-content { width: 100%; - background: #FFFFFF; - border-radius: 32rpx 32rpx 0 0; + background: linear-gradient(180deg, #FFFFFF 0%, #FAFBFF 100%); + border-radius: 40rpx 40rpx 0 0; + box-shadow: 0 -8rpx 40rpx rgba(0, 0, 0, 0.12); padding-bottom: env(safe-area-inset-bottom); - max-height: 80vh; + max-height: 82vh; display: flex; flex-direction: column; + animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +@keyframes slideUp { + from { + transform: translateY(100%); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } } .popup-header { - padding: 32rpx; + padding: 40rpx 32rpx 24rpx; display: flex; justify-content: space-between; - align-items: center; - border-bottom: 1rpx solid #F3F4F6; - + align-items: flex-start; + border-bottom: 2rpx solid #F0F2F5; + background: linear-gradient(180deg, #FFFFFF 0%, #FAFBFF 100%); + position: relative; + + &::after { + content: ''; + position: absolute; + bottom: -8rpx; + left: 50%; + transform: translateX(-50%); + width: 80rpx; + height: 6rpx; + background: #E5E7EB; + border-radius: 3rpx; + } + .title { - font-size: 36rpx; - font-weight: bold; - color: #1F2937; + font-size: 38rpx; + font-weight: 800; + background: linear-gradient(135deg, #667EEA 0%, #764BA2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + letter-spacing: 0.5rpx; } .title-sub { - font-size: 34rpx; - font-weight: normal; + font-size: 22rpx; + font-weight: 400; + color: #9CA3AF; + margin-left: 8rpx; + -webkit-text-fill-color: #9CA3AF; } .close-btn { - font-size: 48rpx; - color: #9CA3AF; + font-size: 52rpx; + color: #CBD5E1; line-height: 0.8; - padding: 10rpx; + padding: 8rpx; + font-weight: 200; + transition: all 0.2s ease; + + &:active { + color: #667EEA; + transform: rotate(90deg); + } } } .packages-list { - padding: 32rpx; - max-height: 60vh; + padding: 32rpx 24rpx; + max-height: 62vh; } .loading-state, .empty-state { text-align: center; - padding: 60rpx 0; + padding: 80rpx 0; color: #9CA3AF; font-size: 28rpx; + font-weight: 500; + + &::before { + content: '📦'; + display: block; + font-size: 88rpx; + margin-bottom: 16rpx; + opacity: 0.4; + } } .package-item { position: relative; - background: linear-gradient(135deg, #FFFFFF, #F9FAFB); - border: 2rpx solid #E5E7EB; - border-radius: 24rpx; - padding: 24rpx 32rpx; - margin-bottom: 24rpx; + background: linear-gradient(145deg, #FFFFFF 0%, #F8F9FF 100%); + border: 2rpx solid #E8EEFF; + border-radius: 28rpx; + padding: 28rpx 24rpx; + margin-bottom: 20rpx; display: flex; justify-content: space-between; align-items: center; - transition: all 0.2s; + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); overflow: hidden; - + box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.08); + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 6rpx; + background: linear-gradient(90deg, #667EEA 0%, #764BA2 100%); + opacity: 0; + transition: opacity 0.3s; + } + &:active { - transform: scale(0.98); - background: #F3F4F6; + transform: scale(0.97); + box-shadow: 0 2rpx 12rpx rgba(102, 126, 234, 0.12); + } + + &:active::before { + opacity: 1; } } @@ -288,75 +362,119 @@ function handleClose() { position: absolute; top: 0; left: 0; - background: #FF6B00; + background: linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%); color: #FFF; font-size: 20rpx; - padding: 4rpx 12rpx; - border-bottom-right-radius: 12rpx; - font-weight: bold; + padding: 6rpx 16rpx; + border-bottom-right-radius: 16rpx; + font-weight: 700; + letter-spacing: 0.5rpx; + box-shadow: 0 4rpx 12rpx rgba(255, 107, 107, 0.3); + z-index: 1; } .pkg-left { flex: 1; + padding-right: 16rpx; } .pkg-name { - font-size: 32rpx; - font-weight: bold; + font-size: 34rpx; + font-weight: 700; color: #1F2937; - margin-bottom: 8rpx; + margin-bottom: 10rpx; + letter-spacing: 0.3rpx; } .pkg-count { font-size: 26rpx; - color: #4B5563; - margin-bottom: 4rpx; + color: #6B7280; + margin-bottom: 6rpx; + font-weight: 500; + display: flex; + align-items: center; + + &::before { + content: '🎮'; + font-size: 22rpx; + margin-right: 6rpx; + } } .pkg-validity { font-size: 22rpx; color: #9CA3AF; + font-weight: 400; + display: flex; + align-items: center; + + &::before { + content: '⏰'; + font-size: 18rpx; + margin-right: 4rpx; + } } .pkg-right { display: flex; flex-direction: column; align-items: flex-end; + min-width: 200rpx; } .pkg-price-row { - color: #FF6B00; - font-weight: bold; - margin-bottom: 4rpx; - + color: #FF6B6B; + font-weight: 800; + margin-bottom: 6rpx; + display: flex; + align-items: baseline; + letter-spacing: -0.5rpx; + .currency { - font-size: 24rpx; + font-size: 26rpx; + font-weight: 700; + margin-right: 2rpx; } .price { - font-size: 40rpx; + font-size: 44rpx; + text-shadow: 0 2rpx 8rpx rgba(255, 107, 107, 0.15); } } .pkg-original-price { font-size: 22rpx; - color: #9CA3AF; + color: #CBD5E1; text-decoration: line-through; - margin-bottom: 12rpx; + margin-bottom: 10rpx; + font-weight: 500; } .btn-buy { - background: linear-gradient(90deg, #FF6B00, #FF9F43); + background: linear-gradient(135deg, #667EEA 0%, #764BA2 100%); color: #FFF; - font-size: 24rpx; - padding: 0 20rpx; - height: 52rpx; - line-height: 52rpx; - border-radius: 26rpx; + font-size: 26rpx; + padding: 0 28rpx; + height: 60rpx; + line-height: 60rpx; + border-radius: 30rpx; border: none; - font-weight: 600; - + font-weight: 700; + box-shadow: 0 6rpx 20rpx rgba(102, 126, 234, 0.35); + transition: all 0.3s ease; + letter-spacing: 0.5rpx; + &[loading] { opacity: 0.8; + transform: scale(0.95); + } + + &:active { + transform: scale(0.92); + box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.4); + } + + &::after { + border: none; } } @@ -370,32 +488,46 @@ function handleClose() { .stepper { display: flex; align-items: center; - background: #F3F4F6; - border-radius: 12rpx; - padding: 2rpx; + background: linear-gradient(145deg, #F1F3F9 0%, #E8EEFF 100%); + border: 2rpx solid #E0E7FF; + border-radius: 16rpx; + padding: 4rpx; + box-shadow: inset 0 2rpx 6rpx rgba(102, 126, 234, 0.06); .step-btn { - width: 44rpx; - height: 44rpx; - line-height: 40rpx; + width: 48rpx; + height: 48rpx; + line-height: 44rpx; text-align: center; font-size: 32rpx; - color: #4B5563; - font-weight: 300; + color: #667EEA; + font-weight: 600; flex-shrink: 0; + transition: all 0.2s ease; + border-radius: 12rpx; + + &:active { + background: rgba(102, 126, 234, 0.1); + transform: scale(0.9); + } } .minus { color: #9CA3AF; + + &:active { + color: #667EEA; + background: rgba(102, 126, 234, 0.1); + } } .step-input { - width: 60rpx; - height: 44rpx; - line-height: 44rpx; + width: 64rpx; + height: 48rpx; + line-height: 48rpx; text-align: center; - font-size: 26rpx; - font-weight: bold; + font-size: 28rpx; + font-weight: 700; color: #1F2937; background: transparent; border: none; @@ -403,7 +535,7 @@ function handleClose() { margin: 0; &::placeholder { - color: #9CA3AF; + color: #CBD5E1; } } } diff --git a/pages-game/game/minesweeper/play.vue b/pages-game/game/minesweeper/play.vue index e4ddd9f..6b566f9 100644 --- a/pages-game/game/minesweeper/play.vue +++ b/pages-game/game/minesweeper/play.vue @@ -707,12 +707,13 @@ export default { this.addLog('system', endMsg); // 添加震动反馈 + // 微信小程序只支持 type: 'success' 或不传参数 if (winnerId === this.myUserId) { uni.vibrateShort({ type: 'success' }); } else if (winnerId === 'draw') { - uni.vibrateShort({ type: 'warning' }); + uni.vibrateShort(); // 平局使用普通震动 } else { - uni.vibrateShort({ type: 'fail' }); + uni.vibrateShort(); // 失败使用普通震动 } } }, diff --git a/pages-shop/shop/detail.vue b/pages-shop/shop/detail.vue index ce1b93e..1f1a004 100644 --- a/pages-shop/shop/detail.vue +++ b/pages-shop/shop/detail.vue @@ -8,7 +8,7 @@ {{ detail.title || detail.name || '-' }} - {{ (detail.points_required ? Math.floor(detail.points_required / 100) : 0) || (detail.price ? Math.floor(detail.price / 100) : 0) }} + {{ (detail.points_required ? (detail.points_required / 100).toFixed(1) : '0.0') || (detail.price ? (detail.price / 100).toFixed(1) : '0.0') }} 积分 @@ -74,7 +74,7 @@ async function onRedeem() { return } - const points = (detail.value.points_required ? Math.floor(detail.value.points_required / 100) : 0) || (detail.value.price ? Math.floor(detail.value.price / 100) : 0) + const points = (detail.value.points_required ? (detail.value.points_required / 100).toFixed(1) : '0.0') || (detail.value.price ? (detail.value.price / 100).toFixed(1) : '0.0') uni.showModal({ title: '确认兑换', content: `是否消耗 ${points} 积分兑换 ${p.title || p.name}?`, diff --git a/pages-user/points/index.vue b/pages-user/points/index.vue index b4dc970..fd80cbb 100644 --- a/pages-user/points/index.vue +++ b/pages-user/points/index.vue @@ -67,9 +67,9 @@ const pageSize = ref(20) const hasMore = ref(true) function formatPoints(v) { const n = Number(v) || 0 - if (n === 0) return '0' + if (n === 0) return '0.0' const f = n / 100 - return Number.isInteger(f) ? String(f) : f.toFixed(2).replace(/\.?0+$/, '') + return f.toFixed(1) } function formatTime(t) { diff --git a/pages/mine/index.vue b/pages/mine/index.vue index f0b6a9a..38df546 100644 --- a/pages/mine/index.vue +++ b/pages/mine/index.vue @@ -738,9 +738,9 @@ export default { }, formatPoints(v) { const n = Number(v) || 0 - if (n === 0) return '0' + if (n === 0) return '0.0' const f = n / 100 - return Number.isInteger(f) ? String(f) : f.toFixed(2).replace(/\.?0+$/, '') + return f.toFixed(1) }, copyInviteCode() { const code = this.getInviteCode() diff --git a/pages/shop/index.vue b/pages/shop/index.vue index efe1a6f..843826f 100644 --- a/pages/shop/index.vue +++ b/pages/shop/index.vue @@ -246,7 +246,7 @@ function normalizeItems(list, kind) { image: cleanUrl(i.main_image || i.image || ''), title: i.name || i.title || '', price: i.price || i.discount_value || 0, - points: i.points_required ? Math.floor(i.points_required / 100) : (i.price ? Math.floor(i.price / 100) : (i.discount_value ? Math.floor(i.discount_value / 100) : 0)), + points: i.points_required ? (i.points_required / 100).toFixed(1) : (i.price ? (i.price / 100).toFixed(1) : (i.discount_value ? (i.discount_value / 100).toFixed(1) : '0.0')), stock: i.in_stock ? 99 : 0, // Simplified stock check if returned as bool discount_value: i.discount_value || 0, min_spend: i.min_spend || 0,