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:
56
tests/distribution-detail.test.mjs
Normal file
56
tests/distribution-detail.test.mjs
Normal 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"\)\}/);
|
||||
});
|
||||
101
tests/public-metrics-fallback.test.mjs
Normal file
101
tests/public-metrics-fallback.test.mjs
Normal file
@@ -0,0 +1,101 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
|
||||
// 公开数据采集失败兜底闭环(2026-10-09):
|
||||
// 自动采集优先 → 采集失败时催 KOC 补交数据截图 → 运营按截图核对补录互动数据。
|
||||
// 同时修正门户创作者数据区块的表述:公开数据系统自动采集,KOC 不需要每天手动填。
|
||||
|
||||
test("koc can submit a public-metrics screenshot when auto collection fails", async () => {
|
||||
const [uploadRoute, imageRoute, partnerRoute, page, schema, migration] =
|
||||
await Promise.all([
|
||||
readFile(new URL("../app/api/partner-upload/route.ts", import.meta.url), "utf8"),
|
||||
readFile(new URL("../app/api/partner-image/route.ts", import.meta.url), "utf8"),
|
||||
readFile(new URL("../app/api/partner/route.ts", import.meta.url), "utf8"),
|
||||
readFile(new URL("../koc-portal/app/page.tsx", import.meta.url), "utf8"),
|
||||
readFile(new URL("../db/schema.ts", import.meta.url), "utf8"),
|
||||
readFile(new URL("../mysql/0022_public_metrics_screenshot.sql", import.meta.url), "utf8"),
|
||||
]);
|
||||
|
||||
assert.match(migration, /ALTER TABLE distributions ADD COLUMN public_metrics_screenshot_key TEXT/);
|
||||
assert.match(schema, /publicMetricsScreenshotKey/);
|
||||
|
||||
// 上传通道:仅发布后可补交,落 public-metrics/ 目录并标记待核对
|
||||
assert.match(uploadRoute, /"public-metrics"/);
|
||||
assert.match(uploadRoute, /\(isCreatorCenter \|\| isPublicMetrics\) && !assignment\.publish_url/);
|
||||
assert.match(uploadRoute, /public-metrics\/\$\{upload\.distributionId\}/);
|
||||
assert.match(uploadRoute, /public_metrics_screenshot_key = \?/);
|
||||
assert.match(uploadRoute, /KOC已补交数据截图,待运营核对/);
|
||||
|
||||
// 领取载荷:门户能感知采集状态、已采集到的公开数据与补交截图
|
||||
assert.match(partnerRoute, /d\.collection_status,/);
|
||||
assert.match(partnerRoute, /d\.latest_likes,/);
|
||||
assert.match(partnerRoute, /d\.public_metrics_screenshot_key,/);
|
||||
|
||||
// 图片服务:KOC 可查看自己补交的数据截图(可变凭证不缓存)
|
||||
assert.match(imageRoute, /imageKind === "public-metrics"/);
|
||||
assert.match(imageRoute, /d\.public_metrics_screenshot_key/);
|
||||
assert.match(imageRoute, /imageKind === "public-metrics"/);
|
||||
|
||||
// 门户:仅采集失败且已发布时展示补交入口
|
||||
assert.match(page, /collection_status === "failed"/);
|
||||
assert.match(page, /"public-metrics"/);
|
||||
assert.match(page, /submitPublicMetricsShot/);
|
||||
assert.match(page, /自动采集失败,请补交数据截图/);
|
||||
assert.match(page, /运营核对后会补录数据/);
|
||||
});
|
||||
|
||||
test("creator data section reads as one-time d7 step, not a daily manual form", async () => {
|
||||
const [page, styles] = await Promise.all([
|
||||
readFile(new URL("../koc-portal/app/page.tsx", import.meta.url), "utf8"),
|
||||
readFile(new URL("../koc-portal/app/globals.css", import.meta.url), "utf8"),
|
||||
]);
|
||||
// 自动采集状态行:有数据时直接展示最近采到的赞藏评
|
||||
assert.match(page, /auto-collect-line/);
|
||||
assert.match(page, /公开数据系统自动采集中/);
|
||||
assert.match(page, /由系统每天自动采集,无需你填写/);
|
||||
// 一次性表述 + 仅识别失败才手动填
|
||||
assert.match(page, /这一步只需做一次/);
|
||||
assert.match(page, /仅当识别失败时才需要手动填写这两个数字/);
|
||||
assert.match(page, /只有识别失败时才需要手动修改/);
|
||||
assert.match(styles, /\.auto-collect-line/);
|
||||
assert.match(styles, /\.metrics-fallback/);
|
||||
});
|
||||
|
||||
test("admin reviews the fallback screenshot and records engagement metrics", async () => {
|
||||
const [actionRoute, adminApp, creatorRoute] = await Promise.all([
|
||||
readFile(new URL("../app/api/action/route.ts", import.meta.url), "utf8"),
|
||||
readFile(new URL("../app/admin-app.tsx", import.meta.url), "utf8"),
|
||||
readFile(new URL("../app/api/creator-screenshot/route.ts", import.meta.url), "utf8"),
|
||||
]);
|
||||
|
||||
// manual_metrics:曝光/阅读可留空;补录互动数据并把采集状态置成功
|
||||
assert.match(actionRoute, /publicLikes/);
|
||||
assert.match(actionRoute, /latest_likes = CASE WHEN \? THEN \? ELSE latest_likes END/);
|
||||
assert.match(actionRoute, /collection_status = CASE WHEN \? THEN 'success' ELSE collection_status END/);
|
||||
assert.match(actionRoute, /运营已按补交截图核对补录/);
|
||||
|
||||
// 后台:采集失败行出现「核对补录」入口,状态列可直达补交截图
|
||||
assert.match(adminApp, /核对补录/);
|
||||
assert.match(adminApp, /KOC补交截图/);
|
||||
assert.match(adminApp, /kind=public-metrics/);
|
||||
assert.match(adminApp, /请至少填写创作者数据或公开互动数据中的一项/);
|
||||
|
||||
// 截图服务:kind=public-metrics 仅管理端可读
|
||||
assert.match(creatorRoute, /"public-metrics"/);
|
||||
assert.match(creatorRoute, /public_metrics_screenshot_key/);
|
||||
});
|
||||
|
||||
test("due-soon reminders include failed collections as a metrics phase", async () => {
|
||||
const [notifier, adminApp] = await Promise.all([
|
||||
readFile(new URL("../lib/wecom-notifier-service.ts", import.meta.url), "utf8"),
|
||||
readFile(new URL("../app/admin-app.tsx", import.meta.url), "utf8"),
|
||||
]);
|
||||
// 催办查询纳入采集失败(不限日期),文案区分「公开数据待补交」
|
||||
assert.match(notifier, /WHEN d\.collection_status = 'failed' THEN 'metrics'/);
|
||||
assert.match(notifier, /AND d\.collection_status = 'failed'\)/);
|
||||
assert.match(notifier, /公开数据待补交/);
|
||||
// 回收队列的「催办未完成」计数与催办口径对齐(含采集失败行)
|
||||
assert.match(adminApp, /\(recoveryEnabled \? recoveryPending : 0\) \+/);
|
||||
assert.match(adminApp, /\+\s*failedCollectionCount/);
|
||||
});
|
||||
Reference in New Issue
Block a user