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,