/** * 宇森 - Odoo 用户认证模块 * 通过 Odoo JSON-RPC 实现登录/登出,与 Odoo 用户系统打通 */ (function () { 'use strict'; const AUTH_URL = '/web/session/authenticate'; const DESTROY_URL = '/web/session/destroy'; const SESSION_URL = '/web/session/get_session_info'; // ============ State ============ let currentUser = null; // ============ Init ============ async function init() { try { const resp = await fetch(SESSION_URL, { credentials: 'same-origin' }); if (resp.ok) { const data = await resp.json(); if (data.result && data.result.uid) { currentUser = { uid: data.result.uid, username: data.result.username, name: data.result.name || data.result.username, }; } } } catch (e) { // Not logged in — that's fine } renderAuthUI(); } // ============ Login ============ async function login(username, password) { const body = { jsonrpc: '2.0', method: 'call', params: { db: 'game', login: username, password: password, }, id: Date.now(), }; const resp = await fetch(AUTH_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), credentials: 'same-origin', }); const data = await resp.json(); if (data.error) { throw new Error(data.error.data?.message || '登录失败,请检查用户名和密码'); } if (data.result && data.result.uid) { currentUser = { uid: data.result.uid, username: data.result.username, name: data.result.name || data.result.username, }; renderAuthUI(); return currentUser; } throw new Error('登录失败'); } // ============ Logout ============ async function logout() { try { await fetch(DESTROY_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', method: 'call', params: {}, id: Date.now() }), credentials: 'same-origin', }); } catch (e) { // ignore } currentUser = null; renderAuthUI(); } // ============ Render ============ function renderAuthUI() { const container = document.getElementById('auth-area'); if (!container) return; if (currentUser) { container.innerHTML = '' + escapeHtml(currentUser.name) + '' + ''; } else { container.innerHTML = ''; } } // ============ Login Modal ============ function showLoginModal() { // Remove existing modal const existing = document.getElementById('login-modal'); if (existing) existing.remove(); const modal = document.createElement('div'); modal.id = 'login-modal'; modal.innerHTML = '
' + '
' + '

登录宇森

' + '' + '
' + '' + '' + '' + '' + '
' + '' + '
' + '
'; document.body.appendChild(modal); const form = modal.querySelector('#login-form'); form.onsubmit = handleLogin; // Focus username setTimeout(() => { const u = document.getElementById('login-username'); if (u) u.focus(); }, 100); } function hideLoginModal(e) { if (e && e.target !== e.currentTarget) return; const modal = document.getElementById('login-modal'); if (modal) modal.remove(); } async function handleLogin() { const username = document.getElementById('login-username').value.trim(); const password = document.getElementById('login-password').value; const errEl = document.getElementById('login-error'); const btn = document.getElementById('login-submit-btn'); if (!username || !password) { errEl.textContent = '请输入用户名和密码'; return; } btn.disabled = true; btn.textContent = '登录中...'; errEl.textContent = ''; try { await login(username, password); hideLoginModal({ target: document.querySelector('.login-overlay') }); } catch (e) { errEl.textContent = e.message; } finally { btn.disabled = false; btn.textContent = '登 录'; } } function escapeHtml(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; } // ============ Public API ============ window.YuSenAuth = { init, login, logout, showLoginModal, hideLoginModal, getCurrentUser: () => currentUser, isLoggedIn: () => !!currentUser, }; })();