KOC 详情弹窗(合作方/数据回收/工作台三处入口): - 新增 KocDetailModal:基本信息 / 绑定KOC账号画像 / 参与任务记录 / 履约漏斗 - 工作台最近分发、回收队列账号名、截图回收合作方名、合作方页名称、分发详情头部合作方均可点开 - 分发表行点击仍打开分发详情(stopPropagation 隔离) 任务中心单入口改版(对齐"单任务双阶段"模型): - 任务卡发布/回收面板整块可点,全卡仅保留一个「查看明细」,回收面板重复按钮移除 - 详情页自述身份:动态 label(任务详情·分发与回收一体/仅分发)+ 阶段徽章(含回收·截止/未开通回收) - 内容分发表新增阶段筛选 chips(全部/待发布/已发布待数据/待收截图,未开通回收不显示截图项),筛选落空给专用空态文案 - 数据回收页入口文案改为「选择一个任务进入回收队列」,全站不再区分发布/回收两种任务类型 资源池 KOC 默认加入合作方 + 采集兜底: - partners 新增 released_account_id(mysql/0023):显式解绑/被顶替的账号不再被默认合作方同步回填 - 任务未设置采集计划时,默认按发布时间起连续采集 7 天,等待文案显示「等待D1 · 默认7天」
69 lines
3.1 KiB
JavaScript
69 lines
3.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import test from "node:test";
|
|
|
|
// 2026-10-08 两端走查发现的 UI 断点修复:
|
|
// 1) 回填提交在缺发布截图时前置禁用并说明原因(原本只在提交后 toast 报错)
|
|
// 2) 未回填链接时收起回收区块的说明/示例图,只留锁定提示
|
|
// 3) 分发表「数据状态」按任务采集计划显示等待日,没计划时明说待设置
|
|
// 4) 截图包回收清单的序号列对无 source_row 的内容回退为行号;种子内容补 source_row
|
|
|
|
test("portal gates the backfill submit button on the publish screenshot", async () => {
|
|
const source = await readFile(
|
|
new URL("../koc-portal/app/page.tsx", import.meta.url),
|
|
"utf8",
|
|
);
|
|
assert.match(
|
|
source,
|
|
/disabled=\{working \|\| !\(screenshot \|\| selected\.publish_screenshot_key\)\}/,
|
|
);
|
|
assert.match(source, /先上传发布截图,链接回填需以截图为凭证/);
|
|
// 服务端/提交守卫仍保留,双保险
|
|
assert.match(source, /请上传这篇笔记的发布截图/);
|
|
});
|
|
|
|
test("portal collapses recovery instructions until the link is backfilled", async () => {
|
|
const source = await readFile(
|
|
new URL("../koc-portal/app/page.tsx", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const lockedHint = "回填发布链接后,这里会开放回收截图上传。";
|
|
assert.ok(source.includes(lockedHint), "锁定提示必须保留");
|
|
const tipIndex = source.indexOf(
|
|
`{selected.publish_url && (\n <p className="creator-recovery-tip">`,
|
|
);
|
|
assert.ok(tipIndex > 0, "回收说明必须由 publish_url 门控");
|
|
// 示例图区块同样门控
|
|
assert.match(
|
|
source,
|
|
/\{selected\.publish_url &&\n \(payload\.task\.recoveryExampleImages\?\.length \?\? 0\) > 0 && \(/,
|
|
);
|
|
});
|
|
|
|
test("admin waiting label follows the task collection plan", async () => {
|
|
const [adminApp, mvpDb] = await Promise.all([
|
|
readFile(new URL("../app/admin-app.tsx", import.meta.url), "utf8"),
|
|
readFile(new URL("../lib/mvp-db.ts", import.meta.url), "utf8"),
|
|
]);
|
|
assert.match(adminApp, /waitingCollectionLabel/);
|
|
// 未设置计划时走默认 7 天兜底,等待文案随之说明而不是停在“待设置”
|
|
assert.match(adminApp, /等待D1 · 默认7天/);
|
|
assert.match(adminApp, /等待D\$\{Math\.min\(\.\.\.days\)\}/);
|
|
assert.doesNotMatch(adminApp, /"等待D2"/);
|
|
// 分发查询带上任务级采集计划字段
|
|
assert.match(mvpDb, /t\.collection_days AS task_collection_days/);
|
|
assert.match(mvpDb, /t\.collection_start_date AS task_collection_start_date/);
|
|
});
|
|
|
|
test("export manifest and seed contents always carry a sequence number", async () => {
|
|
const [exportRoute, seed] = await Promise.all([
|
|
readFile(
|
|
new URL("../app/api/screenshot-task-export/route.ts", import.meta.url),
|
|
"utf8",
|
|
),
|
|
readFile(new URL("../lib/mvp-db.ts", import.meta.url), "utf8"),
|
|
]);
|
|
assert.match(exportRoute, /String\(row\.source_row \?\? rowIndex \+ 1\)/);
|
|
assert.match(seed, /INSERT INTO contents \(id, task_id, title, body, status, source_row\)/);
|
|
});
|