diff --git a/app/admin-app.tsx b/app/admin-app.tsx index 87f000d..7c6332b 100644 --- a/app/admin-app.tsx +++ b/app/admin-app.tsx @@ -59,6 +59,17 @@ type Task = { join_qr_code?: string; keyword?: string; instructions?: string; + related_task_id?: string; + related_task_name?: string | null; + related_dist_total?: number; + related_dist_complete?: number; + reverse_related_task_id?: string | null; + reverse_related_task_name?: string | null; + reverse_dist_total?: number; + reverse_dist_submitted?: number; + dist_total?: number; + dist_complete?: number; + dist_submitted?: number; source_url: string; source_sheet_id: string; source_sheet_name: string; @@ -169,6 +180,8 @@ type Distribution = { last_collection_day: number | null; updated_at: string; content_title: string; + related_content_id?: string; + related_content_title?: string | null; partner_name: string; claimant_name: string | null; account_nickname: string | null; @@ -314,6 +327,7 @@ function statusLabel(status: string) { collecting: "采集中", complete: "已完成", active: "分发中", + completed: "已完结", closed: "已结束", }; return labels[status] || status; @@ -540,6 +554,7 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { brand: "", dueAt: "2026-08-12", feishuUrl: "", + relatedTaskId: "", keyword: "", instructions: "在小红书搜索指定关键词,打开 AI 总结并上传完整截图。", quantity: 1, @@ -656,19 +671,34 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { (latestPublicMetrics(item).likes === null || !hasCreatorMetrics(item)), ).length; + const screenshotPending = data.distributions.filter( + (item) => + item.task_type === "screenshot_collect" && !item.result_submitted_at, + ).length; + const pairedTotals = data.tasks.reduce( + (acc, task) => { + if (!task.reverse_related_task_id) return acc; + return { + submitted: acc.submitted + (task.reverse_dist_submitted ?? 0), + total: acc.total + (task.reverse_dist_total ?? 0), + }; + }, + { submitted: 0, total: 0 }, + ); return { resources: data.accounts.length, activeTasks: data.tasks.filter((task) => task.status === "active").length, published, completed, pendingRecovery, + completedTasks: data.tasks.filter((task) => task.status === "completed") + .length, + screenshotPending, + pairedSubmitted: pairedTotals.submitted, + pairedTotal: pairedTotals.total, }; }, [data]); - const recentDistributions = data.distributions - .filter((item) => item.task_type !== "screenshot_collect") - .slice(0, 6); - const navigate = (key: NavKey) => { if ( currentUser.role === "user" && @@ -684,6 +714,10 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { const submitTask = async (event: FormEvent) => { event.preventDefault(); const editing = Boolean(taskForm.id); + if (!editing && !isManager && !taskForm.projectId.trim()) { + setToast("请选择所属项目"); + return; + } if (!editing && taskForm.taskType === "content_publish" && !sourcePreview) { setToast("请先读取飞书表格"); return; @@ -735,6 +769,18 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { quantity: taskForm.quantity, exampleImageKey, }; + const relatedSourceTask = data.tasks.find( + (task) => task.id === taskForm.relatedTaskId, + ); + const createScreenshotFields = { + name: taskForm.name, + relatedTaskId: taskForm.relatedTaskId, + dueAt: taskForm.dueAt, + instructions: taskForm.instructions, + exampleImageKey, + projectId: taskForm.projectId, + ownerUserid: taskForm.ownerUserid, + }; const publishFields = { ...sharedFields, platform: taskForm.platform, @@ -754,10 +800,10 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { ) : await runAction( taskForm.taskType === "screenshot_collect" - ? { action: "create_screenshot_task", ...screenshotFields } + ? { action: "create_screenshot_task", ...createScreenshotFields } : { action: "create_task", ...publishFields }, taskForm.taskType === "screenshot_collect" - ? `截图回收任务已创建,${taskForm.quantity} 份任务进入可领取池` + ? `截图回收任务已创建,${relatedSourceTask?.quantity ?? 0} 份任务(与「${relatedSourceTask?.name ?? "分发任务"}」的笔记一一对应)进入可领取池` : `任务已创建,${sourcePreview?.rowCount ?? 0} 篇内容进入可领取池`, ); if (success) { @@ -773,6 +819,7 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { brand: "", dueAt: "2026-08-12", feishuUrl: "", + relatedTaskId: "", keyword: "", instructions: "在小红书搜索指定关键词,打开 AI 总结并上传完整截图。", quantity: 1, @@ -1225,14 +1272,15 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) {

账号尚未绑定企业微信

-

绑定任务负责人的企微 userid 后,这里会展示您负责的任务进度、领取明细与数据回收情况。请联系管理员在「用户管理」中绑定。

+

绑定任务负责人的企微后,这里会展示您负责的任务进度、领取明细与数据回收情况。点击右侧按钮用企业微信授权绑定(需在应用可见范围内),或联系管理员在「用户管理」中绑定。

+ 企业微信授权绑定
)} {activeNav === "overview" && (

- {taskForm.id ? "任务创建后仍可调整基础信息" : "任务类型明确,回收链路独立"} + {taskForm.id ? "任务创建后仍可调整基础信息" : "分发与回收一一对应,状态自动闭环"}

{taskForm.id ? "编辑任务" : "新建任务"}

@@ -1472,28 +1522,90 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { ) : (
-
- - -
+ {!taskForm.id ? ( + <> + + {(() => { + const related = data.tasks.find( + (task) => task.id === taskForm.relatedTaskId, + ); + return related ? ( +

+ 将为「{related.name}」生成 {related.quantity} 份回收任务 +

+ ) : null; + })()} + + ) : taskForm.relatedTaskId ? ( +
+ + +
+ ) : ( +
+ + +
+ )}