diff --git a/.workbuddy/memory/2026-09-03.md b/.workbuddy/memory/2026-09-03.md index d4cf855..d05774a 100644 --- a/.workbuddy/memory/2026-09-03.md +++ b/.workbuddy/memory/2026-09-03.md @@ -115,3 +115,9 @@ - **缓存目录数据清理(用户指令「去掉的赛道 现有数据也要删除」)**:删除全部已剔除赛道历史文件 12 个(颜值造型 3 + 情感 3 + 二次元 3 + 化妆美容 3),目录现仅保留 5 赛道×3 期 = 15 文件 - 验证:py_compile OK + 断言(保留=5 赛道,颜值造型/情感不在)+ ranking 接口实测 categories=5(美食/生活vlog/旅行/小剧场/亲子)dates=3 total=250 读取正常 - 教训:用户「情感 去掉」紧接「颜值造型 去掉」=连续精简指令,需完整执行不可只当上一条确认 + +## 工作台「账号周榜」入口 →「热点数据」多榜 tab 页 +- 用户指令:「账号周榜入口改为热点数据,里面用 tab 区分数据列表,和首页一样」 +- 改动:app.js 首页入口卡片 title 账号周榜→热点数据(desc 多榜切换)、CRUMB_TITLES.ranking + router titles.ranking→热点数据;data-pages.js renderRanking 重构为多 tab 页——RANK_TABS 四 tab(week 账号周榜/hot 视频热榜/likes 点赞榜/fans 涨粉榜,与首页 rank-preview 一致),week 显示完整周榜列表(筛选/排序/分页/关注,原逻辑保留),其余 tab 显示「建设中」占位(与首页行为一致,后端 RANKING_DIR 目前仅周榜 json,后续数据落盘即可接入) +- 验证:node --check 两文件通过;服务 8900 存活、新 js 已生效(grep 热点数据=3/1);带 ?v= 打开 #/ranking 页面 +- 纯前端静态改动,server.js 未变无需重启服务 diff --git a/project/短视频脚本创作/V1.0/mcn-work-shop/public/app.js b/project/短视频脚本创作/V1.0/mcn-work-shop/public/app.js index 6904297..d92a430 100644 --- a/project/短视频脚本创作/V1.0/mcn-work-shop/public/app.js +++ b/project/短视频脚本创作/V1.0/mcn-work-shop/public/app.js @@ -696,7 +696,7 @@ async function router() { } // 数据功能页 if (typeof window.DataPages !== 'undefined') { - const titles = { ranking: '账号周榜', accounts: '账号列表', account: '账号详情', video: '视频详情', rewrites: 'AI写脚本', reviews: 'AI脚本诊断' }; + const titles = { ranking: '热点数据', accounts: '账号列表', account: '账号详情', video: '视频详情', rewrites: 'AI写脚本', reviews: 'AI脚本诊断' }; const pages = { 'ranking': () => window.DataPages.renderRanking(view), 'accounts': () => window.DataPages.renderAccounts(view), diff --git a/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js b/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js index 9625ccc..71e288a 100644 --- a/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js +++ b/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js @@ -502,18 +502,64 @@ async function confirmAiScript(accountName, btn) { } /* ================= 周榜 ================= */ +/* ================= 热点数据(#/ranking:账号周榜为主,多榜 tab 与首页 rank-preview 一致) ================= */ async function renderRanking(view) { - let state = { date: '', category: '', sortBy: 'comprehensiveScore', order: 'desc', page: 1, pageSize: 20, dates: [], categories: [] }; - const data = await api('/api/dsh/ranking?pageSize=20').catch((e) => ({ ok: false, error: e.message })); - if (!data.ok) { view.innerHTML = `
${toolbarBack()}账号周榜
${esc(data.error || '加载失败')}
`; bindBack(view); return; } - state.dates = data.dates || []; state.categories = data.categories || []; state.date = data.date; state.category = data.category; + // tab 与首页 rank-tabs 一致:账号周榜有本地数据文件;视频热榜/点赞榜/涨粉榜暂占位(后端 RANKING_DIR 目前仅周榜 json) + const RANK_TABS = [ + ['week', '账号周榜'], + ['hot', '视频热榜'], + ['likes', '点赞榜'], + ['fans', '涨粉榜'], + ]; + let state = { tab: 'week', date: '', category: '', sortBy: 'comprehensiveScore', order: 'desc', page: 1, pageSize: 20, dates: [], categories: [] }; + const meta = await api('/api/dsh/ranking?pageSize=20').catch((e) => ({ ok: false, error: e.message })); + if (!meta.ok) { + view.innerHTML = `
${toolbarBack()}热点数据
${esc(meta.error || '加载失败')}
`; + bindBack(view); return; + } + state.dates = meta.dates || []; state.categories = meta.categories || []; state.date = meta.date || (state.dates[0] || ''); state.category = meta.category || ''; - async function load() { - const d = await api('/api/dsh/ranking?date=' + encodeURIComponent(state.date) + '&category=' + encodeURIComponent(state.category) + '&sortBy=' + state.sortBy + '&order=' + state.order + '&page=' + state.page + '&pageSize=' + state.pageSize); - const di = state.dates.indexOf(state.date); - const WIDE = new Set(['comprehensiveScore', 'followers', 'newFans', 'newLikes', 'newComments', 'newShares']); // 数值列(窄+右对齐) - const sortable = (key, label) => `${label}${state.sortBy === key ? (state.order === 'asc' ? ' ↑' : ' ↓') : ''}`; - const rows = (d.items || []).map((r) => ` + const tabLabel = () => { const t = RANK_TABS.find(([k]) => k === state.tab); return t ? t[1] : ''; }; + const tabs = () => ` +
+ ${RANK_TABS.map(([k, label]) => ``).join('')} +
`; + const toolbar = (withFilters) => ` +
+ ${toolbarBack()} + 热点数据 + ${withFilters ? `
+ + + ${esc(state.date)} + +
` : ''} +
`; + + function bindShell() { + bindBack(view); + view.querySelectorAll('.rank-tab').forEach((t) => t.addEventListener('click', () => { + const k = t.dataset.rankTab; + if (k === state.tab) return; + state.tab = k; state.page = 1; render(); + })); + } + + function render() { + if (state.tab !== 'week') { + // 其余榜单与首页一致:建设中占位(无本地数据文件,数据获取技能落盘后即可接入) + view.innerHTML = `
${toolbar(false)}${tabs()}
「${esc(tabLabel())}」建设中,敬请期待
`; + bindShell(); return; + } + (async () => { + const d = await api('/api/dsh/ranking?date=' + encodeURIComponent(state.date) + '&category=' + encodeURIComponent(state.category) + '&sortBy=' + state.sortBy + '&order=' + state.order + '&page=' + state.page + '&pageSize=' + state.pageSize); + const di = state.dates.indexOf(state.date); + const WIDE = new Set(['comprehensiveScore', 'followers', 'newFans', 'newLikes', 'newComments', 'newShares']); // 数值列(窄+右对齐) + const sortable = (key, label) => `${label}${state.sortBy === key ? (state.order === 'asc' ? ' ↑' : ' ↓') : ''}`; + const rows = (d.items || []).map((r) => ` ${r.rank ?? '-'} ${esc(r.category || '-')} ${r.profileUrl ? `${esc(r.accountName)}` : esc(r.accountName)} @@ -525,21 +571,9 @@ async function renderRanking(view) { ${fmt(r.newShares)} ${r.inDb ? `查看` : ``} `).join(''); - view.innerHTML = ` + view.innerHTML = `
-
- ${toolbarBack()} - 账号周榜 -
- - - ${esc(state.date)} - -
-
+ ${toolbar(true)}${tabs()}
@@ -548,26 +582,29 @@ async function renderRanking(view) { ${rows || ''}
暂无周榜数据
- ${pagerHtml(d.total, d.page, state.pageSize, (p) => { state.page = p; load(); })} + ${pagerHtml(d.total, d.page, state.pageSize, (p) => { state.page = p; render(); })}
`; - bindBack(view); - view.querySelectorAll('.sortable').forEach((th) => th.addEventListener('click', () => { - const k = th.dataset.sort; - if (state.sortBy === k) state.order = state.order === 'asc' ? 'desc' : 'asc'; - else { state.sortBy = k; state.order = k === 'rank' ? 'asc' : 'desc'; } - state.page = 1; load(); - })); - view.querySelector('#rankCat').addEventListener('change', (e) => { state.category = e.target.value; state.page = 1; load(); }); - view.querySelector('#rankPrev').addEventListener('click', () => { const i = state.dates.indexOf(state.date) - 1; if (i >= 0) { state.date = state.dates[i]; state.page = 1; load(); } }); - view.querySelector('#rankNext').addEventListener('click', () => { const i = state.dates.indexOf(state.date) + 1; if (i < state.dates.length) { state.date = state.dates[i]; state.page = 1; load(); } }); - bindPager(view, (p) => { state.page = p; load(); }); - view.querySelectorAll('[data-import]').forEach((b) => b.addEventListener('click', () => { - const r = JSON.parse(b.dataset.import); - confirmSaveAccount(r.accountName, r.profileUrl || '', b); - })); - view._reload = load; // 静默自动刷新(保留筛选/翻页状态) + bindShell(); + view.querySelectorAll('.sortable').forEach((th) => th.addEventListener('click', () => { + const k = th.dataset.sort; + if (state.sortBy === k) state.order = state.order === 'asc' ? 'desc' : 'asc'; + else { state.sortBy = k; state.order = k === 'rank' ? 'asc' : 'desc'; } + state.page = 1; render(); + })); + const rankCat = view.querySelector('#rankCat'); + if (rankCat) rankCat.addEventListener('change', (e) => { state.category = e.target.value; state.page = 1; render(); }); + const prev = view.querySelector('#rankPrev'), next = view.querySelector('#rankNext'); + if (prev) { prev.disabled = di <= 0; prev.addEventListener('click', () => { const i = state.dates.indexOf(state.date) - 1; if (i >= 0) { state.date = state.dates[i]; state.page = 1; render(); } }); } + if (next) { next.disabled = di < 0 || di >= state.dates.length - 1; next.addEventListener('click', () => { const i = state.dates.indexOf(state.date) + 1; if (i < state.dates.length) { state.date = state.dates[i]; state.page = 1; render(); } }); } + bindPager(view, (p) => { state.page = p; render(); }); + view.querySelectorAll('[data-import]').forEach((b) => b.addEventListener('click', () => { + const r = JSON.parse(b.dataset.import); + confirmSaveAccount(r.accountName, r.profileUrl || '', b); + })); + view._reload = render; // 静默自动刷新(保留 tab/筛选/翻页状态) + })(); } - await load(); + render(); } /* ================= 账号列表 ================= */