game/website/auth.js

189 lines
5.4 KiB
JavaScript

/**
* 宇森 - 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 =
'<span class="user-name">' +
escapeHtml(currentUser.name) +
'</span>' +
'<button class="auth-btn logout-btn" onclick="YuSenAuth.logout()">退出</button>';
} else {
container.innerHTML =
'<button class="auth-btn login-btn" onclick="YuSenAuth.showLoginModal()">登录</button>';
}
}
// ============ 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 =
'<div class="login-overlay" onclick="YuSenAuth.hideLoginModal(event)">' +
'<div class="login-box" onclick="event.stopPropagation()">' +
'<h2>登录宇森</h2>' +
'<p class="login-sub">使用 Odoo 账号登录</p>' +
'<form id="login-form" onsubmit="return false">' +
'<input type="text" id="login-username" placeholder="用户名" autocomplete="username" />' +
'<input type="password" id="login-password" placeholder="密码" autocomplete="current-password" />' +
'<div id="login-error" class="login-error"></div>' +
'<button type="submit" class="login-submit" id="login-submit-btn">登 录</button>' +
'</form>' +
'<p class="login-footer">还没有账号?前往 <a href="/admin/web/login" target="_blank">Odoo 注册</a></p>' +
'</div>' +
'</div>';
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,
};
})();