feat: 负责人下钻视图+项目负责人编辑管理+企微授权自助绑定
- 任务/项目负责人 union scope:任务中心分组视图、工作台项目进度卡、收录验证列 - 项目负责人可管理自己项目:编辑/删除项目、编辑任务、分配负责人、推送、项目内建任务;堵死转移归属/越权新建/任务迁移 - 只读依赖放开给已登录:inspect_feishu、wecom_list_internal_contacts - 企微 OAuth 自助绑定:/api/wecom-bind(state 签名校验+登录态一致性+归属冲突检查),未绑定 banner 增加入口 - 工作台项目进度卡与未绑定 banner 排版修复 - 修 user-auth 判空分支被 Turbopack dev 折叠删除导致匿名请求 500
This commit is contained in:
@@ -32,6 +32,11 @@ const reportRow = {
|
||||
latest_comments: 40,
|
||||
latest_collects: 60,
|
||||
latest_shares: 10,
|
||||
related_task_id: "",
|
||||
related_task_name: null,
|
||||
reverse_related_task_id: null,
|
||||
reverse_related_task_name: null,
|
||||
submitted_count: 0,
|
||||
};
|
||||
|
||||
test("buildTaskReportCsv writes BOM, headers and mapped rows", () => {
|
||||
@@ -71,6 +76,8 @@ test("buildTaskReportCsv writes BOM, headers and mapped rows", () => {
|
||||
"最新评论",
|
||||
"最新收藏",
|
||||
"最新转发",
|
||||
"关联任务",
|
||||
"截图提交数",
|
||||
].join(","),
|
||||
);
|
||||
assert.equal(
|
||||
@@ -105,6 +112,8 @@ test("buildTaskReportCsv writes BOM, headers and mapped rows", () => {
|
||||
40,
|
||||
60,
|
||||
10,
|
||||
"",
|
||||
"",
|
||||
].join(","),
|
||||
);
|
||||
});
|
||||
@@ -136,9 +145,26 @@ test("buildTaskReportCsv escapes commas and quotes, blanks null metrics", () =>
|
||||
const rowLine = csv.slice(1).split("\r\n")[1];
|
||||
assert.ok(rowLine.includes('"含,逗号""引号""任务"'));
|
||||
const cells = rowLine.split(",");
|
||||
assert.equal(cells.at(-1), "", "null latest_shares becomes empty");
|
||||
assert.equal(cells.at(-18), "", "no claims means empty completion rate");
|
||||
assert.equal(cells.at(-16), "2026-08-01 10:00:00");
|
||||
assert.equal(cells.at(-1), "", "content publish row leaves screenshot count empty");
|
||||
assert.equal(cells.at(-2), "", "no related task leaves empty");
|
||||
assert.equal(cells.at(-20), "", "no claims means empty completion rate");
|
||||
assert.equal(cells.at(-18), "2026-08-01 10:00:00");
|
||||
});
|
||||
|
||||
test("buildTaskReportCsv writes related batch and screenshot submission for collect tasks", () => {
|
||||
const csv = buildTaskReportCsv([
|
||||
{
|
||||
...reportRow,
|
||||
task_type: "screenshot_collect",
|
||||
related_task_id: "task-B",
|
||||
related_task_name: "夏日种草计划",
|
||||
submitted_count: 7,
|
||||
claimed_count: 12,
|
||||
},
|
||||
]);
|
||||
const cells = csv.slice(1).split("\r\n")[1].split(",");
|
||||
assert.equal(cells.at(-2), "夏日种草计划");
|
||||
assert.equal(cells.at(-1), "7");
|
||||
});
|
||||
|
||||
test("getTaskReportData aggregates per task via distributions join", async () => {
|
||||
@@ -161,4 +187,6 @@ test("getTaskReportData aggregates per task via distributions join", async () =>
|
||||
assert.match(capturedSql, /GROUP BY t\.id/);
|
||||
assert.match(capturedSql, /publish_url/);
|
||||
assert.match(capturedSql, /latest_shares/);
|
||||
assert.match(capturedSql, /related_task_id/);
|
||||
assert.match(capturedSql, /result_submitted_at/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user