diff --git a/components/activity/LotteryResultPopup.vue b/components/activity/LotteryResultPopup.vue index 1d3b9b8..98441fa 100644 --- a/components/activity/LotteryResultPopup.vue +++ b/components/activity/LotteryResultPopup.vue @@ -14,7 +14,7 @@ 🎉 - 恭喜中奖 + 恭喜获得 @@ -58,7 +58,7 @@ - 收下奖励 + 知道了! diff --git a/pages-activity/activity/duiduipeng/index.vue b/pages-activity/activity/duiduipeng/index.vue index 9a18150..db4e536 100644 --- a/pages-activity/activity/duiduipeng/index.vue +++ b/pages-activity/activity/duiduipeng/index.vue @@ -94,13 +94,18 @@ + 总对数 {{ totalPairs }} - 摸牌机会 - {{ chance }} + {{ countdownSeconds > 0 ? '倒计时' : '摸牌机会' }} + + {{ countdownSeconds > 0 ? `${countdownSeconds}s` : chance }} + 牌组剩余 @@ -137,9 +142,6 @@ - @@ -240,6 +242,8 @@ const chance = ref(0) const totalPairs = ref(0) const gameFinished = ref(false) const pickedHandIndex = ref(-1) +const countdownTimer = ref(null) +const countdownSeconds = ref(0) const gameIdText = computed(() => String((gameEntry.value && gameEntry.value.game_id) || '')) const deckRemaining = computed(() => { const entry = gameEntry.value || null @@ -738,7 +742,14 @@ async function openGame(latest) { gameError.value = '' await applyResumeEntry(gameEntry.value) restoreOrInitLocalGame() - await autoDrawIfStuck() + + // 检查是否摸牌次数为0且无法继续配对 + if (Number(chance.value || 0) <= 0 && !canEliminateNow()) { + // 使用 setTimeout 确保界面先显示出来,再启动倒计时 + setTimeout(() => { + startCountdown() + }, 500) + } } function closeGame() { @@ -748,6 +759,44 @@ function closeGame() { gameEntry.value = null gameIssueId.value = '' pickedHandIndex.value = -1 + // 清理倒计时 + clearCountdown() +} + +function startCountdown() { + // 清除之前的倒计时 + clearCountdown() + + countdownSeconds.value = 3 + uni.showToast({ + title: `摸牌次数已用完,${countdownSeconds.value}秒后结束游戏`, + icon: 'none', + duration: 1000 + }) + + countdownTimer.value = setInterval(() => { + countdownSeconds.value -= 1 + + if (countdownSeconds.value > 0) { + uni.showToast({ + title: `${countdownSeconds.value}秒后结束游戏`, + icon: 'none', + duration: 900 + }) + } else { + // 倒计时结束,执行游戏结束逻辑 + clearCountdown() + finishAndReport() + } + }, 1000) +} + +function clearCountdown() { + if (countdownTimer.value) { + clearInterval(countdownTimer.value) + countdownTimer.value = null + } + countdownSeconds.value = 0 } function getSelectedCodeFromEntry(entry) { @@ -918,6 +967,11 @@ function manualDraw() { chance.value = Math.max(0, Number(chance.value || 0) - 1) pickedHandIndex.value = -1 persistLocalGame() + + // 检查摸牌次数是否为0且无法继续配对 + if (Number(chance.value || 0) <= 0 && !canEliminateNow()) { + startCountdown() + } } async function autoDrawIfStuck() { @@ -977,7 +1031,13 @@ async function onCellTap(cell) { chance.value = Number(chance.value || 0) + 1 pickedHandIndex.value = -1 persistLocalGame() - await autoDrawIfStuck() + + // 检查配对后是否无法继续配对且摸牌次数为0 + if (!canEliminateNow() && Number(chance.value || 0) <= 0) { + startCountdown() + } + + // 移除自动摸牌,让玩家手动控制 return } @@ -1099,8 +1159,17 @@ async function advanceOne() { return } + // 移除自动摸牌逻辑,让玩家手动控制 + // 如果无法配对,提示玩家需要摸牌 if (!canEliminateNow()) { - await autoDrawIfStuck() + if (Number(chance.value || 0) > 0 && canDrawOne()) { + uni.showToast({ title: '请摸牌后再试', icon: 'none' }) + } else if (Number(chance.value || 0) <= 0 && !canDrawOne()) { + // 摸牌次数为0且无法继续抽牌,再次确认场上无法配对才结束游戏 + if (!canEliminateNow()) { + await finishAndReport() + } + } return } @@ -2149,11 +2218,40 @@ onLoad((opts) => { .game-stats { display: flex; justify-content: center; - gap: 48rpx; + align-items: center; + gap: 32rpx; padding: 24rpx 32rpx; margin: 0 32rpx; } +.game-btn-draw { + flex-shrink: 0; + width: 120rpx; + height: 120rpx; + border-radius: 50%; + background: rgba(255, 255, 255, 0.15); + border: 3rpx solid rgba(255, 255, 255, 0.3); + color: #FF6B6B; + font-size: 28rpx; + font-weight: 800; + display: flex; + align-items: center; + justify-content: center; + backdrop-filter: blur(10rpx); + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3); + transition: all 0.3s; + + &:active { + transform: scale(0.9); + background: rgba(255, 255, 255, 0.25); + } + + &[disabled] { + opacity: 0.3; + transform: none; + } +} + .stat-item { display: flex; flex-direction: column; @@ -2171,6 +2269,22 @@ onLoad((opts) => { font-weight: 900; color: $accent-gold; font-family: 'DIN Alternate', sans-serif; + + &.countdown { + color: #FF6B6B; + animation: pulse 1s ease-in-out infinite; + } +} + +@keyframes pulse { + 0%, 100% { + opacity: 1; + transform: scale(1); + } + 50% { + opacity: 0.7; + transform: scale(1.1); + } } .game-content { @@ -2266,13 +2380,13 @@ onLoad((opts) => { .game-actions { display: flex; - gap: 24rpx; + justify-content: center; padding: 32rpx; padding-bottom: calc(32rpx + env(safe-area-inset-bottom)); } .game-btn { - flex: 1; + width: 400rpx; height: 96rpx; border-radius: 48rpx; font-size: 32rpx; @@ -2282,11 +2396,24 @@ onLoad((opts) => { justify-content: center; border: none; transition: all 0.3s; - + color: #fff; + + &.btn-primary { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.4); + } + + &.btn-secondary { + background: rgba(255, 255, 255, 0.15); + border: 2rpx solid rgba(255, 255, 255, 0.3); + color: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10rpx); + } + &:active { transform: scale(0.95); } - + &[disabled] { opacity: 0.4; }