/* ============================================================ 宇森官网 · 公共脚本(所有子页面共享) common.js — 含:导航高亮 / 登录态 / SVG 缩略图生成器 依赖:assets/game-api.js(需在本文件之前加载) ============================================================ */ // ---------- 导航栏:根据当前 URL 自动高亮对应链接 ---------- (function(){ const links = document.querySelectorAll('.nav a'); const page = location.pathname.split('/').pop().replace(/\.html$/,'') || 'index'; links.forEach(a => { const href = a.getAttribute('href') || ''; const target = href.replace(/\.html$/,'').replace(/^\.\//,''); if (target === page || (page === '' && target === 'index')) { a.classList.add('active'); } }); })(); // ---------- 登录态 / 右上角用户信息(从 Odoo 取) ---------- (function(){ const userBox = document.getElementById('userBox'); if (!userBox) return; // sessionStorage key:'yusen:me' = JSON({uid,name,login}) 或 '' 表示已确认未登录 function saveMe(me){ try{ sessionStorage.setItem('yusen:me', me ? JSON.stringify(me) : ''); }catch(e){} } function loadMe(){ try{ const v=sessionStorage.getItem('yusen:me'); return v===null?undefined:(v?JSON.parse(v):null); }catch(e){return undefined;} } function renderLoggedOut(){ userBox.innerHTML = '登录注册'; document.querySelectorAll('.nav .auth-only').forEach(el => el.classList.remove('visible')); } function renderLoggedIn(me){ userBox.innerHTML = ''; const nm = userBox.querySelector('.ub-name'); if (nm) nm.textContent = me.name || me.login; document.querySelectorAll('.nav .auth-only').forEach(el => el.classList.add('visible')); const lb = document.getElementById('ubLogout'); if (lb) lb.addEventListener('click', async ()=>{ try { await API.logout(); } catch(e){} saveMe(null); sessionStorage.removeItem('yusen:me'); location.href = 'index.html'; }); } // 1) 同步首屏:从 sessionStorage 立即渲染正确状态(消除 topbar 闪一下) const cached = loadMe(); if (cached === undefined) { // 第一次访问:渲染一个不闪烁的占位(保持默认空,等异步结果) userBox.innerHTML = ''; } else if (cached && cached.uid) { renderLoggedIn(cached); } else { renderLoggedOut(); } // 2) 异步校验:拿真实登录态,纠正缓存 async function refreshUserBox(){ try{ const me = await API.me(); if (me && me.uid) { saveMe(me); renderLoggedIn(me); } else { saveMe(null); renderLoggedOut(); } }catch(e){ if (cached === undefined) renderLoggedOut(); // 首次访问 + 接口挂了才退回未登录 } } if (typeof API !== 'undefined') refreshUserBox(); else document.addEventListener('DOMContentLoaded', ()=>{ if (typeof API !== 'undefined') refreshUserBox(); }); })(); // ---------- 程序化矢量缩略图(图鉴/首页共用) ---------- function hashStr(s){let h=2166136261;for(let i=0;i>>0;} function rng(seed){let s=seed>>>0;return function(){s=(Math.imul(s,1664525)+1013904223)>>>0;return s/4294967296;};} const TIERCOL={'普通':'#9aa6c4','精良':'#5fd38a','稀有':'#4cc9f0','史诗':'#c77dff','传说':'#e7b85c'}; function starPts(cx,cy,spikes,outer,inner){ let pts=[],rot=-Math.PI/2; for(let i=0;i`; if(v===0){s+=``;} else if(v===1){s+=``;} else{s+=``;} s+=``; return s; } function shBuild(r,seed){ let s=``; s+=``; for(let i=0;i<3;i++)s+=``; return s; } function shElement(r,seed){ const sides=3+Math.floor(r()*6); let s=``; s+=``; return s; } function shPersona(r,seed){ let s=``; s+=``; s+=``; return s; } function shTalent(r,seed){ const sp=4+Math.floor(r()*4); let s=``; s+=``; return s; } function shRelic(r,seed){ let s=``; s+=``; return s; } function shEquip(sub,seed){ switch(sub){ case 'head': return ``; case 'hand': {let s=``;for(let i=0;i<3;i++)s+=``;return s;} case 'chest': return ``; case 'pants': return ``; case 'shoes': return ``; case 'ring': return ``; case 'neck': return ``; case 'treasure': return ``; default: return ``; } } function shEvent(r,seed){ let s=``; s+=``; return s; } function shapeFor(cat,sub,r,seed){ switch(cat){ case 'race': return shRace(r,seed); case 'build': return shBuild(r,seed); case 'element': return shElement(r,seed); case 'persona': return shPersona(r,seed); case 'talent': return shTalent(r,seed); case 'relic': return shRelic(r,seed); case 'equip': return shEquip(sub,seed); case 'event': return shEvent(r,seed); default: return ``; } } function thumbSVG(it){ const seed=hashStr(it.cat+it.sub+it.name); const r=rng(seed); const h=Math.floor(r()*360); const h2=(h+40)%360; const tcol=TIERCOL[it.tier]||'#9aa6c4'; const shape=shapeFor(it.cat,it.sub,r,seed); return ``+ ``+ ``+ ``+ ``+ ``+ ``+ ``+ ``+ ``+ ``+ ``+ shape+ ``+ ``; }