工作台账号详情tab调整:账号设定内联信息页,视频列表移入persona tab并改名

- info tab:移除视频列表表格,内联展示账号设定(空态/文字版/卡片+文字切换),小节标题「账号设定」
- persona tab:改为视频列表表格+分页/批量,tab 标签改名「视频列表」
- persona 加载改为 info tab 首屏并行加载(dvP/await 拆分),tab 点击处理器去冗余
This commit is contained in:
maogeigei committed 2026-09-02 10:51:40 +08:00
1 parent 00e649a2f2
commit 74c9bfdf98
2 files changed
+46 -30

No files matched your search

+10
View File
@@ -40,3 +40,13 @@
- 边界:mcn-dou-analysis 内部 `subskills/nuwa-skill-main` 为正常结构不动;dsh 副本 `~/.dsh/skills/mcn-dou-analysis/` 单向只读未动
- 残留检查:project/ 下全类型 grep `subskill/`(排除 subskills/)零命中;memory 历史日志为 append-only 不改写
- git:commit 11fe8d4(520 文件),push a255abd..11fe8d4 成功
## 账号详情页 tab 结构调整(16:25,用户要求)
- **需求原话**:「账号详情 下面的视频列表 改为账号设定内容,视频列表放到现在账号设定tab下,改名为视频列表」
- **修改**(data-pages.js renderAccountDetail):
- tab 定义:`persona` 标签「账号设定」→「视频列表」
- info tab(账号信息):移除视频列表表格,内联展示账号设定内容(空态/文字版/卡片+文字切换),小节标题「账号设定」
- persona tab:改为视频列表表格 + list-footer(批量/分页)
- 加载逻辑:persona 数据从「点击 persona tab 时才加载」改为「info tab 首屏即加载」(`if (tab==='info' && persona===null) await loadPersona()`,与视频数据并行 dvP/await 拆分);tab 点击处理器去掉冗余 persona 加载
- **验证**:bindPager/bindBatchBar 均用 querySelectorAll/空值守卫,容器缺元素不报错;data-rewrite(AI创作)点击时仍 `if (!persona) await loadPersona()` 兜底;data-extract 绑定全局查找在 info tab 同样生效
- 服务未重启(纯静态资源),重开页面 `?v=20260902#/account/1629`(旧梦留声机)验证
@@ -389,7 +389,9 @@ async function renderAccountDetail(view, id) {
}
async function load() {
const dv = await api('/api/dsh/account-videos?accountId=' + accountId + '&page=' + page + '&pageSize=20');
const dvP = api('/api/dsh/account-videos?accountId=' + accountId + '&page=' + page + '&pageSize=20');
if (tab === 'info' && persona === null) await loadPersona(); // 账号设定内联在信息页,首屏即加载(与视频数据并行)
const dv = await dvP;
const infoGrid = (label, val, wide, raw) => `<div class="info-item ${wide ? 'info-wide' : ''}"><div class="info-label">${label}</div><div class="info-value">${raw ? val : esc(fmt(val))}</div></div>`;
const rows = (dv.items || []).map((v) => `<tr>
${bstate.batch ? `<td class="cb-cell"><input type="checkbox" class="batch-cb" data-id="${v.id}"></td>` : ''}
@@ -402,7 +404,34 @@ async function renderAccountDetail(view, id) {
<td class="num">${fmtDuration(v.duration)}</td>
<td class="cell-act"><button class="btn btn-sm ${(v.has_source || v.has_analysis) ? 'btn-view' : ''}" data-rewrite='${esc(JSON.stringify({ id: v.id, name: acc.account_name, title: cleanTitle(v.video_title), aweme: v.aweme_id, url: v.video_url || '', parsed: !!(v.has_source || v.has_analysis) }))}'>AI创作</button></td>
</tr>`).join('');
const tabBtns = [['info', '账号信息'], ['persona', '账号设定'], ['analysis', '数据分析']].map(([k, label]) => `<button class="tab ${tab === k ? 'tab-active' : ''}" data-tab="${k}">${label}</button>`).join('');
const tabBtns = [['info', '账号信息'], ['persona', '视频列表'], ['analysis', '数据分析']].map(([k, label]) => `<button class="tab ${tab === k ? 'tab-active' : ''}" data-tab="${k}">${label}</button>`).join('');
// 账号设定内容渲染(info tab 内联展示;无设定=空态引导 / 无卡片=文字版 / 有卡片=卡片+文字切换)
const personaPanel = () => {
if (!persona) {
return `<div class="empty-state">
<div class="empty-icon">${svgIcon('users', 40)}</div>
<div class="empty-title">该账号暂无账号设定信息</div>
<div class="empty-desc">为达人提炼账号设定后,可基于设定生成脚本</div>
<button class="btn btn-view" data-extract>提炼账号设定</button>
</div>`;
}
if (!personaCard) {
// 无卡片:直接文字版(无切换控件)
return `<div class="md-body persona-text">${renderMarkdown(persona)}</div>`;
}
// 有卡片:右上角图标切换(卡片版 / 文字版),默认卡片版
return `
<div class="persona-wrap">
<div class="persona-vs-icons">
<button class="vi-btn ${viewMode === 'card' ? 'vi-active' : ''}" data-vs="card" title="卡片版">${svgIcon('image', 16)}</button>
<button class="vi-btn ${viewMode === 'text' ? 'vi-active' : ''}" data-vs="text" title="文字版">${svgIcon('file-text', 16)}</button>
</div>
<div class="card-view ${viewMode === 'card' ? '' : 'vs-hidden'}">
<img src="/api/file?path=${encodeURIComponent(personaCard.path)}" alt="${esc(acc.account_name)}账号设定卡">
</div>
<div class="md-body persona-text ${viewMode === 'text' ? '' : 'vs-hidden'}">${renderMarkdown(persona)}</div>
</div>`;
};
let panel = '';
if (tab === 'info') {
const contentText = String(acc.content || '');
@@ -414,37 +443,15 @@ async function renderAccountDetail(view, id) {
<div class="info-row">${infoGrid('简介', acc.bio, true)}</div>
<div class="info-row">${infoGrid('账号定位', contentHtml, true, true)}</div>
</div>
<h3 class="video-list-title">视频列表</h3>
<h3 class="video-list-title">账号设定</h3>
${personaPanel()}`;
} else if (tab === 'persona') {
panel = `<h3 class="video-list-title">视频列表</h3>
<div class="table-wrap"><table class="table"><thead><tr>${bstate.batch ? '<th class="cb-cell"><input type="checkbox" class="batch-cb-all"></th>' : ''}<th class="th-pub">发布时间</th><th class="th-title">视频标题</th><th class="num">点赞</th><th class="num">评论</th><th class="num">分享</th><th class="num">收藏</th><th class="num">时长</th><th class="th-act">操作</th></tr></thead><tbody>${rows || `<tr><td colspan="${bstate.batch ? 9 : 8}" class="empty">暂无视频数据</td></tr>`}</tbody></table></div>
<div class="list-footer">
${batchBarHtml(bstate, 0)}
${pagerHtml(dv.total, dv.page, 20, (p) => { page = p; load(); })}
</div>`;
} else if (tab === 'persona') {
if (!persona) {
panel = `<div class="empty-state">
<div class="empty-icon">${svgIcon('users', 40)}</div>
<div class="empty-title">该账号暂无账号设定信息</div>
<div class="empty-desc">为达人提炼账号设定后,可基于设定生成脚本</div>
<button class="btn btn-view" data-extract>提炼账号设定</button>
</div>`;
} else if (!personaCard) {
// 无卡片:直接文字版(无切换控件)
panel = `<div class="md-body persona-text">${renderMarkdown(persona)}</div>`;
} else {
// 有卡片:右上角图标切换(卡片版 / 文字版),默认卡片版
panel = `
<div class="persona-wrap">
<div class="persona-vs-icons">
<button class="vi-btn ${viewMode === 'card' ? 'vi-active' : ''}" data-vs="card" title="卡片版">${svgIcon('image', 16)}</button>
<button class="vi-btn ${viewMode === 'text' ? 'vi-active' : ''}" data-vs="text" title="文字版">${svgIcon('file-text', 16)}</button>
</div>
<div class="card-view ${viewMode === 'card' ? '' : 'vs-hidden'}">
<img src="/api/file?path=${encodeURIComponent(personaCard.path)}" alt="${esc(acc.account_name)}账号设定卡">
</div>
<div class="md-body persona-text ${viewMode === 'text' ? '' : 'vs-hidden'}">${renderMarkdown(persona)}</div>
</div>`;
}
} else {
panel = analysis ? `<div class="md-body">${renderMarkdown(analysis)}</div>` : `<div class="empty">该账号暂无数据分析</div>`;
}
@@ -457,9 +464,8 @@ async function renderAccountDetail(view, id) {
bindBack(view);
view.querySelectorAll('[data-tab]').forEach((b) => b.addEventListener('click', async () => {
tab = b.dataset.tab;
if (tab === 'persona' && persona === null) await loadPersona();
if (tab === 'analysis' && analysis === null) await loadAnalysis();
load();
load(); // info tab 的账号设定加载已在 load() 内处理
}));
bindPager(view, (p) => { page = p; load(); });
bindBatchBar(view, {