feat: 采集失败KOC补交截图闭环 + 任务中心分发详情弹窗

公开数据补交闭环(F1):
- distributions 新增 public_metrics_screenshot_key(mysql/0022 迁移)
- KOC 门户:链接已回填但采集失败时展示补交数据截图入口(kind=public-metrics)
- 运营端:回收队列"核对补录"支持公开互动数据(赞/藏/评),按补交截图补录后采集状态置成功
- 企微催办:采集失败纳入待办(公开数据待补交)
- task-result-image 支持 kind=publish 输出发布截图

门户文案(F2):
- 自动采集数据明确"由系统每天自动采集,无需你填写",仅识别失败时才手动填写曝光/阅读

任务中心分发详情:
- 任务中心/数据回收的分发表行可点击,弹窗查看详情
- 详情按任务类型适配:发布阶段/数据回收(自动采集)/创作者数据(第7天)/截图回收四区块三段式布局
This commit is contained in:
ABAPPLO
2026-10-09 17:02:46 +08:00
parent c686003cfb
commit c11afd5f99
15 changed files with 1250 additions and 67 deletions

View File

@@ -0,0 +1,56 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
// 任务中心优化(2026-10-09):内容分发表的行可点击查看分发详情;
// 详情弹窗按单任务双阶段自适应(发布 / 数据回收 / 创作者数据 / 截图回收)。
test("distribution rows open a detail modal from both task center and recovery queue", async () => {
const [adminApp, globalCss, resultImageRoute] = await Promise.all([
readFile(new URL("../app/admin-app.tsx", import.meta.url), "utf8"),
readFile(new URL("../app/globals.css", import.meta.url), "utf8"),
readFile(new URL("../app/api/task-result-image/route.ts", import.meta.url), "utf8"),
]);
// 弹窗组件 + 两处入口(分发明细表 / 回收队列表)行可点击
assert.match(adminApp, /function DistributionDetailModal/);
assert.match(adminApp, /const \[detailDistributionId, setDetailDistributionId\]/);
assert.match(adminApp, /title=\{onOpenDetail \? "点击查看分发详情" : undefined\}/);
assert.match(adminApp, /className=\{onOpenDetail \? "clickable" : ""\}/);
assert.match(adminApp, /className="clickable"\s*\n\s*onClick=\{\(\) => onOpenDetail\(item\)\}/);
// 行内操作(释放/立即采集/核对补录)不冒泡误开详情
assert.match(adminApp, /<td onClick=\{\(event\) => event\.stopPropagation\(\)\}>/);
assert.match(globalCss, /\.data-table tbody tr\.clickable\s*\{/);
// 详情数据实时刷新:任何操作重拉数据后弹窗按 id 重新取行
assert.match(adminApp, /data\.distributions\.find\(\(item\) => item\.id === detailDistributionId\)/);
// 发布截图:管理端通过 task-result-image?kind=publish 核对发布凭证
assert.match(resultImageRoute, /get\("kind"\) === "publish" \? "publish" : "result"/);
assert.match(resultImageRoute, /publish_screenshot_key/);
assert.match(adminApp, /kind=publish/);
assert.match(adminApp, /function PublishEvidencePreview/);
});
test("detail modal sections adapt to the dual-phase task model", async () => {
const adminApp = await readFile(
new URL("../app/admin-app.tsx", import.meta.url),
"utf8",
);
// 四个区块按阶段组织;未开通回收的任务不展示截图回收区块
assert.match(adminApp, /① 发布阶段/);
assert.match(adminApp, /② 数据回收(自动采集)/);
assert.match(adminApp, /③ 创作者数据(第7天)/);
assert.match(adminApp, /④ 截图回收/);
assert.match(adminApp, /recoveryEnabled && \(\s*<section className="detail-section">/);
// 抖音任务多展示转发,口径与回收队列一致
assert.match(adminApp, /item\.task_platform === "抖音" && \(\s*<div className="detail-metric">\s*<span>转发<\/span>/);
// 详情内集成兜底闭环:补交截图直达 + 核对补录入口
assert.match(adminApp, /KOC补交截图 ↗/);
assert.match(adminApp, /核对补录/);
// 详情内可执行的动作:更新/填写链接、立即采集、手动填写、释放(带确认)
assert.match(adminApp, /更新链接" : "填写链接"/);
assert.match(adminApp, /确认释放“\$\{distribution\.content_title\}”/);
// 采集计划随详情展示
assert.match(adminApp, /起 D\$\{collectionDays\.join\("\/D"\)\}/);
});