355 lines
7.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page">
<!-- 背景 -->
<view class="bg-gradient"></view>
<!-- 头部 -->
<view class="header">
<view class="back-btn" @tap="goBack">
<text class="back-icon"></text>
</view>
<text class="title">🎮 动物扫雷大作战</text>
</view>
<!-- 主内容 -->
<view class="content">
<!-- 游戏图标 -->
<view class="game-icon-box">
<view class="game-icon">💣</view>
<view class="game-glow"></view>
</view>
<!-- 游戏介绍 -->
<view class="intro-card">
<text class="intro-title">多人对战扫雷</text>
<text class="intro-desc">和好友一起挑战获胜赢取精美奖品</text>
</view>
<!-- 资格显示 -->
<view class="ticket-card" v-if="!loading">
<view class="ticket-row">
<text class="ticket-label">我的游戏资格</text>
<view class="ticket-count-box">
<text class="ticket-count">{{ ticketCount }}</text>
<text class="ticket-unit"></text>
</view>
</view>
<text class="ticket-tip" v-if="ticketCount === 0">完成任务可获得游戏资格哦~</text>
</view>
<!-- 加载中 -->
<view v-else class="loading-box">
<text class="loading-text">加载中...</text>
</view>
</view>
<!-- 底部按钮 -->
<view class="footer">
<view
class="enter-btn"
:class="{ disabled: ticketCount <= 0 || entering }"
@tap="enterGame"
>
<text class="enter-btn-text">{{ entering ? '进入中...' : '进入游戏' }}</text>
</view>
<text class="footer-tip">每次进入消耗1次资格</text>
</view>
</view>
</template>
<script>
import { authRequest } from '../../../utils/request.js'
export default {
data() {
return {
loading: true,
ticketCount: 0,
entering: false,
gameCode: 'minesweeper'
}
},
onShow() {
this.loadTickets()
},
methods: {
goBack() {
uni.navigateBack()
},
async loadTickets() {
this.loading = true
try {
const userInfo = uni.getStorageSync('user_info') || {}
const userId = userInfo.id || userInfo.user_id
console.log('===== 调试游戏资格 =====')
console.log('userId:', userId)
if (!userId) {
console.log('未获取到用户ID返回0')
this.ticketCount = 0
return
}
const res = await authRequest({
url: `/api/app/users/${userId}/game_tickets`
})
console.log('API返回:', res)
// res 格式: { minesweeper: 3, poker: 0, ... }
this.ticketCount = res[this.gameCode] || 0
console.log('gameCode:', this.gameCode, 'ticketCount:', this.ticketCount)
} catch (e) {
console.error('加载游戏资格失败', e)
this.ticketCount = 0
} finally {
this.loading = false
}
},
async enterGame() {
if (this.ticketCount <= 0 || this.entering) return
this.entering = true
try {
const res = await authRequest({
url: '/api/app/games/enter',
method: 'POST',
data: {
game_code: this.gameCode
}
})
// 构建游戏URL传递安全认证参数
const gameBaseUrl = res.client_url || 'https://game.1024tool.vip'
const gameToken = encodeURIComponent(res.game_token)
const nakamaServer = encodeURIComponent(res.nakama_server)
const nakamaKey = encodeURIComponent(res.nakama_key)
const gameUrl = `${gameBaseUrl}?game_token=${gameToken}&nakama_server=${nakamaServer}&nakama_key=${nakamaKey}`
// 跳转到webview
uni.navigateTo({
url: `/pages-game/game/webview?url=${encodeURIComponent(gameUrl)}`
})
} catch (e) {
uni.showToast({
title: e.message || '进入游戏失败',
icon: 'none'
})
} finally {
this.entering = false
// 刷新资格数
this.loadTickets()
}
}
}
}
</script>
<style lang="scss">
.page {
min-height: 100vh;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
}
.bg-gradient {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(180deg, #E0C3FC 0%, #8EC5FC 50%, #E0E7FF 100%);
z-index: 0;
}
.header {
position: relative;
z-index: 1;
display: flex;
align-items: center;
padding: 24rpx 32rpx;
padding-top: calc(100rpx + env(safe-area-inset-top));
}
.back-btn {
width: 72rpx;
height: 72rpx;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
.back-icon {
font-size: 36rpx;
color: #333;
}
.title {
flex: 1;
text-align: center;
font-size: 36rpx;
font-weight: 800;
color: #333;
margin-right: 72rpx; // 平衡返回按钮
}
.content {
flex: 1;
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 48rpx;
}
.game-icon-box {
position: relative;
margin-bottom: 48rpx;
}
.game-icon {
font-size: 160rpx;
animation: bounce 2s ease-in-out infinite;
}
.game-glow {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200rpx;
height: 200rpx;
background: radial-gradient(circle, rgba(255,255,255,0.6) 0%, transparent 70%);
animation: pulse 2s ease-in-out infinite;
}
.intro-card {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-radius: 32rpx;
padding: 48rpx;
width: 100%;
text-align: center;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
margin-bottom: 32rpx;
}
.intro-title {
font-size: 40rpx;
font-weight: 800;
color: #333;
display: block;
margin-bottom: 16rpx;
}
.intro-desc {
font-size: 28rpx;
color: #666;
}
.ticket-card {
background: #fff;
border-radius: 24rpx;
padding: 32rpx 40rpx;
width: 100%;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
}
.ticket-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.ticket-label {
font-size: 30rpx;
color: #333;
font-weight: 600;
}
.ticket-count-box {
display: flex;
align-items: baseline;
}
.ticket-count {
font-size: 56rpx;
font-weight: 900;
color: #7C3AED;
}
.ticket-unit {
font-size: 28rpx;
color: #666;
margin-left: 8rpx;
}
.ticket-tip {
font-size: 24rpx;
color: #999;
margin-top: 16rpx;
display: block;
}
.loading-box {
padding: 60rpx;
}
.loading-text {
font-size: 28rpx;
color: #999;
}
.footer {
position: relative;
z-index: 1;
padding: 32rpx 48rpx;
padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
}
.enter-btn {
background: linear-gradient(135deg, #7C3AED 0%, #9F7AEA 100%);
border-radius: 48rpx;
padding: 32rpx;
text-align: center;
box-shadow: 0 8rpx 24rpx rgba(124, 58, 237, 0.4);
transition: all 0.2s;
}
.enter-btn:active {
transform: scale(0.98);
box-shadow: 0 4rpx 12rpx rgba(124, 58, 237, 0.3);
}
.enter-btn.disabled {
background: #CCC;
box-shadow: none;
}
.enter-btn-text {
font-size: 34rpx;
font-weight: 800;
color: #fff;
}
.footer-tip {
display: block;
text-align: center;
font-size: 24rpx;
color: #999;
margin-top: 16rpx;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20rpx); }
}
@keyframes pulse {
0%, 100% { opacity: 0.6; transform: translate(-50%, -50%) scale(1); }
50% { opacity: 1; transform: translate(-50%, -50%) scale(1.1); }
}
</style>