feat: Odoo login integration for all pages
This commit is contained in:
parent
424923c81e
commit
d01703dd3f
146
website/auth.css
Normal file
146
website/auth.css
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/* 宇森 - 登录认证样式 */
|
||||||
|
|
||||||
|
/* ---- Nav bar auth area ---- */
|
||||||
|
#auth-area {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-btn {
|
||||||
|
background: rgba(100, 200, 255, 0.15);
|
||||||
|
border: 1px solid rgba(100, 200, 255, 0.35);
|
||||||
|
color: #c8e6ff;
|
||||||
|
padding: 6px 16px;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: all 0.25s;
|
||||||
|
}
|
||||||
|
.auth-btn:hover {
|
||||||
|
background: rgba(100, 200, 255, 0.25);
|
||||||
|
border-color: rgba(100, 200, 255, 0.6);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {}
|
||||||
|
.logout-btn {
|
||||||
|
background: rgba(255, 100, 100, 0.12);
|
||||||
|
border-color: rgba(255, 100, 100, 0.3);
|
||||||
|
color: #fcc;
|
||||||
|
}
|
||||||
|
.logout-btn:hover {
|
||||||
|
background: rgba(255, 100, 100, 0.22);
|
||||||
|
border-color: rgba(255, 100, 100, 0.5);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
color: #a8e6cf;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Login Modal ---- */
|
||||||
|
#login-modal {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(5, 8, 16, 0.8);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
background: linear-gradient(135deg, rgba(15, 23, 42, 0.95), rgba(10, 18, 35, 0.98));
|
||||||
|
border: 1px solid rgba(100, 200, 255, 0.2);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 36px 32px;
|
||||||
|
width: 360px;
|
||||||
|
max-width: 90vw;
|
||||||
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 80px rgba(100, 200, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box h2 {
|
||||||
|
margin: 0 0 4px;
|
||||||
|
font-size: 22px;
|
||||||
|
background: linear-gradient(90deg, #4af, #a8e6cf);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-sub {
|
||||||
|
margin: 0 0 24px;
|
||||||
|
color: #6a8;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-box input {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
border: 1px solid rgba(100, 200, 255, 0.2);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #e0e8f0;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
transition: border 0.2s;
|
||||||
|
}
|
||||||
|
.login-box input:focus {
|
||||||
|
border-color: rgba(100, 200, 255, 0.5);
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-error {
|
||||||
|
color: #f66;
|
||||||
|
font-size: 12px;
|
||||||
|
min-height: 18px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-submit {
|
||||||
|
width: 100%;
|
||||||
|
padding: 11px;
|
||||||
|
margin-top: 4px;
|
||||||
|
background: linear-gradient(135deg, #2a6, #4af);
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.25s;
|
||||||
|
}
|
||||||
|
.login-submit:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 20px rgba(68, 170, 255, 0.3);
|
||||||
|
}
|
||||||
|
.login-submit:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-footer {
|
||||||
|
margin: 16px 0 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #557;
|
||||||
|
}
|
||||||
|
.login-footer a {
|
||||||
|
color: #4af;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.login-footer a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
188
website/auth.js
Normal file
188
website/auth.js
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* 宇森 - 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,
|
||||||
|
};
|
||||||
|
})();
|
||||||
@ -28,7 +28,7 @@ body { background: #0a0e17; overflow: hidden; font-family: 'Microsoft YaHei', sa
|
|||||||
#topBar .nav-links { display:flex; gap:16px; margin-left:24px; }
|
#topBar .nav-links { display:flex; gap:16px; margin-left:24px; }
|
||||||
#topBar .nav-links a { color:#667788; text-decoration:none; font-size:12px; transition:color 0.2s; }
|
#topBar .nav-links a { color:#667788; text-decoration:none; font-size:12px; transition:color 0.2s; }
|
||||||
#topBar .nav-links a:hover { color:#4af; }
|
#topBar .nav-links a:hover { color:#4af; }
|
||||||
#topBar .coords { margin-left:auto; font-size:12px; color:#8899aa; }
|
#topBar .coords { margin-left:8px; font-size:12px; color:#8899aa; }
|
||||||
|
|
||||||
/* 微观世界视图 */
|
/* 微观世界视图 */
|
||||||
#microView {
|
#microView {
|
||||||
@ -164,6 +164,7 @@ body { background: #0a0e17; overflow: hidden; font-family: 'Microsoft YaHei', sa
|
|||||||
cursor: pointer; font-size: 13px;
|
cursor: pointer; font-size: 13px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="auth.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@ -185,6 +186,7 @@ body { background: #0a0e17; overflow: hidden; font-family: 'Microsoft YaHei', sa
|
|||||||
<a href="world.html">世界</a>
|
<a href="world.html">世界</a>
|
||||||
<a href="races.html">种族</a>
|
<a href="races.html">种族</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="auth-area" style="margin-left:auto; margin-right:8px;"></div>
|
||||||
<span class="coords" id="coords">坐标: (0, 0)</span>
|
<span class="coords" id="coords">坐标: (0, 0)</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1078,5 +1080,7 @@ window.addEventListener('resize', () => {
|
|||||||
generateMap();
|
generateMap();
|
||||||
init();
|
init();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="auth.js"></script>
|
||||||
|
<script>YuSenAuth.init();</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -83,6 +83,7 @@ nav .links a:hover { color:#4af; }
|
|||||||
.quick-card { padding:14px 18px; min-width:110px; }
|
.quick-card { padding:14px 18px; min-width:110px; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="auth.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ nav .links a:hover { color:#4af; }
|
|||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<span class="logo">宇森</span>
|
<span class="logo">宇森</span>
|
||||||
|
<div id="auth-area"></div>
|
||||||
<ul class="links">
|
<ul class="links">
|
||||||
<li><a href="intro.html">游戏介绍</a></li>
|
<li><a href="intro.html">游戏介绍</a></li>
|
||||||
<li><a href="platform.html">平台架构</a></li>
|
<li><a href="platform.html">平台架构</a></li>
|
||||||
@ -177,5 +179,7 @@ function animate() {
|
|||||||
}
|
}
|
||||||
animate();
|
animate();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="auth.js"></script>
|
||||||
|
<script>YuSenAuth.init();</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -62,6 +62,7 @@ p { color:#99aabb; font-size:15px; margin-bottom:16px; line-height:1.9; }
|
|||||||
.page { padding:80px 20px 40px; }
|
.page { padding:80px 20px 40px; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="auth.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@ -69,6 +70,7 @@ p { color:#99aabb; font-size:15px; margin-bottom:16px; line-height:1.9; }
|
|||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a href="index.html" class="logo">宇森</a>
|
<a href="index.html" class="logo">宇森</a>
|
||||||
|
<div id="auth-area"></div>
|
||||||
<ul class="links">
|
<ul class="links">
|
||||||
<li><a href="intro.html" class="active">游戏介绍</a></li>
|
<li><a href="intro.html" class="active">游戏介绍</a></li>
|
||||||
<li><a href="platform.html">平台架构</a></li>
|
<li><a href="platform.html">平台架构</a></li>
|
||||||
@ -146,5 +148,7 @@ for (let i=0;i<80;i++) particles.push(new Particle());
|
|||||||
function animate() { ctx.clearRect(0,0,canvas.width,canvas.height); particles.forEach(p=>{p.update();p.draw();}); requestAnimationFrame(animate); }
|
function animate() { ctx.clearRect(0,0,canvas.width,canvas.height); particles.forEach(p=>{p.update();p.draw();}); requestAnimationFrame(animate); }
|
||||||
animate();
|
animate();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="auth.js"></script>
|
||||||
|
<script>YuSenAuth.init();</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -56,6 +56,7 @@ h1 { font-size:32px; font-weight:bold; margin-bottom:8px; background:linear-grad
|
|||||||
h1 { font-size:24px; } nav .links { display:none; } .page { padding:80px 20px 40px; }
|
h1 { font-size:24px; } nav .links { display:none; } .page { padding:80px 20px 40px; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="auth.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ h1 { font-size:32px; font-weight:bold; margin-bottom:8px; background:linear-grad
|
|||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a href="index.html" class="logo">宇森</a>
|
<a href="index.html" class="logo">宇森</a>
|
||||||
|
<div id="auth-area"></div>
|
||||||
<ul class="links">
|
<ul class="links">
|
||||||
<li><a href="intro.html">游戏介绍</a></li>
|
<li><a href="intro.html">游戏介绍</a></li>
|
||||||
<li><a href="platform.html" class="active">平台架构</a></li>
|
<li><a href="platform.html" class="active">平台架构</a></li>
|
||||||
@ -114,5 +116,7 @@ class Particle{constructor(){this.r();this.y=Math.random()*c.height}r(){this.x=M
|
|||||||
for(let i=0;i<80;i++)P.push(new Particle());
|
for(let i=0;i<80;i++)P.push(new Particle());
|
||||||
(function A(){x.clearRect(0,0,c.width,c.height);P.forEach(p=>{p.u();p.d()});requestAnimationFrame(A)})();
|
(function A(){x.clearRect(0,0,c.width,c.height);P.forEach(p=>{p.u();p.d()});requestAnimationFrame(A)})();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="auth.js"></script>
|
||||||
|
<script>YuSenAuth.init();</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -49,6 +49,7 @@ h1 { font-size:32px; font-weight:bold; margin-bottom:8px; background:linear-grad
|
|||||||
.races { grid-template-columns:1fr; } .race-card { padding:22px 18px; }
|
.races { grid-template-columns:1fr; } .race-card { padding:22px 18px; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="auth.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ h1 { font-size:32px; font-weight:bold; margin-bottom:8px; background:linear-grad
|
|||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a href="index.html" class="logo">宇森</a>
|
<a href="index.html" class="logo">宇森</a>
|
||||||
|
<div id="auth-area"></div>
|
||||||
<ul class="links">
|
<ul class="links">
|
||||||
<li><a href="intro.html">游戏介绍</a></li>
|
<li><a href="intro.html">游戏介绍</a></li>
|
||||||
<li><a href="platform.html">平台架构</a></li>
|
<li><a href="platform.html">平台架构</a></li>
|
||||||
@ -126,5 +128,7 @@ class Particle{constructor(){this.r();this.y=Math.random()*c.height}r(){this.x=M
|
|||||||
for(let i=0;i<80;i++)P.push(new Particle());
|
for(let i=0;i<80;i++)P.push(new Particle());
|
||||||
(function A(){x.clearRect(0,0,c.width,c.height);P.forEach(p=>{p.u();p.d()});requestAnimationFrame(A)})();
|
(function A(){x.clearRect(0,0,c.width,c.height);P.forEach(p=>{p.u();p.d()});requestAnimationFrame(A)})();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="auth.js"></script>
|
||||||
|
<script>YuSenAuth.init();</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -51,6 +51,7 @@ h1 { font-size:32px; font-weight:bold; margin-bottom:8px; background:linear-grad
|
|||||||
.layer-icon { padding-top:0; }
|
.layer-icon { padding-top:0; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="auth.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ h1 { font-size:32px; font-weight:bold; margin-bottom:8px; background:linear-grad
|
|||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a href="index.html" class="logo">宇森</a>
|
<a href="index.html" class="logo">宇森</a>
|
||||||
|
<div id="auth-area"></div>
|
||||||
<ul class="links">
|
<ul class="links">
|
||||||
<li><a href="intro.html">游戏介绍</a></li>
|
<li><a href="intro.html">游戏介绍</a></li>
|
||||||
<li><a href="platform.html">平台架构</a></li>
|
<li><a href="platform.html">平台架构</a></li>
|
||||||
@ -134,5 +136,7 @@ class Particle{constructor(){this.r();this.y=Math.random()*c.height}r(){this.x=M
|
|||||||
for(let i=0;i<80;i++)P.push(new Particle());
|
for(let i=0;i<80;i++)P.push(new Particle());
|
||||||
(function A(){x.clearRect(0,0,c.width,c.height);P.forEach(p=>{p.u();p.d()});requestAnimationFrame(A)})();
|
(function A(){x.clearRect(0,0,c.width,c.height);P.forEach(p=>{p.u();p.d()});requestAnimationFrame(A)})();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="auth.js"></script>
|
||||||
|
<script>YuSenAuth.init();</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user