增加用户管理
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
let ws = null, playerId = '', roomId = '', state = null, selected = [];
|
||||
let token = '', userId = '', username = '', nickname = '';
|
||||
let loginCaptchaId = '', regCaptchaId = '';
|
||||
const $ = id => document.getElementById(id);
|
||||
|
||||
function show(id) {
|
||||
@@ -13,13 +15,191 @@ function chat(name, msg, sys) {
|
||||
$('chatMsgs').scrollTop = 1e6;
|
||||
}
|
||||
|
||||
function authHeaders() {
|
||||
return {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token
|
||||
};
|
||||
}
|
||||
|
||||
async function getCaptcha(type) {
|
||||
try {
|
||||
const res = await fetch('/api/auth/captcha');
|
||||
const d = await res.json();
|
||||
if (d.code === 0) {
|
||||
if (type === 'login') {
|
||||
loginCaptchaId = d.data.captchaId;
|
||||
$('loginCaptchaImg').src = d.data.image;
|
||||
} else {
|
||||
regCaptchaId = d.data.captchaId;
|
||||
$('regCaptchaImg').src = d.data.image;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to get captcha:', e);
|
||||
}
|
||||
}
|
||||
|
||||
async function login() {
|
||||
const usernameVal = $('loginUsername').value.trim();
|
||||
const passwordVal = $('loginPassword').value;
|
||||
const captchaVal = $('loginCaptcha').value.trim().toUpperCase();
|
||||
|
||||
if (!usernameVal || !passwordVal || !captchaVal) {
|
||||
alert('请填写完整信息');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
username: usernameVal,
|
||||
password: passwordVal,
|
||||
captcha: captchaVal,
|
||||
captchaId: loginCaptchaId
|
||||
})
|
||||
});
|
||||
const d = await res.json();
|
||||
if (d.code === 0) {
|
||||
token = d.data.token;
|
||||
userId = d.data.userId;
|
||||
username = d.data.username;
|
||||
nickname = d.data.nickname;
|
||||
localStorage.setItem('token', token);
|
||||
localStorage.setItem('userId', userId);
|
||||
localStorage.setItem('username', username);
|
||||
localStorage.setItem('nickname', nickname);
|
||||
showLobby();
|
||||
} else {
|
||||
alert(d.message);
|
||||
getCaptcha('login');
|
||||
}
|
||||
} catch (e) {
|
||||
alert('登录失败: ' + e.message);
|
||||
getCaptcha('login');
|
||||
}
|
||||
}
|
||||
|
||||
async function register() {
|
||||
const usernameVal = $('regUsername').value.trim();
|
||||
const passwordVal = $('regPassword').value;
|
||||
const nicknameVal = $('regNickname').value.trim();
|
||||
const captchaVal = $('regCaptcha').value.trim().toUpperCase();
|
||||
|
||||
if (!usernameVal || !passwordVal || !nicknameVal || !captchaVal) {
|
||||
alert('请填写完整信息');
|
||||
return;
|
||||
}
|
||||
|
||||
if (usernameVal.length < 3 || usernameVal.length > 20) {
|
||||
alert('用户名需要3-20个字符');
|
||||
return;
|
||||
}
|
||||
|
||||
if (passwordVal.length < 6) {
|
||||
alert('密码至少6位');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/auth/register', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
username: usernameVal,
|
||||
password: passwordVal,
|
||||
nickname: nicknameVal,
|
||||
captcha: captchaVal,
|
||||
captchaId: regCaptchaId
|
||||
})
|
||||
});
|
||||
const d = await res.json();
|
||||
if (d.code === 0) {
|
||||
token = d.data.token;
|
||||
userId = d.data.userId;
|
||||
username = d.data.username;
|
||||
nickname = d.data.nickname;
|
||||
localStorage.setItem('token', token);
|
||||
localStorage.setItem('userId', userId);
|
||||
localStorage.setItem('username', username);
|
||||
localStorage.setItem('nickname', nickname);
|
||||
showLobby();
|
||||
} else {
|
||||
alert(d.message);
|
||||
getCaptcha('register');
|
||||
}
|
||||
} catch (e) {
|
||||
alert('注册失败: ' + e.message);
|
||||
getCaptcha('register');
|
||||
}
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
try {
|
||||
await fetch('/api/auth/logout', {
|
||||
method: 'POST',
|
||||
headers: authHeaders()
|
||||
});
|
||||
} catch (e) {}
|
||||
token = '';
|
||||
userId = '';
|
||||
username = '';
|
||||
nickname = '';
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('userId');
|
||||
localStorage.removeItem('username');
|
||||
localStorage.removeItem('nickname');
|
||||
show('auth');
|
||||
getCaptcha('login');
|
||||
}
|
||||
|
||||
async function validateToken() {
|
||||
if (!token) return false;
|
||||
try {
|
||||
const res = await fetch('/api/auth/validate', {
|
||||
headers: authHeaders()
|
||||
});
|
||||
const d = await res.json();
|
||||
if (d.code === 0) {
|
||||
userId = d.data.userId;
|
||||
username = d.data.username;
|
||||
nickname = d.data.nickname;
|
||||
return true;
|
||||
}
|
||||
} catch (e) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function checkCurrentRoom() {
|
||||
try {
|
||||
const res = await fetch('/api/rooms/current', {
|
||||
headers: authHeaders()
|
||||
});
|
||||
const d = await res.json();
|
||||
if (d.code === 0 && d.data && d.data.roomId) {
|
||||
roomId = d.data.roomId;
|
||||
playerId = d.data.playerId;
|
||||
return true;
|
||||
}
|
||||
} catch (e) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function showLobby() {
|
||||
$('welcomeUser').textContent = '欢迎, ' + nickname;
|
||||
$('playerName').value = nickname;
|
||||
show('lobby');
|
||||
}
|
||||
|
||||
async function create() {
|
||||
const name = $('playerName').value.trim();
|
||||
if (!name) { alert('请输入昵称'); return; }
|
||||
try {
|
||||
const res = await fetch('/api/rooms', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: authHeaders(),
|
||||
body: JSON.stringify({playerName: name, maxPlayers: +$('maxPlayers').value})
|
||||
});
|
||||
const d = await res.json();
|
||||
@@ -43,7 +223,7 @@ async function join() {
|
||||
try {
|
||||
const res = await fetch('/api/rooms/' + rid + '/join', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: authHeaders(),
|
||||
body: JSON.stringify({playerName: name})
|
||||
});
|
||||
const d = await res.json();
|
||||
@@ -59,6 +239,21 @@ async function join() {
|
||||
}
|
||||
}
|
||||
|
||||
async function leaveRoom() {
|
||||
try {
|
||||
await fetch('/api/rooms/leave', {
|
||||
method: 'POST',
|
||||
headers: authHeaders()
|
||||
});
|
||||
} catch (e) {}
|
||||
if (ws) ws.close();
|
||||
show('lobby');
|
||||
roomId = '';
|
||||
playerId = '';
|
||||
state = null;
|
||||
selected = [];
|
||||
}
|
||||
|
||||
function connect() {
|
||||
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
ws = new WebSocket(proto + '//' + location.host + '/api/ws?roomId=' + roomId + '&playerId=' + playerId);
|
||||
@@ -68,6 +263,7 @@ function connect() {
|
||||
if (msg.type === 'state') render(msg.data);
|
||||
else if (msg.type === 'gameOver') showGameOver(msg.data);
|
||||
else if (msg.type === 'chat') chat(msg.data.playerName, msg.data.message);
|
||||
else if (msg.type === 'leave') chat('', '有玩家离开房间', true);
|
||||
else if (msg.type === 'error') chat('', msg.data, true);
|
||||
};
|
||||
ws.onerror = function() { chat('', '连接错误', true); };
|
||||
@@ -308,9 +504,7 @@ function toggleReady() {
|
||||
}
|
||||
|
||||
function leave() {
|
||||
if (ws) ws.close();
|
||||
show('lobby');
|
||||
roomId = ''; playerId = ''; state = null; selected = [];
|
||||
leaveRoom();
|
||||
}
|
||||
|
||||
function showGameOver(d) {
|
||||
@@ -329,11 +523,31 @@ function again() {
|
||||
send('ready', {ready: false});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
$('loginTab').onclick = function() {
|
||||
$('loginTab').classList.add('active');
|
||||
$('registerTab').classList.remove('active');
|
||||
$('loginForm').classList.remove('hidden');
|
||||
$('registerForm').classList.add('hidden');
|
||||
getCaptcha('login');
|
||||
};
|
||||
$('registerTab').onclick = function() {
|
||||
$('registerTab').classList.add('active');
|
||||
$('loginTab').classList.remove('active');
|
||||
$('registerForm').classList.remove('hidden');
|
||||
$('loginForm').classList.add('hidden');
|
||||
getCaptcha('register');
|
||||
};
|
||||
$('loginCaptchaImg').onclick = function() { getCaptcha('login'); };
|
||||
$('regCaptchaImg').onclick = function() { getCaptcha('register'); };
|
||||
$('loginBtn').onclick = login;
|
||||
$('registerBtn').onclick = register;
|
||||
$('logoutBtn').onclick = logout;
|
||||
|
||||
$('createBtn').onclick = create;
|
||||
$('joinBtn').onclick = join;
|
||||
$('readyBtn').onclick = toggleReady;
|
||||
$('leaveBtn').onclick = leave;
|
||||
$('leaveBtn').onclick = leaveRoom;
|
||||
$('playBtn').onclick = play;
|
||||
$('passBtn').onclick = pass;
|
||||
$('againBtn').onclick = again;
|
||||
@@ -343,4 +557,29 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
};
|
||||
$('chatInput').onkeypress = function(e) { if (e.key === 'Enter') $('chatBtn').click(); };
|
||||
$('roomIdInput').onkeypress = function(e) { if (e.key === 'Enter') join(); };
|
||||
|
||||
token = localStorage.getItem('token') || '';
|
||||
userId = localStorage.getItem('userId') || '';
|
||||
username = localStorage.getItem('username') || '';
|
||||
nickname = localStorage.getItem('nickname') || '';
|
||||
|
||||
if (token) {
|
||||
var valid = await validateToken();
|
||||
if (valid) {
|
||||
var inRoom = await checkCurrentRoom();
|
||||
if (inRoom) {
|
||||
connect();
|
||||
return;
|
||||
}
|
||||
showLobby();
|
||||
return;
|
||||
}
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('userId');
|
||||
localStorage.removeItem('username');
|
||||
localStorage.removeItem('nickname');
|
||||
}
|
||||
|
||||
show('auth');
|
||||
getCaptcha('login');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user