const BASE = '/api'; let token = localStorage.getItem('wk5_token') || ''; let role = localStorage.getItem('wk5_role') || ''; document.addEventListener('DOMContentLoaded', () => { if (token) { showMain(); loadStudents(); checkRoleUI(); } }); // ==================== 认证 ==================== async function doLogin() { const username = document.getElementById('login-username').value.trim(); const password = document.getElementById('login-password').value.trim(); if (!username || !password) { showLoginError('请输入用户名和密码'); return; } try { const resp = await fetch(BASE + '/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const result = await resp.json(); if (resp.ok && result.code === 200) { token = result.data.token; role = result.data.role; localStorage.setItem('wk5_token', token); localStorage.setItem('wk5_role', role); showMain(); loadStudents(); checkRoleUI(); } else { showLoginError(result.message || '登录失败'); } } catch (e) { showLoginError('连接失败: ' + e.message); } } async function doRegister() { const username = document.getElementById('reg-username').value.trim(); const password = document.getElementById('reg-password').value.trim(); if (!username || !password) { document.getElementById('reg-error').textContent = '请输入用户名和密码'; return; } try { const resp = await fetch(BASE + '/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const result = await resp.json(); if (resp.ok && result.code === 200) { token = result.data.token; role = result.data.role; localStorage.setItem('wk5_token', token); localStorage.setItem('wk5_role', role); showMain(); loadStudents(); checkRoleUI(); } else { document.getElementById('reg-error').textContent = result.message || '注册失败'; } } catch (e) { document.getElementById('reg-error').textContent = '连接失败'; } } function showLoginError(msg) { document.getElementById('login-error').textContent = msg; } function showLogin() { document.getElementById('login-panel').style.display = 'block'; document.getElementById('register-panel').style.display = 'none'; document.getElementById('main-panel').style.display = 'none'; } function showRegister() { document.getElementById('login-panel').style.display = 'none'; document.getElementById('register-panel').style.display = 'block'; } function showMain() { document.getElementById('login-panel').style.display = 'none'; document.getElementById('register-panel').style.display = 'none'; document.getElementById('main-panel').style.display = 'block'; } function logout() { localStorage.removeItem('wk5_token'); localStorage.removeItem('wk5_role'); token = ''; role = ''; showLogin(); } /** 根据角色显示/隐藏操作按钮 */ function checkRoleUI() { document.getElementById('user-info').textContent = '当前: ' + (role || '-') + ' | '; document.getElementById('btn-add').style.display = (role === 'ADMIN') ? '' : 'none'; } // ==================== 请求封装 ==================== async function api(url, options) { options = options || {}; options.headers = options.headers || {}; options.headers['Authorization'] = 'Bearer ' + token; const resp = await fetch(url, options); const result = await resp.json(); if (resp.status === 403) { showError('权限不足:需要 ADMIN 角色'); return null; } if ((resp.status === 401 || resp.status === 403) && result.code !== 200) { logout(); showError('认证失败,请重新登录'); return null; } if (result.extra && result.extra.orm) { document.getElementById('stat-orm').textContent = result.extra.orm; } return result; } function showError(msg) { const bar = document.getElementById('error-bar'); bar.textContent = '⚠ ' + msg; bar.style.display = 'block'; setTimeout(() => bar.style.display = 'none', 4000); } // ==================== 数据 ==================== async function loadStudents(keyword) { const tbody = document.getElementById('table-body'); tbody.innerHTML = '