137 lines
8.6 KiB
JavaScript
137 lines
8.6 KiB
JavaScript
/* NBA球迷大全 独立详情页渲染(/team/1 /player/1 /game/1 /news/1 /person/1) */
|
||
const $ = (s) => document.querySelector(s);
|
||
const esc = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
|
||
const STATUS_CN = { scheduled: "未开始", live: "进行中", finished: "已结束" };
|
||
|
||
async function getJSON(url) { const r = await fetch(url); if (!r.ok) throw new Error("记录不存在或已删除"); return r.json(); }
|
||
|
||
/* 交叉链接 */
|
||
const T = (id, name) => `<a class="xlink" href="/team/${id}">${esc(name)}</a>`;
|
||
const P = (id, name) => `<a class="xlink" href="/player/${id}">${esc(name)}</a>`;
|
||
const G = (id, text) => `<a class="xlink" href="/game/${id}">${esc(text)}</a>`;
|
||
const N = (id, title) => `<a class="xlink" href="/news/${id}">${esc(title)}</a>`;
|
||
const PER = (id, name) => `<a class="xlink" href="/person/${id}">${esc(name)}</a>`;
|
||
|
||
/* ================= 球队 ================= */
|
||
function renderTeam(d) {
|
||
const t = d.team;
|
||
const standings = (d.standings || []).map((s) =>
|
||
`<span class="season-pill">${esc(s.season)} ${esc(s.conference)}第${s.rank}名 · ${s.wins}-${s.losses}</span>`).join("");
|
||
const roster = (d.roster || []).map((p) => `
|
||
<div class="row-item">
|
||
<span>${P(p.id, p.name)} <span class="en">#${p.number} · ${esc(p.position)}</span></span>
|
||
<span>本季场均 <span class="num-badge">${p.season.pts}</span> 分 / ${p.season.reb} 板 / ${p.season.ast} 助</span>
|
||
</div>`).join("") || '<div class="txt">暂无球员数据</div>';
|
||
const games = (d.recent_games || []).map((g) => {
|
||
const score = g.status === "finished" ? `<span class="num-badge">${g.away_score} : ${g.home_score}</span>` : "VS";
|
||
return `<div class="row-item">
|
||
<span>${G(g.id, `${g.away_team} ${score} ${g.home_team}`)}</span>
|
||
<span class="en">${esc(g.round_name)} · ${esc(g.game_time.slice(0, 16))} · ${STATUS_CN[g.status]}</span>
|
||
</div>`;
|
||
}).join("") || '<div class="txt">暂无比赛</div>';
|
||
$("#crumb").innerHTML = `<span class="en">🏟️ 球队 / ${esc(t.name)}</span>`;
|
||
$("#detail-body").innerHTML = `
|
||
<div class="hero">
|
||
<div class="big">${esc(t.name)}</div>
|
||
<div class="detail-sub">${esc(t.name_en)} · ${esc(t.city)} · ${esc(t.arena)} · 建队 ${t.founded} 年 · 总冠军 ×${t.champion_count}</div>
|
||
</div>
|
||
<div class="section"><h3>📈 各赛季战绩</h3>${standings || '<span class="txt">暂无排名数据</span>'}</div>
|
||
<div class="section"><h3>📝 球队简介</h3><div class="txt">${esc(t.intro || "暂无简介")}</div></div>
|
||
<div class="section"><h3>🧑🏫 主教练</h3><div class="txt">${esc(t.head_coach || "未知")}</div></div>
|
||
<div class="section"><h3>⭐ 主要球员(本赛季场均)</h3>${roster}</div>
|
||
<div class="section"><h3>📅 近期比赛</h3>${games}</div>`;
|
||
}
|
||
|
||
/* ================= 球员 ================= */
|
||
function renderPlayer(p) {
|
||
const logs = (p.game_logs || []).map((g) => {
|
||
const score = g.home_score !== null ? `${g.away_score} : ${g.home_score}` : "VS";
|
||
return `<div class="row-item">
|
||
<span>${G(g.game_id, `${g.away_team} ${score} ${g.home_team}`)} <span class="en">${esc(g.round_name)} · ${esc(g.game_time.slice(0, 10))}</span></span>
|
||
<span><span class="num-badge">${g.pts}</span>分 ${g.reb}板 ${g.ast}助 ${g.stl}断 ${g.blk}帽 ${g.min}分钟</span>
|
||
</div>`;
|
||
}).join("") || '<div class="txt">暂无比赛记录</div>';
|
||
$("#crumb").innerHTML = `<span class="en">⭐ 球员 / ${esc(p.name)}</span>`;
|
||
$("#detail-body").innerHTML = `
|
||
<div class="hero">
|
||
<div class="big">${esc(p.name)}</div>
|
||
<div class="detail-sub">${esc(p.name_en || "")} · ${p.team ? T(p.team_id ?? 0, p.team) : "自由球员"} · ${esc(p.position)} · #${p.number} · ${esc(p.country)}</div>
|
||
</div>
|
||
<div class="section"><h3>📋 基本信息</h3>
|
||
<div class="kv">
|
||
<div><span class="k">身高</span><span class="v">${p.height_cm} cm</span></div>
|
||
<div><span class="k">体重</span><span class="v">${p.weight_kg} kg</span></div>
|
||
<div><span class="k">选秀</span><span class="v">${esc(p.draft)}</span></div>
|
||
<div><span class="k">年薪</span><span class="v">$${(p.salary_m / 100).toFixed(2)} 亿</span></div>
|
||
<div><span class="k">本季场均</span><span class="v">${p.season.pts}分 ${p.season.reb}板 ${p.season.ast}助</span></div>
|
||
<div><span class="k">本季防守</span><span class="v">${p.season.stl}断 ${p.season.blk}帽</span></div>
|
||
<div><span class="k">生涯场均</span><span class="v">${p.career.pts}分 ${p.career.reb}板 ${p.career.ast}助</span></div>
|
||
<div><span class="k">生涯场次</span><span class="v">${p.career.games} 场</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="section"><h3>🏅 主要荣誉</h3><div class="txt">${esc(p.awards || "暂无")}</div></div>
|
||
<div class="section"><h3>📝 球员简介</h3><div class="txt">${esc(p.bio || "暂无")}</div></div>
|
||
<div class="section"><h3>🏀 近期比赛记录</h3>${logs}</div>`;
|
||
}
|
||
|
||
/* ================= 比赛 ================= */
|
||
function renderGame(g) {
|
||
const finished = g.status === "finished";
|
||
const head = finished
|
||
? `<div class="score-head">${T(g.home_team_id, g.home_team)} <span class="s">${g.home_score}</span> : <span class="s">${g.away_score}</span> ${T(g.away_team_id, g.away_team)}</div>`
|
||
: `<div class="score-head">${T(g.home_team_id, g.home_team)} VS ${T(g.away_team_id, g.away_team)}</div>`;
|
||
const stats = (g.box_score || []).map((s) => `
|
||
<tr><td>${esc(s.team_name)}</td><td>${P(s.player_id, s.player_name)}</td>
|
||
<td class="num">${s.points}</td><td class="num">${s.rebounds}</td><td class="num">${s.assists}</td>
|
||
<td class="num">${s.steals}</td><td class="num">${s.blocks}</td><td class="num">${s.minutes}</td></tr>`).join("");
|
||
$("#crumb").innerHTML = `<span class="en">📅 比赛 / ${esc(g.round_name)}</span>`;
|
||
$("#detail-body").innerHTML = `
|
||
<div class="hero">
|
||
<div style="text-align:center;color:var(--sub);font-size:13px">${esc(g.round_name)} · ${STATUS_CN[g.status]}</div>
|
||
${head}
|
||
<div style="text-align:center;color:var(--sub);font-size:13px;margin-top:6px">🕐 ${esc(g.game_time)} · ${esc(g.venue)} · ${esc(g.broadcast)}</div>
|
||
</div>
|
||
${stats ? `<div class="section"><h3>📊 球员技术统计</h3>
|
||
<table><tr><th>球队</th><th>球员</th><th>得分</th><th>篮板</th><th>助攻</th><th>抢断</th><th>盖帽</th><th>分钟</th></tr>${stats}</table>
|
||
</div>` : '<div class="section"><h3>📊 球员技术统计</h3><div class="txt">暂无统计</div></div>'}`;
|
||
}
|
||
|
||
/* ================= 新闻/百科 ================= */
|
||
function renderNews(n) {
|
||
$("#crumb").innerHTML = `<span class="en">📰 ${n.kind === "wiki" ? "百科" : "新闻"} / ${esc(n.title)}</span>`;
|
||
$("#detail-body").innerHTML = `
|
||
<div class="hero">
|
||
<div class="big">${esc(n.title)}</div>
|
||
<div class="detail-sub">🕐 ${esc(n.publish_time || "")} · ${esc(n.source || "")}${n.author ? " · " + esc(n.author) : ""} · ${n.kind === "wiki" ? "百科词条" : "新闻"}${n.tags ? " · " + esc(n.tags) : ""}</div>
|
||
</div>
|
||
<div class="section"><h3>📄 正文</h3><div class="news-body">${esc(n.content || "")}</div></div>`;
|
||
}
|
||
|
||
/* ================= 人物 ================= */
|
||
function renderPerson(p) {
|
||
$("#crumb").innerHTML = `<span class="en">👥 人物 / ${esc(p.name)}</span>`;
|
||
$("#detail-body").innerHTML = `
|
||
<div class="hero">
|
||
<div class="big">${esc(p.name)}</div>
|
||
<div class="detail-sub">${esc(p.role_cn || p.role || "")} · ${esc(p.title || "")}${p.team_id ? " · " + T(p.team_id, p.team_name || "相关球队") : ""}</div>
|
||
</div>
|
||
<div class="section"><h3>📝 人物简介</h3><div class="txt">${esc(p.bio || "暂无")}</div></div>
|
||
<div class="section"><h3>🏅 主要成就</h3><div class="txt">${esc(p.achievements || "暂无")}</div></div>`;
|
||
}
|
||
|
||
/* ================= 路由 ================= */
|
||
const ROUTERS = { team: renderTeam, player: renderPlayer, game: renderGame, news: renderNews, person: renderPerson };
|
||
const APIS = { team: "/api/teams/", player: "/api/players/", game: "/api/games/", news: "/api/news/", person: "/api/persons/" };
|
||
|
||
(async function init() {
|
||
const m = location.pathname.match(/^\/(team|player|game|news|person)\/(\d+)\/?$/);
|
||
if (!m) { $("#detail-body").innerHTML = '<div class="loading">❌ 地址无效</div>'; return; }
|
||
const [etype, eid] = [m[1], parseInt(m[2])];
|
||
try {
|
||
const d = await getJSON(APIS[etype] + eid);
|
||
ROUTERS[etype](d);
|
||
} catch (e) {
|
||
$("#detail-body").innerHTML = `<div class="loading">❌ ${esc(e.message)}<br><br><a class="tab" href="/">← 返回首页</a></div>`;
|
||
}
|
||
})();
|