feat(workshop): 账号列表去地区列+加AI脚本列(数量/跳转该账号AI写脚本) v22

- dsh-data listAccounts 增 rewrite_count 子查询(口径同视频页:rewrite_log done 且有脚本)
- renderAccounts:删地区列,操作列左加「AI脚本」列——数量>0 显示为链接,0 显示 —
- 跳转 #/rewrites/<账号名>:parseHash param 传 renderRewrites(view, initAccount),预填搜索+note 提示该账号上下文
- app.js rewrites 路由透传 param;空行 colspan 13/12→12/11
This commit is contained in:
maogeigei committed 2026-09-02 18:59:02 +08:00
1 parent 6a5b68fc0b
commit 0cf59c2512
3 files changed
+10 -8

No files matched your search

@@ -112,7 +112,9 @@ function listAccounts({ page = 1, pageSize = 20, search = '', track = '', type =
const offset = (Math.max(1, Number(page) || 1) - 1) * limit;
const followersExpr = `CASE WHEN h.followers LIKE '%亿%' THEN CAST(REPLACE(REPLACE(h.followers,'亿',''),'万','') AS REAL) * 100000000 WHEN h.followers LIKE '%万%' THEN CAST(REPLACE(h.followers,'万','') AS REAL) * 10000 ELSE CAST(h.followers AS REAL) END`;
const orderBySql = `h.favorite DESC, ${followersExpr} DESC, h.id ASC`;
const items = d.prepare(`SELECT h.*, (SELECT COUNT(*) FROM account_videos v WHERE v.account_id = h.id) AS video_count FROM hot_accounts h ${whereSql} ORDER BY ${orderBySql} LIMIT ? OFFSET ?`).all(...params, limit, offset);
const items = d.prepare(`SELECT h.*, (SELECT COUNT(*) FROM account_videos v WHERE v.account_id = h.id) AS video_count,
(SELECT COUNT(*) FROM rewrite_log r WHERE r.account_id = h.id AND r.status='done' AND r.script_text IS NOT NULL AND r.script_text <> '') AS rewrite_count
FROM hot_accounts h ${whereSql} ORDER BY ${orderBySql} LIMIT ? OFFSET ?`).all(...params, limit, offset);
return { total, page: Math.max(1, Number(page) || 1), pageSize: limit, items };
}
@@ -701,7 +701,7 @@ async function router() {
'accounts': () => window.DataPages.renderAccounts(view),
'account': () => window.DataPages.renderAccountDetail(view, param),
'video': () => window.DataPages.renderVideoDetail(view, param),
'rewrites': () => window.DataPages.renderRewrites(view),
'rewrites': () => window.DataPages.renderRewrites(view, param),
'reviews': () => window.DataPages.renderReviews(view),
};
if (pages[name]) {
@@ -569,9 +569,9 @@ async function renderAccounts(view) {
<td>${fmt(a.followers)}</td>
<td>${fmt(a.total_likes)}</td>
<td>${fmt(a.works_count)}</td>
<td>${esc(a.location || '-')}</td>
<td class="cell-content" title="${esc(a.bio || '')}">${esc((a.bio || '').slice(0, 50))}</td>
<td>${a.video_count ?? 0}</td>
<td>${a.rewrite_count > 0 ? `<a class="link" href="#/rewrites/${encodeURIComponent(a.account_name)}" title="查看该账号的 AI 脚本">${a.rewrite_count}</a>` : '—'}</td>
<td class="cell-act"><button class="btn btn-sm" data-create='${esc(a.account_name)}' data-acc-id="${a.id}">AI创作</button></td>
</tr>`).join('');
view.innerHTML = `
@@ -593,8 +593,8 @@ async function renderAccounts(view) {
</div>
<div class="table-wrap">
<table class="table">
<thead><tr>${state.batch ? '<th class="cb-cell"><input type="checkbox" class="batch-cb-all"></th>' : ''}<th>关注</th><th>类型</th><th>账号名</th><th>赛道</th><th>AI制作</th><th>粉丝</th><th>获赞</th><th>作品数</th><th>地区</th><th>简介</th><th>视频数</th><th class="th-act">操作</th></tr></thead>
<tbody>${rows || `<tr><td colspan="${state.batch ? 13 : 12}" class="empty">暂无账号数据</td></tr>`}</tbody>
<thead><tr>${state.batch ? '<th class="cb-cell"><input type="checkbox" class="batch-cb-all"></th>' : ''}<th>关注</th><th>类型</th><th>账号名</th><th>赛道</th><th>AI制作</th><th>粉丝</th><th>获赞</th><th>作品数</th><th>简介</th><th>视频数</th><th>AI脚本</th><th class="th-act">操作</th></tr></thead>
<tbody>${rows || `<tr><td colspan="${state.batch ? 12 : 11}" class="empty">暂无账号数据</td></tr>`}</tbody>
</table>
</div>
<div class="list-footer">
@@ -921,8 +921,8 @@ async function renderVideoDetail(view, id) {
}
/* ================= AI写脚本 ================= */
async function renderRewrites(view) {
let state = { search: '', parsed: '', days: '30', page: 1, pageSize: 20, batch: false };
async function renderRewrites(view, initAccount) { /* v22:initAccount=账号列表 AI脚本列跳转进入,预筛该账号 */
let state = { search: initAccount || '', parsed: '', days: '30', page: 1, pageSize: 20, batch: false };
async function load() {
const d = await api('/api/dsh/videos?search=' + encodeURIComponent(state.search) + '&parsed=' + state.parsed + '&days=' + state.days + '&page=' + state.page + '&pageSize=' + state.pageSize);
const rows = (d.items || []).map((v) => `<tr>
@@ -959,7 +959,7 @@ async function renderRewrites(view) {
</select>
</div>
</div>
<div class="toolbar-note">全部视频分页展示 · 关注账号优先 · 按发布时间倒序</div>
<div class="toolbar-note">${initAccount ? `正在查看账号「${esc(initAccount)}」的视频与 AI 脚本 · 视频行「AI脚本」列可打开脚本对比 · 行尾「AI创作」可为该账号继续创作` : '全部视频分页展示 · 关注账号优先 · 按发布时间倒序'}</div>
<div class="table-wrap"><table class="table">
<thead><tr>${state.batch ? '<th class="cb-cell"><input type="checkbox" class="batch-cb-all"></th>' : ''}<th>账号</th><th>视频标题</th><th>点赞</th><th>评论</th><th>分享</th><th>时长</th><th>发布时间</th><th>状态</th><th>AI脚本</th><th class="th-act">操作</th></tr></thead>
<tbody>${rows || `<tr><td colspan="${state.batch ? 11 : 10}" class="empty">暂无视频数据</td></tr>`}</tbody>