189 lines
5.4 KiB
JavaScript
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="https://game.pengyuthon.cn/web/login?db=game" 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,
|
|
};
|
|
})();
|