939 lines
33 KiB
HTML
939 lines
33 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||
<title>🎮 Net-Games 游戏大厅</title>
|
||
<script>
|
||
// 强制刷新缓存
|
||
if (!window.location.search.includes('v=2')) {
|
||
window.location.replace(window.location.pathname + '?v=2');
|
||
}
|
||
</script>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||
min-height: 100vh;
|
||
color: #fff;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* 头部 */
|
||
.header {
|
||
text-align: center;
|
||
padding: 40px 20px 30px;
|
||
background: rgba(0, 0, 0, 0.2);
|
||
backdrop-filter: blur(10px);
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.header h1 {
|
||
font-size: 2.5rem;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
margin-bottom: 10px;
|
||
text-shadow: 0 0 30px rgba(102, 126, 234, 0.3);
|
||
}
|
||
|
||
.header p {
|
||
color: #888;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
/* 游戏网格容器 */
|
||
.games-container {
|
||
max-width: 1600px;
|
||
margin: 0 auto;
|
||
padding: 30px 20px 60px;
|
||
}
|
||
|
||
.games-grid {
|
||
display: grid;
|
||
gap: 20px;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
@media (min-width: 640px) {
|
||
.games-grid { grid-template-columns: repeat(3, 1fr); }
|
||
}
|
||
|
||
@media (min-width: 900px) {
|
||
.games-grid { grid-template-columns: repeat(4, 1fr); }
|
||
}
|
||
|
||
@media (min-width: 1200px) {
|
||
.games-grid { grid-template-columns: repeat(5, 1fr); }
|
||
}
|
||
|
||
/* 游戏卡片 */
|
||
.game-card {
|
||
position: relative;
|
||
background: linear-gradient(145deg, #1e293b 0%, #0f172a 100%);
|
||
border-radius: 16px;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
aspect-ratio: 3/4;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.game-card:hover {
|
||
transform: translateY(-8px) scale(1.02);
|
||
box-shadow: 0 20px 40px rgba(102, 126, 234, 0.3);
|
||
border-color: rgba(102, 126, 234, 0.5);
|
||
}
|
||
|
||
.game-card:active {
|
||
transform: translateY(-4px) scale(0.98);
|
||
}
|
||
|
||
.game-icon {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 4rem;
|
||
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2) 0%, rgba(118, 75, 162, 0.2) 100%);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.game-icon::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: -50%;
|
||
left: -50%;
|
||
width: 200%;
|
||
height: 200%;
|
||
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 60%);
|
||
animation: shimmer 3s infinite;
|
||
}
|
||
|
||
@keyframes shimmer {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
.game-info {
|
||
padding: 15px;
|
||
background: rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
.game-title {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
margin-bottom: 5px;
|
||
color: #fff;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.game-desc {
|
||
font-size: 0.75rem;
|
||
color: #888;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.game-tag {
|
||
display: inline-block;
|
||
padding: 3px 8px;
|
||
background: rgba(102, 126, 234, 0.3);
|
||
border-radius: 12px;
|
||
font-size: 0.7rem;
|
||
color: #a5b4fc;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.game-score {
|
||
display: inline-block;
|
||
padding: 3px 10px;
|
||
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
||
border-radius: 12px;
|
||
font-size: 0.75rem;
|
||
color: #fff;
|
||
margin-top: 8px;
|
||
margin-left: 6px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.new-badge {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 10px;
|
||
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a5a 100%);
|
||
color: #fff;
|
||
padding: 4px 10px;
|
||
border-radius: 12px;
|
||
font-size: 0.7rem;
|
||
font-weight: 600;
|
||
z-index: 10;
|
||
box-shadow: 0 4px 10px rgba(238, 90, 90, 0.4);
|
||
}
|
||
|
||
.hot-badge {
|
||
position: absolute;
|
||
top: 10px;
|
||
left: 10px;
|
||
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
||
color: #fff;
|
||
padding: 4px 10px;
|
||
border-radius: 12px;
|
||
font-size: 0.7rem;
|
||
font-weight: 600;
|
||
z-index: 10;
|
||
box-shadow: 0 4px 10px rgba(217, 119, 6, 0.4);
|
||
}
|
||
|
||
/* 页脚 */
|
||
.footer {
|
||
text-align: center;
|
||
padding: 30px 20px;
|
||
color: #666;
|
||
font-size: 0.85rem;
|
||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
/* 分类标题 */
|
||
.category-title {
|
||
font-size: 1.3rem;
|
||
margin: 30px 0 20px;
|
||
padding-left: 10px;
|
||
border-left: 4px solid #667eea;
|
||
color: #fff;
|
||
}
|
||
|
||
/* ========== 登录弹窗 ========== */
|
||
.login-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0,0,0,0.85);
|
||
z-index: 10000;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
backdrop-filter: blur(8px);
|
||
}
|
||
|
||
.login-overlay.hidden {
|
||
display: none !important;
|
||
}
|
||
|
||
.login-input.hidden {
|
||
display: none !important;
|
||
}
|
||
|
||
.login-box {
|
||
background: linear-gradient(145deg, #1e293b 0%, #0f172a 100%);
|
||
padding: 30px;
|
||
border-radius: 16px;
|
||
width: 90%;
|
||
max-width: 360px;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.login-title {
|
||
text-align: center;
|
||
font-size: 22px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
color: #fff;
|
||
}
|
||
|
||
.login-subtitle {
|
||
text-align: center;
|
||
font-size: 14px;
|
||
color: #888;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.login-input {
|
||
width: 100%;
|
||
padding: 14px 16px;
|
||
margin-bottom: 12px;
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
border-radius: 10px;
|
||
font-size: 16px;
|
||
background: rgba(0, 0, 0, 0.3);
|
||
color: #fff;
|
||
transition: border-color 0.2s;
|
||
}
|
||
|
||
.login-input:focus {
|
||
outline: none;
|
||
border-color: #667eea;
|
||
}
|
||
|
||
.login-input::placeholder {
|
||
color: #666;
|
||
}
|
||
|
||
.login-btn {
|
||
width: 100%;
|
||
padding: 14px;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 10px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: opacity 0.2s;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.login-btn:hover { opacity: 0.9; }
|
||
.login-btn:disabled {
|
||
background: #444;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.login-error {
|
||
color: #ff6b6b;
|
||
font-size: 14px;
|
||
margin-top: 12px;
|
||
text-align: center;
|
||
display: none;
|
||
}
|
||
|
||
.login-error.show { display: block; }
|
||
|
||
.login-link {
|
||
text-align: center;
|
||
margin-top: 16px;
|
||
font-size: 14px;
|
||
color: #888;
|
||
}
|
||
|
||
.login-link a {
|
||
color: #667eea;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.login-link a:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* ========== 用户信息栏 ========== */
|
||
.user-bar {
|
||
position: fixed;
|
||
top: 10px;
|
||
right: 10px;
|
||
display: none;
|
||
align-items: center;
|
||
gap: 10px;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
padding: 8px 16px;
|
||
border-radius: 20px;
|
||
backdrop-filter: blur(10px);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
z-index: 1000;
|
||
}
|
||
|
||
.user-bar.visible { display: flex; }
|
||
|
||
.user-info { font-size: 13px; color: #ccc; }
|
||
.user-name { color: #fff; font-weight: 600; }
|
||
|
||
.logout-btn {
|
||
padding: 4px 12px;
|
||
background: rgba(255, 59, 48, 0.8);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 12px;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.logout-btn:hover { background: rgba(255, 59, 48, 1); }
|
||
|
||
.settings-btn {
|
||
padding: 4px 12px;
|
||
background: rgba(102, 126, 234, 0.8);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 12px;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.settings-btn:hover { background: rgba(102, 126, 234, 1); }
|
||
|
||
@keyframes shake {
|
||
0%, 100% { transform: translateX(0); }
|
||
25% { transform: translateX(-5px); }
|
||
75% { transform: translateX(5px); }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- 登录/注册弹窗 - 默认隐藏,由JS控制显示 -->
|
||
<div class="login-overlay hidden" id="loginOverlay" style="display: none;">
|
||
<div class="login-box">
|
||
<div class="login-title" id="authTitle">🔒 Net-Games</div>
|
||
<div class="login-subtitle" id="authSubtitle">请先登录后进入游戏大厅</div>
|
||
<input type="text" class="login-input" id="username" placeholder="用户名" autocomplete="username">
|
||
<input type="password" class="login-input" id="password" placeholder="密码" autocomplete="current-password">
|
||
<input type="password" class="login-input hidden" id="password2" placeholder="确认密码" autocomplete="new-password">
|
||
<button class="login-btn" id="authBtn" onclick="doAuth()">登录</button>
|
||
<div class="login-error" id="loginError"></div>
|
||
<div class="login-link">
|
||
<span id="authSwitchText">还没有账号?</span>
|
||
<a id="authSwitchLink" onclick="toggleAuthMode()">立即注册</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 用户信息栏 -->
|
||
<div class="user-bar" id="userBar">
|
||
<div class="user-info">
|
||
👤 <span class="user-name" id="userName"></span>
|
||
<span id="adminBadge" style="display: none; background: #ff6b6b; color: white; padding: 2px 6px; border-radius: 4px; font-size: 11px; margin-left: 6px;">管理员</span>
|
||
</div>
|
||
<button class="settings-btn" id="adminBtn" style="display: none; background: #ff6b6b;" onclick="showAdminPanel()">管理</button>
|
||
<button class="settings-btn" onclick="showSettingsModal()">设置</button>
|
||
<button class="logout-btn" onclick="doLogout()">退出</button>
|
||
</div>
|
||
|
||
<!-- 个人设置弹窗 -->
|
||
<div class="login-overlay hidden" id="settingsOverlay" style="display: none;">
|
||
<div class="login-box">
|
||
<div class="login-title">⚙️ 个人设置</div>
|
||
<div class="login-subtitle">修改昵称和密码</div>
|
||
|
||
<div style="margin-bottom: 20px; padding: 12px; background: rgba(102, 126, 234, 0.1); border-radius: 8px;">
|
||
<div style="font-size: 13px; color: #888;">用户名(不可修改)</div>
|
||
<div id="settingsUsername" style="font-size: 16px; color: #fff; font-weight: 600;"></div>
|
||
</div>
|
||
|
||
<input type="text" class="login-input" id="settingNickname" placeholder="昵称" maxlength="20">
|
||
|
||
<div style="margin: 20px 0; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 20px;">
|
||
<div style="font-size: 14px; color: #888; margin-bottom: 12px;">🔒 修改密码(可选)</div>
|
||
<input type="password" class="login-input" id="settingOldPassword" placeholder="当前密码">
|
||
<input type="password" class="login-input" id="settingNewPassword" placeholder="新密码(至少6位)">
|
||
</div>
|
||
|
||
<button class="login-btn" onclick="saveSettings()">保存设置</button>
|
||
<div class="login-error" id="settingsError"></div>
|
||
|
||
<div class="login-link">
|
||
<a onclick="hideSettingsModal()">取消</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<header class="header">
|
||
<h1>🎮 Net-Games 游戏大厅</h1>
|
||
<p>Socket.IO 实时对战游戏平台</p>
|
||
<p style="font-size: 0.8rem; margin-top: 5px; opacity: 0.7;">支持人机对战、AI对战、多人联机</p>
|
||
</header>
|
||
|
||
<main class="games-container">
|
||
<h2 class="category-title">🔥 热门对战</h2>
|
||
<div class="games-grid" id="gamesGrid">
|
||
<!-- 游戏卡片动态生成 -->
|
||
</div>
|
||
|
||
<h2 class="category-title">🆕 即将上线</h2>
|
||
<div class="games-grid" id="comingSoonGrid">
|
||
<!-- 即将上线 -->
|
||
</div>
|
||
</main>
|
||
|
||
<footer class="footer">
|
||
<p>🎮 Net-Games 游戏大厅 | 实时对战,随时开局</p>
|
||
</footer>
|
||
|
||
<script>
|
||
// 游戏配置 - 添加新游戏只需修改这里
|
||
const games = [
|
||
{
|
||
id: 'doudizhu',
|
||
title: '🃏 斗地主',
|
||
desc: '经典三人扑克,支持人类 vs AI、AI vs AI 多种对战模式',
|
||
icon: '🃏',
|
||
url: '/doudizhu/',
|
||
tag: '扑克棋牌',
|
||
isNew: true,
|
||
isHot: true,
|
||
category: 'hot'
|
||
}
|
||
// 后续添加更多游戏...
|
||
// {
|
||
// id: 'chinese-chess',
|
||
// title: '♟️ 中国象棋',
|
||
// desc: '人机对弈,Minimax + DeepSeek AI',
|
||
// icon: '♟️',
|
||
// url: '/chinese-chess/',
|
||
// tag: '棋牌策略',
|
||
// isNew: false,
|
||
// isHot: true
|
||
// }
|
||
];
|
||
|
||
const comingSoonGames = [
|
||
{
|
||
id: 'chinese-chess',
|
||
title: '♟️ 中国象棋',
|
||
desc: '人机对弈,Minimax + DeepSeek AI(开发中)',
|
||
icon: '♟️',
|
||
url: '#',
|
||
tag: '即将上线',
|
||
disabled: true
|
||
},
|
||
{
|
||
id: 'guandan',
|
||
title: '🃏 掼蛋',
|
||
desc: '4人2v2对家组队(开发中)',
|
||
icon: '🃏',
|
||
url: '#',
|
||
tag: '即将上线',
|
||
disabled: true
|
||
}
|
||
];
|
||
|
||
let isAuthenticated = false;
|
||
|
||
// 用户各游戏积分
|
||
let userGameScores = {};
|
||
|
||
// 创建游戏卡片
|
||
function createGameCard(game) {
|
||
const badges = [];
|
||
if (game.isHot) badges.push('<span class="hot-badge">🔥 HOT</span>');
|
||
if (game.isNew) badges.push('<span class="new-badge">NEW</span>');
|
||
|
||
// 显示该游戏积分(如果已获取)
|
||
const score = userGameScores[game.id];
|
||
const scoreHtml = score !== undefined && !game.disabled
|
||
? `<div class="game-score">🏆 积分: ${score}</div>`
|
||
: '';
|
||
|
||
return `
|
||
<div class="game-card" data-id="${game.id}" data-url="${game.url}"
|
||
${game.disabled ? '' : 'onclick="handleGameClick(this)"'}
|
||
style="${game.disabled ? 'opacity: 0.6; cursor: not-allowed;' : ''}">
|
||
${badges.join('')}
|
||
<div class="game-icon">${game.icon}</div>
|
||
<div class="game-info">
|
||
<div class="game-title">${game.title}</div>
|
||
<div class="game-desc">${game.desc}</div>
|
||
<span class="game-tag">${game.tag}</span>
|
||
${scoreHtml}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
// 获取用户各游戏积分
|
||
async function fetchUserScores() {
|
||
if (!isAuthenticated) return;
|
||
|
||
try {
|
||
const response = await fetch('/api/user/scores', {
|
||
credentials: 'include'
|
||
});
|
||
const data = await response.json();
|
||
if (data.success) {
|
||
userGameScores = data.scores || {};
|
||
renderGames(); // 重新渲染以显示积分
|
||
}
|
||
} catch (error) {
|
||
console.error('获取积分失败:', error);
|
||
}
|
||
}
|
||
|
||
// 处理游戏点击
|
||
function handleGameClick(element) {
|
||
if (!isAuthenticated) {
|
||
element.style.animation = 'shake 0.3s';
|
||
setTimeout(() => element.style.animation = '', 300);
|
||
showLoginOverlay();
|
||
return;
|
||
}
|
||
const url = element.dataset.url;
|
||
window.location.href = url;
|
||
}
|
||
|
||
// 渲染游戏列表
|
||
function renderGames() {
|
||
const hotGames = games.filter(g => g.category === 'hot' || g.isHot);
|
||
document.getElementById('gamesGrid').innerHTML = hotGames.map(createGameCard).join('');
|
||
document.getElementById('comingSoonGrid').innerHTML = comingSoonGames.map(createGameCard).join('');
|
||
}
|
||
|
||
// ========== 登录相关 ==========
|
||
function showLoginOverlay() {
|
||
const overlay = document.getElementById('loginOverlay');
|
||
overlay.style.display = '';
|
||
overlay.classList.remove('hidden');
|
||
}
|
||
|
||
function hideLoginOverlay() {
|
||
const overlay = document.getElementById('loginOverlay');
|
||
overlay.classList.add('hidden');
|
||
// 保留内联样式确保隐藏
|
||
overlay.style.display = 'none';
|
||
}
|
||
|
||
function showUserBar(user) {
|
||
currentUser = user;
|
||
document.getElementById('userName').textContent = user.nickname || user.username;
|
||
document.getElementById('userBar').classList.add('visible');
|
||
|
||
// 显示管理员标记和按钮
|
||
if (user.is_admin || user.role === 'admin') {
|
||
document.getElementById('adminBadge').style.display = 'inline-block';
|
||
document.getElementById('adminBtn').style.display = 'inline-block';
|
||
} else {
|
||
document.getElementById('adminBadge').style.display = 'none';
|
||
document.getElementById('adminBtn').style.display = 'none';
|
||
}
|
||
}
|
||
|
||
function hideUserBar() {
|
||
document.getElementById('userBar').classList.remove('visible');
|
||
}
|
||
|
||
// ========== 管理员面板 ==========
|
||
function showAdminPanel() {
|
||
alert('🛠️ 管理员功能开发中...\n\n计划功能:\n• 查看在线统计\n• 管理房间列表\n• 强制关闭房间\n• 用户管理');
|
||
}
|
||
|
||
// ========== 个人设置 ==========
|
||
let currentUser = null;
|
||
|
||
function showSettingsModal() {
|
||
if (!currentUser) return;
|
||
|
||
document.getElementById('settingsUsername').textContent = currentUser.username;
|
||
document.getElementById('settingNickname').value = currentUser.nickname || currentUser.username;
|
||
document.getElementById('settingOldPassword').value = '';
|
||
document.getElementById('settingNewPassword').value = '';
|
||
document.getElementById('settingsError').classList.remove('show');
|
||
|
||
const overlay = document.getElementById('settingsOverlay');
|
||
overlay.style.display = '';
|
||
overlay.classList.remove('hidden');
|
||
}
|
||
|
||
function hideSettingsModal() {
|
||
const overlay = document.getElementById('settingsOverlay');
|
||
overlay.classList.add('hidden');
|
||
overlay.style.display = 'none';
|
||
}
|
||
|
||
async function saveSettings() {
|
||
const nickname = document.getElementById('settingNickname').value.trim();
|
||
const oldPassword = document.getElementById('settingOldPassword').value;
|
||
const newPassword = document.getElementById('settingNewPassword').value;
|
||
const errorDiv = document.getElementById('settingsError');
|
||
const btn = document.querySelector('#settingsOverlay .login-btn');
|
||
|
||
// 验证昵称
|
||
if (!nickname || nickname.length < 2 || nickname.length > 20) {
|
||
errorDiv.textContent = '昵称长度需在2-20个字符之间';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
// 验证密码(如果填写了)
|
||
if (newPassword && newPassword.length < 6) {
|
||
errorDiv.textContent = '新密码长度至少6位';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
if (newPassword && !oldPassword) {
|
||
errorDiv.textContent = '修改密码需要填写当前密码';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
btn.disabled = true;
|
||
btn.textContent = '保存中...';
|
||
|
||
try {
|
||
// 更新昵称
|
||
const profileRes = await fetch('/api/user/profile', {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: 'include',
|
||
body: JSON.stringify({ nickname })
|
||
});
|
||
|
||
const profileData = await profileRes.json();
|
||
|
||
if (!profileData.success) {
|
||
errorDiv.textContent = profileData.error || '更新昵称失败';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
// 更新密码(如果填写了)
|
||
if (newPassword) {
|
||
const pwdRes = await fetch('/api/user/password', {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: 'include',
|
||
body: JSON.stringify({ old_password: oldPassword, new_password: newPassword })
|
||
});
|
||
|
||
const pwdData = await pwdRes.json();
|
||
|
||
if (!pwdData.success) {
|
||
errorDiv.textContent = pwdData.error || '修改密码失败';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
// 密码修改成功,需要重新登录
|
||
alert('密码修改成功,请重新登录');
|
||
doLogout();
|
||
hideSettingsModal();
|
||
return;
|
||
}
|
||
|
||
// 更新本地用户信息
|
||
currentUser = profileData.user;
|
||
document.getElementById('userName').textContent = currentUser.nickname || currentUser.username;
|
||
|
||
hideSettingsModal();
|
||
|
||
} catch (error) {
|
||
errorDiv.textContent = '网络错误,请重试';
|
||
errorDiv.classList.add('show');
|
||
} finally {
|
||
btn.disabled = false;
|
||
btn.textContent = '保存设置';
|
||
}
|
||
}
|
||
|
||
async function checkAuth() {
|
||
try {
|
||
const response = await fetch('/api/auth/status', {
|
||
credentials: 'include',
|
||
cache: 'no-cache'
|
||
});
|
||
const data = await response.json();
|
||
|
||
isAuthenticated = data.authenticated;
|
||
console.log('登录状态:', isAuthenticated);
|
||
|
||
if (isAuthenticated) {
|
||
hideLoginOverlay();
|
||
showUserBar(data.user);
|
||
// 获取用户各游戏积分
|
||
await fetchUserScores();
|
||
} else {
|
||
// 未登录也可以浏览,但点击游戏需要登录
|
||
hideLoginOverlay();
|
||
}
|
||
} catch (error) {
|
||
console.error('检查登录状态失败:', error);
|
||
hideLoginOverlay();
|
||
}
|
||
}
|
||
|
||
let isRegisterMode = false;
|
||
|
||
function toggleAuthMode() {
|
||
isRegisterMode = !isRegisterMode;
|
||
const title = document.getElementById('authTitle');
|
||
const subtitle = document.getElementById('authSubtitle');
|
||
const btn = document.getElementById('authBtn');
|
||
const switchText = document.getElementById('authSwitchText');
|
||
const switchLink = document.getElementById('authSwitchLink');
|
||
const password2 = document.getElementById('password2');
|
||
const errorDiv = document.getElementById('loginError');
|
||
|
||
errorDiv.classList.remove('show');
|
||
|
||
if (isRegisterMode) {
|
||
title.textContent = '📝 注册账号';
|
||
subtitle.textContent = '创建新账号开始游戏';
|
||
btn.textContent = '注册';
|
||
switchText.textContent = '已有账号?';
|
||
switchLink.textContent = '立即登录';
|
||
password2.classList.remove('hidden');
|
||
} else {
|
||
title.textContent = '🔒 Net-Games';
|
||
subtitle.textContent = '请先登录后进入游戏大厅';
|
||
btn.textContent = '登录';
|
||
switchText.textContent = '还没有账号?';
|
||
switchLink.textContent = '立即注册';
|
||
password2.classList.add('hidden');
|
||
}
|
||
}
|
||
|
||
async function doAuth() {
|
||
if (isRegisterMode) {
|
||
await doRegister();
|
||
} else {
|
||
await doLogin();
|
||
}
|
||
}
|
||
|
||
async function doLogin() {
|
||
const username = document.getElementById('username').value.trim();
|
||
const password = document.getElementById('password').value.trim();
|
||
const btn = document.getElementById('authBtn');
|
||
const errorDiv = document.getElementById('loginError');
|
||
|
||
if (!username || !password) {
|
||
errorDiv.textContent = '请输入用户名和密码';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
btn.disabled = true;
|
||
btn.textContent = '登录中...';
|
||
|
||
try {
|
||
const response = await fetch('/api/auth/login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: 'include',
|
||
body: JSON.stringify({ username, password })
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
isAuthenticated = true;
|
||
hideLoginOverlay();
|
||
showUserBar(data.user);
|
||
document.getElementById('username').value = '';
|
||
document.getElementById('password').value = '';
|
||
// 获取用户各游戏积分
|
||
await fetchUserScores();
|
||
} else {
|
||
errorDiv.textContent = data.error || '登录失败';
|
||
errorDiv.classList.add('show');
|
||
}
|
||
} catch (error) {
|
||
errorDiv.textContent = '网络错误,请重试';
|
||
errorDiv.classList.add('show');
|
||
} finally {
|
||
btn.disabled = false;
|
||
btn.textContent = '登录';
|
||
}
|
||
}
|
||
|
||
async function doRegister() {
|
||
const username = document.getElementById('username').value.trim();
|
||
const password = document.getElementById('password').value.trim();
|
||
const password2 = document.getElementById('password2').value.trim();
|
||
const btn = document.getElementById('authBtn');
|
||
const errorDiv = document.getElementById('loginError');
|
||
|
||
if (!username || !password) {
|
||
errorDiv.textContent = '请输入用户名和密码';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
if (username.length < 3) {
|
||
errorDiv.textContent = '用户名至少3个字符';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
if (password.length < 6) {
|
||
errorDiv.textContent = '密码至少6位';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
if (password !== password2) {
|
||
errorDiv.textContent = '两次输入的密码不一致';
|
||
errorDiv.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
btn.disabled = true;
|
||
btn.textContent = '注册中...';
|
||
|
||
try {
|
||
const response = await fetch('/api/auth/register', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: 'include',
|
||
body: JSON.stringify({ username, password })
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
isAuthenticated = true;
|
||
hideLoginOverlay();
|
||
showUserBar(data.user);
|
||
document.getElementById('username').value = '';
|
||
document.getElementById('password').value = '';
|
||
document.getElementById('password2').value = '';
|
||
// 切换回登录模式
|
||
toggleAuthMode();
|
||
alert('注册成功!欢迎加入 Net-Games!');
|
||
} else {
|
||
errorDiv.textContent = data.error || '注册失败';
|
||
errorDiv.classList.add('show');
|
||
}
|
||
} catch (error) {
|
||
errorDiv.textContent = '网络错误,请重试';
|
||
errorDiv.classList.add('show');
|
||
} finally {
|
||
btn.disabled = false;
|
||
btn.textContent = '注册';
|
||
}
|
||
}
|
||
|
||
async function doLogout() {
|
||
try {
|
||
await fetch('/api/auth/logout', {
|
||
method: 'POST',
|
||
credentials: 'include'
|
||
});
|
||
isAuthenticated = false;
|
||
hideUserBar();
|
||
showLoginOverlay();
|
||
} catch (error) {
|
||
console.error('登出失败:', error);
|
||
}
|
||
}
|
||
|
||
// 初始化
|
||
document.addEventListener('DOMContentLoaded', async () => {
|
||
await checkAuth();
|
||
renderGames();
|
||
|
||
// 回车登录
|
||
document.getElementById('password').addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') doLogin();
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|