import { api } from "../api.js"; import { avatar, badge, emptyState, sectionHeader, videoCard, } from "../components.js"; import { barChart, lineChart, themeColor } from "../charts.js"; import { escapeAttr, escapeHtml, formatCount, formatDate, formatPercent, } from "../format.js"; import { replaceQuery } from "../router.js"; const SORTS = [ ["view", "播放"], ["efficiency", "内容效率"], ["latest", "最新发布"], ["interaction", "互动率"], ]; function sortedVideos(videos, sort) { const items = [...videos]; if (sort === "latest") { items.sort((a, b) => b.pubdate - a.pubdate); } else if (sort === "interaction") { items.sort((a, b) => (b.interaction_rate || 0) - (a.interaction_rate || 0)); } else if (sort === "efficiency") { items.sort((a, b) => (b.efficiency || 0) - (a.efficiency || 0)); } else { items.sort((a, b) => (b.metrics?.view || 0) - (a.metrics?.view || 0)); } return items; } export async function renderUp(root, { params, query }) { const mid = Number(params[0]); const sort = query.get("sort") || "view"; const up = await api(`/api/ups/${mid}`); const videos = sortedVideos(up.videos || [], sort); const topForBar = [...(up.videos || [])] .sort((a, b) => (b.metrics?.view || 0) - (a.metrics?.view || 0)) .slice(0, 12); root.innerHTML = `
← 返回 UP 榜 B 站空间
${avatar(up, "hero-avatar")}

${escapeHtml(up.up_name || `UP ${mid}`)}

mid ${up.up_mid} 首RE时间 ${escapeHtml(formatDate(up.first_pubdate))} ${up.blacklisted ? badge("黑名单 · 仅影响发现", "warning") : ""}

最近发布 ${escapeHtml(formatDate(up.latest_pubdate))}

视频数${formatCount(up.video_count)}
总时长${up.content_hours == null ? "—" : `${formatCount(up.content_hours)} 小时`}
播放/小时${formatCount(up.views_per_hour)}
总播放${formatCount(up.total_views)}
平均播放${formatCount(up.avg_views)}
总互动${formatCount(up.total_interactions)}
平均互动率${formatPercent(up.avg_interaction)}
粉丝(入库时)${formatCount(up.up_follower)}
当前粉丝${formatCount(up.follower_latest)}
${sectionHeader("该 UP 视频总播放趋势")} ${up.series?.dates?.length ? `
` : emptyState("暂无趋势", "该 UP 还没有成功快照。")}

按该 UP 全部视频的每日播放合计绘制;缺失日期断开。

${videos.length > 1 ? `
${sectionHeader("单视频播放对比")} ${topForBar.length ? `
` : emptyState("暂无视频数据")}
` : ""}

视频列表

${videos.length ? videos.map((item) => videoCard(item)).join("") : emptyState("没有视频")}
`; const trendElement = root.querySelector("#up-trend"); if (trendElement) { lineChart(trendElement, { dates: up.series.dates, values: up.series.views, name: "总播放", color: themeColor("accent"), scale: true, }); } const barsElement = root.querySelector("#up-bars"); if (barsElement) { barChart(barsElement, { labels: topForBar.map((item) => (item.title || `#${item.aid}`).slice(0, 12)), values: topForBar.map((item) => item.metrics?.view || 0), name: "播放", color: themeColor("blue"), }); } root.querySelector("#up-sort")?.addEventListener("change", (event) => { replaceQuery({ sort: event.target.value }); }); }