From a1227600f78a4ab1c2eed8df2994d209fe8fe714 Mon Sep 17 00:00:00 2001 From: maogeigei Date: Thu, 3 Sep 2026 12:20:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E5=8F=B0=E3=80=8C=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E5=91=A8=E6=A6=9C=E3=80=8D=E5=85=A5=E5=8F=A3=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E3=80=8C=E7=83=AD=E7=82=B9=E6=95=B0=E6=8D=AE=E3=80=8D?= =?UTF-8?q?=E5=A4=9A=E6=A6=9C=20tab=20=E9=A1=B5=EF=BC=9A=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=E5=8D=A1=E7=89=87/=E9=9D=A2=E5=8C=85?= =?UTF-8?q?=E5=B1=91/=E8=B7=AF=E7=94=B1=E6=A0=87=E9=A2=98=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E6=94=B9=E5=90=8D=EF=BC=9BrenderRanking=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E2=80=94=E2=80=94RANK=5FTABS=20=E5=9B=9B=20tab?= =?UTF-8?q?=EF=BC=88=E8=B4=A6=E5=8F=B7=E5=91=A8=E6=A6=9C/=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E7=83=AD=E6=A6=9C/=E7=82=B9=E8=B5=9E=E6=A6=9C/?= =?UTF-8?q?=E6=B6=A8=E7=B2=89=E6=A6=9C=EF=BC=8C=E4=B8=8E=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=20rank-preview=20=E4=B8=80=E8=87=B4=EF=BC=89=EF=BC=8C=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E5=91=A8=E6=A6=9C=20tab=20=E4=BF=9D=E7=95=99=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E5=88=97=E8=A1=A8=EF=BC=88=E7=AD=9B=E9=80=89/?= =?UTF-8?q?=E6=8E=92=E5=BA=8F/=E5=88=86=E9=A1=B5/=E5=85=B3=E6=B3=A8?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E5=85=B6=E4=BD=99=E6=A6=9C=E6=9A=82=E5=8D=A0?= =?UTF-8?q?=E4=BD=8D=EF=BC=88=E5=90=8E=E7=AB=AF=E4=BB=85=E5=91=A8=E6=A6=9C?= =?UTF-8?q?=20json=EF=BC=8C=E6=95=B0=E6=8D=AE=E8=90=BD=E7=9B=98=E5=90=8E?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .workbuddy/memory/2026-09-03.md | 6 + .../V1.0/mcn-work-shop/public/app.js | 2 +- .../V1.0/mcn-work-shop/public/data-pages.js | 121 ++++++++++++------ 3 files changed, 86 insertions(+), 43 deletions(-) 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(); } /* ================= 账号列表 ================= */