/* career.js — 个人生涯,完全对照参考图 */
let _cPuuid=null,_cGames=[],_cParsed=[],_cSummoner=null;
const QMAP={420:'单排',440:'灵活组排',430:'普通对战',450:'极地大乱斗',
900:'无限火力',1700:'斗魂竞技场',1090:'云顶之弈',1100:'云顶排位',
3140:'多人 训练模式 自定义',0:'自定义'};
const qname=id=>QMAP[id]||`模式${id}`;
const tierZh=t=>({'IRON':'黑铁','BRONZE':'黄铜','SILVER':'白银','GOLD':'黄金',
'PLATINUM':'铂金','EMERALD':'翡翠','DIAMOND':'钻石','MASTER':'大师',
'GRANDMASTER':'宗师','CHALLENGER':'王者'}[t?.toUpperCase()]||t||'--');
const ip=p=>p?`/api/img?path=${encodeURIComponent(p)}`:'';
async function renderCareer(){
const page=document.getElementById('page-career');
page.innerHTML='
加载生涯
';
try{
const s=await API.get('summoner');
_cSummoner=s;_cPuuid=s.puuid;
await _loadCareer(s.puuid,s);
}catch(e){page.innerHTML='';}
}
async function _loadCareer(puuid,summoner){
const page=document.getElementById('page-career');
page.innerHTML='加载生涯数据
';
try{
const[rr,gr]=await Promise.allSettled([
API.get('ranked'),
API.get('games',{puuid,beg:0,end:19})
]);
const ranked=rr.status==='fulfilled'?rr.value:null;
const raw=gr.status==='fulfilled'?gr.value:null;
console.log('[career] raw keys=', raw ? Object.keys(raw) : null);
console.log('[career] raw.games=', raw?.games ? Object.keys(raw.games) : null);
console.log('[career] gameCount=', raw?.games?.gameCount);
const list=raw?.games?.games||raw?.games||[];
_cGames=Array.isArray(list)?list:[];
_cParsed=_cGames.map(g=>_parseGame(g,puuid));
console.log('[career] _cGames.length=', _cGames.length, '_cParsed=', _cParsed.length);
if(_cParsed.length) console.log('[career] first game=', _cParsed[0]);
_buildPage(summoner,ranked,_cParsed);
}catch(e){page.innerHTML='';}
}
function _parseGame(game,puuid){
const ids=game.participantIdentities||[];
const ps=game.participants||[];
let pid=-1;
for(const id of ids){if(id.player?.puuid===puuid){pid=id.participantId;break;}}
if(pid===-1&&ids.length)pid=ids[0].participantId;
const p=ps.find(x=>x.participantId===pid)||ps[0]||{};
const st=p.stats||{};
const cid=p.championId||0;
const secs=game.gameDuration||0;
const dur=`${String(Math.floor(secs/60)).padStart(2,'0')}:${String(secs%60).padStart(2,'0')}`;
const ts=game.gameCreation||0;
let t='';
if(ts){const d=new Date(ts);t=`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')} · ${d.getFullYear()}/${String(d.getMonth()+1).padStart(2,'0')}/${String(d.getDate()).padStart(2,'0')}`;}
return{
queueId:game.queueId||0,win:st.win||false,remake:st.gameEndedInEarlySurrender||false,
kills:st.kills||0,deaths:st.deaths||0,assists:st.assists||0,
champLevel:st.champLevel||1,cs:(st.totalMinionsKilled||0)+(st.neutralMinionsKilled||0),
gold:st.goldEarned||0,champIcon:`/lol-game-data/assets/v1/champion-icons/${cid}.png`,
sp1:`/lol-game-data/assets/v1/summoner-spell-icons/${p.spell1Id||0}.png`,
sp2:`/lol-game-data/assets/v1/summoner-spell-icons/${p.spell2Id||0}.png`,
items:[st.item0,st.item1,st.item2,st.item3,st.item4,st.item5,st.item6]
.map(id=>id?`/lol-game-data/assets/v1/item-icons/${id}.png`:''),
time:t,dur,
};
}
function _stats(games){
let k=0,d=0,a=0,w=0,l=0;
for(const g of games){
if(g.remake||g.queueId===0)continue;
k+=g.kills;d+=g.deaths;a+=g.assists;
if(g.win)w++;else l++;
}
return{k,d,a,w,l,kda:d===0?(k+a).toFixed(1):((k+a)/d).toFixed(1)};
}
function _champIcons(games){
const map={};
for(const g of games){
if(!g.champIcon)continue;
if(!map[g.champIcon])map[g.champIcon]={icon:g.champIcon,t:0,w:0};
map[g.champIcon].t++;if(g.win)map[g.champIcon].w++;
}
return Object.values(map).sort((a,b)=>b.t-a.t).slice(0,10);
}
function _rankRow(r,label){
const t=r.tier||'',dv=r.division||'';
const w=r.wins||0,l=r.losses||0,tot=w+l;
const div=dv==='NA'?'':dv;
const tier=t?tierZh(t)+' '+div:'--';
const high=r.highestTier?tierZh(r.highestTier)+' '+(r.highestDivision==='NA'?'':r.highestDivision):'--';
const prev=r.previousSeasonEndTier?tierZh(r.previousSeasonEndTier)+' '+(r.previousSeasonEndDivision==='NA'?'':r.previousSeasonEndDivision):'--';
return`| ${label} | ${tot||0} | ${tot?Math.round(w*100/tot)+'%':'--'} | ${w} | ${l} | ${tier} | ${r.leaguePoints??0} | ${high} | ${prev} |
`;
}
function _buildPage(s,ranked,games){
const page=document.getElementById('page-career');
const name=s.gameName||s.displayName||'---';
const tag=s.tagLine||'';
const lvl=s.summonerLevel||'--';
const iconUrl=ip(`/lol-game-data/assets/v1/profile-icons/${s.profileIconId||29}.jpg`);
const copyTxt=tag?`${name}#${tag}`:name;
const solo=ranked?.queueMap?.['RANKED_SOLO_5x5']||{};
const flex=ranked?.queueMap?.['RANKED_FLEX_SR']||{};
const{k,d,a,w,l,kda}=_stats(games);
const champs=_champIcons(games).map(c=>`
`).join('');
page.innerHTML=`
| 游戏类型 | 总计 | 胜率 | 胜场 | 败场 | 段位 | 胜点 | 最高段位 | 上赛季结算段位 |
${_rankRow(solo,'单排')}${_rankRow(flex,'灵活组排')}
近期战绩(最近 ${games.length} 场)
胜场:${w}
败场:${l}
KDA: ${k} / ${d} / ${a} (${kda})
${champs}
`;
_renderGames(games,0);
}
function _renderGames(games,qid){
const el=document.getElementById('cvGL');if(!el)return;
const list=qid?games.filter(g=>g.queueId===qid):games;
if(!list.length){el.innerHTML='';return;}
el.innerHTML=list.map(g=>{
const win=g.win,rm=g.remake;
const rc=rm?'cr':'';
const bc=rm?'gbar re':(win?'gbar win':'gbar lose');
const rtxt=rm?'重开':(win?'胜利':'失败');
const rcls=rm?'gres cr':(win?'gres cw':'gres cl');
const gold=g.gold>=1000?(g.gold/1000).toFixed(1)+'k':g.gold||0;
const items=(g.items||[]).slice(0,7).map(p=>
p?`
`
:``).join('');
const s1=g.sp1?`
`:'';
const s2=g.sp2?`
`:'';
return`
${rtxt}
${esc(qname(g.queueId))}
${g.champLevel}
${s1}${s2}
${g.kills} / ${g.deaths} / ${g.assists}
${g.cs} CS · ${g.dur}
${items}
${gold}
${esc(g.time||'')}
`;
}).join('');
}
function careerFilter(qid){_renderGames(_cParsed,qid);}
async function careerRefresh(){if(_cPuuid&&_cSummoner)await _loadCareer(_cPuuid,_cSummoner);}
async function careerBackToMe(){
try{const s=await API.get('summoner');_cSummoner=s;_cPuuid=s.puuid;await _loadCareer(s.puuid,s);}
catch(e){showToast('获取失败','err');}
}