Files

130 lines
4.1 KiB
JavaScript

(function () {
const body = document.body;
const statusEl = document.getElementById('status');
const leaderboardList = document.getElementById('leaderboard-list');
const searchForm = document.getElementById('search-form');
const searchInput = document.getElementById('search-input');
const searchResults = document.getElementById('search-results');
const setStatus = (text) => {
statusEl.textContent = text || '';
};
const getJson = async (url) => {
const res = await fetch(url);
return res.json();
};
const renderLeaderboard = (rows) => {
if (!leaderboardList) return;
if (!rows.length) {
leaderboardList.textContent = '暂无排行数据';
return;
}
const table = document.createElement('table');
table.className = 'admin-table';
const thead = document.createElement('thead');
const headRow = document.createElement('tr');
['排名', '用户名', '胜场', '参与局', '胜率', '总回合'].forEach((text) => {
const th = document.createElement('th');
th.textContent = text;
headRow.appendChild(th);
});
thead.appendChild(headRow);
table.appendChild(thead);
const tbody = document.createElement('tbody');
rows.forEach((row) => {
const tr = document.createElement('tr');
const tdRank = document.createElement('td');
tdRank.textContent = `#${row.rank || '-'}`;
tr.appendChild(tdRank);
const tdUser = document.createElement('td');
const link = document.createElement('a');
link.href = `/users/${encodeURIComponent(row.username || '')}`;
link.textContent = row.username || '匿名';
tdUser.appendChild(link);
tr.appendChild(tdUser);
const tdWins = document.createElement('td');
tdWins.textContent = String(row.wins || 0);
tr.appendChild(tdWins);
const tdGames = document.createElement('td');
tdGames.textContent = String(row.played_games || 0);
tr.appendChild(tdGames);
const tdRate = document.createElement('td');
tdRate.textContent = `${Number(row.win_rate || 0).toFixed(1)}%`;
tr.appendChild(tdRate);
const tdRounds = document.createElement('td');
tdRounds.textContent = String(row.total_rounds || 0);
tr.appendChild(tdRounds);
tbody.appendChild(tr);
});
table.appendChild(tbody);
leaderboardList.textContent = '';
leaderboardList.appendChild(table);
};
const renderSearch = (rows) => {
searchResults.textContent = '';
if (!rows.length) {
const li = document.createElement('li');
li.textContent = '没有匹配用户';
searchResults.appendChild(li);
return;
}
rows.forEach((row) => {
const li = document.createElement('li');
const online = row.presence?.is_online ? '在线' : '离线';
const rank = row.stats?.rank ? `#${row.stats.rank}` : '-';
const link = document.createElement('a');
link.href = `/users/${encodeURIComponent(row.username || '')}`;
link.textContent = row.username || '匿名';
li.appendChild(link);
const text = document.createElement('span');
text.textContent = ` · ${online} · 排名 ${rank} · 胜场 ${row.stats?.wins || 0}`;
li.appendChild(text);
searchResults.appendChild(li);
});
};
const loadLeaderboard = async () => {
const data = await getJson('/api/leaderboard?limit=100');
if (!data.ok) {
setStatus(data.error || '加载排行榜失败');
return;
}
renderLeaderboard(data.leaderboard || []);
};
const searchUsers = async (q) => {
const data = await getJson(`/api/users/search?q=${encodeURIComponent(q || '')}&limit=20`);
if (!data.ok) {
setStatus(data.error || '搜索失败');
return;
}
renderSearch(data.users || []);
};
if (searchForm) {
searchForm.addEventListener('submit', async (event) => {
event.preventDefault();
try {
await searchUsers(searchInput?.value || '');
} catch (error) {
setStatus(`网络错误: ${error}`);
}
});
}
loadLeaderboard()
.then(() => searchUsers(''))
.catch((error) => setStatus(`网络错误: ${error}`));
})();