R37-R38: 榜单下载按钮回 rank-toolbar 行+去白底纯图标;首页榜单 tab 右侧加同款下载按钮(复用 updateRankingData)

This commit is contained in:
maogeigei committed 2026-09-03 17:50:32 +08:00
1 parent 1f147e84dd
commit 28eba2a3b0
5 files changed
+44 -16

No files matched your search

+23
View File
@@ -339,5 +339,28 @@
- 视觉截图:tab「账号周榜/视频热榜/点赞榜」+ ⬇ 在第一行右侧;筛选下拉+翻页在第二行 - 视觉截图:tab「账号周榜/视频热榜/点赞榜」+ ⬇ 在第一行右侧;筛选下拉+翻页在第二行
- **版本**:data-pages.js x→y(CSS 不动) - **版本**:data-pages.js x→y(CSS 不动)
## R37 榜单下载按钮回 rank-toolbar + 去白底(09-03 17:40)
- **R36 偏差纠正**:用户反馈「你把 tab 和下载按钮 放下去,为啥总是喜欢把东西摆在标题哪一行呢」——R36 把 tab 提到 page-toolbar 错了,标题行应该只放 返回+标题
- **R37 正确布局**:
- page-toolbar:返回 + 标题「热点数据」(干净,无其他元素)
- rank-toolbar:**恒渲染**(含 tab + 下载按钮,保证空态/错误态也能看到更新入口),筛选+翻页仅 withFilters=true 时出现
- tab + ⬇ 紧贴:在 rank-tabs 容器内 rank-tabs flex:1 占满,tab 按钮 + ⬇ 排在最左(gap 4px),空白推到 ⬇ 之后容器尾
- **去白底**:用户「下载按钮去掉白底 只显示ICON」→ style.css `#rankUpdate { background: transparent; border-color: transparent }` + `#rankUpdate:hover` 同样覆盖 .btn:hover 默认主色边框;CDP 计算样式确认 bg=rgba(0,0,0,0) border=rgba(0,0,0,0)
- **验证**:
- DOM:page-toolbar 仅 返回+标题;rank-toolbar 含 rank-tabs(tab+⬇) + 筛选;⬇ inRankTabs=true 紧贴 tab「点赞榜」
- 视觉截图:tab 行下划线延续到 ⬇ 下方(rank-tabs border-bottom 自然延伸),⬇ 纯 icon 无边框,视觉与 tab 同组
- **版本**:data-pages.js y→z、style.css x→y(CSS 去白底+hover 覆盖;data-pages 移动 tab 到 rank-toolbar)
## R34 同步 dsh 副本计划 ## R34 同步 dsh 副本计划
- dsh 副本 `C:\Users\maidou\.dsh\skills\short-video-script\`(独立副本,非软链)—— R34 改动 data-pages.js/app.js/style.css/index.html 同步评估后人工复制 - dsh 副本 `C:\Users\maidou\.dsh\skills\short-video-script\`(独立副本,非软链)—— R34 改动 data-pages.js/app.js/style.css/index.html 同步评估后人工复制
## R38 首页榜单 tab 右侧加同款下载按钮(09-03 17:50)
- **需求**:用户「首页 榜单tab组件右边 相同位置也放下载按钮」——首页 rank-preview 的 rank-tabs(账号周榜/视频热榜/点赞榜)右侧加与榜单页 #rankUpdate 同款 ⬇ 按钮,行为完全一致(确认弹窗→后台任务重抓→冷却防重)
- **改动 3 文件**:
- `data-pages.js`:`window.DataPages` 导出新增 `updateRankingData`(L1811,供 app.js 首页跨文件调用;原榜单页绑定已在内)
- `app.js`:renderHome 首页 `.rank-preview .recent-head` 内 `.rank-tabs` 后插入 `<button class="btn btn-icon home-rank-update" id="homeRankUpdate" title="更新榜单数据…">${svgIcon('download',16,'currentColor')}</button>`(L330);renderPage 首页分支事件绑定 `window.DataPages && window.DataPages.updateRankingData(view, hUpd)`(L744-745)
- `style.css`:`.home-rank-update`(padding 11.5px 对齐 #rankUpdate + 去白底/边框透明)+ hover 覆盖 `.btn:hover` 默认主色边框
- **版本**:style.css ?v=20260903y→z、app.js v→w、data-pages.js z→aa(同文件三处 bump 串行)
- **CDP 冒烟** `tmp/cdp-r38-home-btn.mjs`(9225)15/15 PASS:三资源版本(z/w/aa)加载 ✓;homeRankUpdate 纯图标透明底(bg/border rgba(0,0,0,0))宽 35px ✓;**紧贴 tab 右侧 12px** ✓;与筛选控件同行无溢出(sameLineTools=true overflow=false)✓;点击 → 确认弹窗出现(title=更新榜单数据/上次更新 2026-08-24/取消+确认按钮)✓ 取消关闭 ✓
- **脚本坑**:`link[href$=".css"]` 匹配不上带 `?v=` query 的 href(以 z 结尾非 .css)→ 改 `link[rel="stylesheet"]` 后全绿
- **R35-R38 累计未推送**:本地 HEAD 领先 origin/main 2 commit(449d784 R35 / 1f147e8 R36)+ working tree R37/R38 待提交
@@ -327,6 +327,7 @@ function renderHome() {
<button class="rank-tab" data-rank-tab="hot" title="近7日数据" role="tab">视频热榜</button> <button class="rank-tab" data-rank-tab="hot" title="近7日数据" role="tab">视频热榜</button>
<button class="rank-tab" data-rank-tab="likes" title="近7日数据" role="tab">点赞榜</button> <button class="rank-tab" data-rank-tab="likes" title="近7日数据" role="tab">点赞榜</button>
</div> </div>
<button class="btn btn-icon home-rank-update" id="homeRankUpdate" title="更新榜单数据:后台任务重新抓取三榜(账号周榜 5 赛道 / 视频热榜 / 点赞榜)最新一期并落盘;30 分钟内已更新会拦截防重复">${svgIcon('download', 16, 'currentColor')}</button>
<div class="rank-tools" id="rankTools"> <div class="rank-tools" id="rankTools">
<select id="rankCat" class="input-select rank-filter" title="赛道筛选"></select> <select id="rankCat" class="input-select rank-filter" title="赛道筛选"></select>
<button class="btn btn-sm" id="rankPrevDate" title="上一期">◀</button> <button class="btn btn-sm" id="rankPrevDate" title="上一期">◀</button>
@@ -739,6 +740,9 @@ async function router() {
updateCrumbs(''); updateCrumbs('');
view.innerHTML = renderHome(); view.innerHTML = renderHome();
view.querySelectorAll('.data-card').forEach((b) => b.addEventListener('click', () => { location.hash = b.dataset.hash; })); view.querySelectorAll('.data-card').forEach((b) => b.addEventListener('click', () => { location.hash = b.dataset.hash; }));
// 首页榜单下载按钮(复用榜单页同款后台任务;data-pages.js updateRankingData 已导出到 window.DataPages)
const hUpd = view.querySelector('#homeRankUpdate');
if (hUpd) hUpd.addEventListener('click', () => window.DataPages && window.DataPages.updateRankingData(view, hUpd));
// 榜单 tab 切换:week/hot/likes 各自按 board 拉数据渲染(meta 与数据均带 board 参数) // 榜单 tab 切换:week/hot/likes 各自按 board 拉数据渲染(meta 与数据均带 board 参数)
view.querySelectorAll('.rank-tab').forEach((t) => t.addEventListener('click', () => { view.querySelectorAll('.rank-tab').forEach((t) => t.addEventListener('click', () => {
setRankBoard(t.dataset.rankTab, t); setRankBoard(t.dataset.rankTab, t);
@@ -522,14 +522,11 @@ async function renderRanking(view) {
const st = { week: mkState(), hot: mkState(), likes: mkState() }; const st = { week: mkState(), hot: mkState(), likes: mkState() };
let tab = 'week'; let tab = 'week';
const tabLabel = () => { const t = RANK_TABS.find(([k]) => k === tab); return t ? t[1] : ''; }; const tabLabel = () => { const t = RANK_TABS.find(([k]) => k === tab); return t ? t[1] : ''; };
// 09-03 tab 始终在 page-toolbar 渲染(含空态/错误态),下载按钮紧贴 tab 右侧;筛选+翻页放 rank-toolbar(withFilters 时) // 09-03 page-toolbar 只放 返回+标题;rank-toolbar 恒渲染含 tab + 下载按钮(紧贴 tab 右侧)保证空态/错误态也能看到更新入口(首次抓取);筛选+翻页仅 withFilters 时出现在同行最右
const toolbar = (s, withFilters) => { const toolbar = (s, withFilters) => {
const tabsHtml = `<div class="rank-tabs" role="tablist" style="margin-left:auto"> const tabsHtml = `${RANK_TABS.map(([k, label, tip]) => `<button class="rank-tab${k === tab ? ' active' : ''}" data-rank-tab="${k}"${tip ? ` title="${tip}"` : ''} role="tab">${label}</button>`).join('')}
${RANK_TABS.map(([k, label, tip]) => `<button class="rank-tab${k === tab ? ' active' : ''}" data-rank-tab="${k}"${tip ? ` title="${tip}"` : ''} role="tab">${label}</button>`).join('')} <button class="btn btn-icon" id="rankUpdate" title="更新榜单数据:后台任务重新抓取三榜(账号周榜 5 赛道 / 视频热榜 / 点赞榜)最新一期并落盘;30 分钟内已更新会拦截防重复">${svgIcon('download', 16, 'currentColor')}</button>`;
</div> const filtersHtml = withFilters ? `<div class="toolbar-right">
<button class="btn btn-icon" id="rankUpdate" title="更新榜单数据:后台任务重新抓取三榜(账号周榜 5 赛道 / 视频热榜 / 点赞榜)最新一期并落盘;30 分钟内已更新会拦截防重复">${svgIcon('download', 16, 'currentColor')}</button>`;
const filtersHtml = withFilters ? `<div class="rank-toolbar">
<div class="toolbar-right">
<select id="rankCat" class="input-select" title="赛道筛选"> <select id="rankCat" class="input-select" title="赛道筛选">
<option value="">全部赛道</option> <option value="">全部赛道</option>
${s.categories.map((c) => `<option value="${esc(c)}" ${c === s.category ? 'selected' : ''}>${esc(c)}</option>`).join('')} ${s.categories.map((c) => `<option value="${esc(c)}" ${c === s.category ? 'selected' : ''}>${esc(c)}</option>`).join('')}
@@ -537,14 +534,15 @@ async function renderRanking(view) {
<button class="btn" id="rankPrev" title="上一期">◀</button> <button class="btn" id="rankPrev" title="上一期">◀</button>
<span class="pager-info" title="选择日期">${esc(s.date)}</span> <span class="pager-info" title="选择日期">${esc(s.date)}</span>
<button class="btn" id="rankNext" title="下一期">▶</button> <button class="btn" id="rankNext" title="下一期">▶</button>
</div> </div>` : '';
</div>` : '';
return `<div class="page-toolbar"> return `<div class="page-toolbar">
${toolbarBack()} ${toolbarBack()}
<span class="page-title">热点数据</span> <span class="page-title">热点数据</span>
${tabsHtml}
</div> </div>
${filtersHtml}`; <div class="rank-toolbar">
<div class="rank-tabs" role="tablist">${tabsHtml}</div>
${filtersHtml}
</div>`;
}; };
// 标题列统一截断(作品标题很长):悬停 title 看全文 // 标题列统一截断(作品标题很长):悬停 title 看全文
@@ -1810,4 +1808,4 @@ async function openScriptModal({ rewriteId, videoId } = {}) {
renderModal(); renderModal();
} }
window.DataPages = { renderRanking, renderAccounts, renderAccountDetail, renderVideoDetail, renderRewrites, renderReviews, openScriptModal }; window.DataPages = { renderRanking, renderAccounts, renderAccountDetail, renderVideoDetail, renderRewrites, renderReviews, openScriptModal, updateRankingData };
@@ -4,7 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MCN工作台</title> <title>MCN工作台</title>
<link rel="stylesheet" href="style.css?v=20260903x"> <link rel="stylesheet" href="style.css?v=20260903z">
<script src="vendor/echarts.min.js"></script> <script src="vendor/echarts.min.js"></script>
</head> </head>
<body> <body>
@@ -41,7 +41,7 @@
</div> </div>
</div> </div>
<script src="app.js?v=20260903v"></script> <script src="app.js?v=20260903w"></script>
<script src="data-pages.js?v=20260903y"></script> <script src="data-pages.js?v=20260903aa"></script>
</body> </body>
</html> </html>
@@ -427,7 +427,10 @@ main#view { height: calc(100vh - 55px); overflow: auto; } /* 55px=topbar 实际
.btn:disabled { opacity: .5; cursor: not-allowed; } .btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-busy { background: var(--primary-soft) !important; color: var(--primary) !important; border-color: var(--primary) !important; opacity: .8; } .btn-busy { background: var(--primary-soft) !important; color: var(--primary) !important; border-color: var(--primary) !important; opacity: .8; }
.btn-icon { padding: 5px 9px; display: inline-flex; align-items: center; justify-content: center; } /* 纯图标按钮(09-03:榜单更新等) */ .btn-icon { padding: 5px 9px; display: inline-flex; align-items: center; justify-content: center; } /* 纯图标按钮(09-03:榜单更新等) */
#rankUpdate { padding-left: 11.5px; padding-right: 11.5px; } /* 09-03 更新按钮加宽 5px(icon 16 + 左右 padding 9→11.5),更易点中 */ #rankUpdate { padding-left: 11.5px; padding-right: 11.5px; background: transparent; border-color: transparent; } /* 09-03 更新按钮加宽 5px(icon 16 + 左右 padding 9→11.5),更易点中;去白底/边框只显 icon */
#rankUpdate:hover { background: transparent; border-color: transparent; } /* 覆盖 .btn:hover 默认主色边框 */
.home-rank-update { background: transparent; border-color: transparent; padding-left: 11.5px; padding-right: 11.5px; } /* 09-03 首页榜单下载按钮:去白底只显 icon,padding 与榜单 #rankUpdate 对齐 */
.home-rank-update:hover { background: transparent; border-color: transparent; }
.btn-busy .ic { animation: req-spin 1s linear infinite; } /* busy 态图标旋转(复用弹窗 spinner 动画) */ .btn-busy .ic { animation: req-spin 1s linear infinite; } /* busy 态图标旋转(复用弹窗 spinner 动画) */
.btn-sm { padding: 3px 10px; font-size: 14px; border-radius: 6px; } .btn-sm { padding: 3px 10px; font-size: 14px; border-radius: 6px; }
.btn-primary { background: var(--primary); color: #fff; border-color: transparent; } .btn-primary { background: var(--primary); color: #fff; border-color: transparent; }