feat: 新增项目中心——按项目组织任务/任务群/总群并一键推送

- 新表 projects / project_group_chats,partners 加 partner_type/wecom_userid,tasks 加 project_id(迁移 0010)
- 项目 CRUD、总群成员配置、任务群人工映射(群主→合作方)、任务挂项目
- 推送:总群成员逐人应用消息 + 任务群按群主企业群发,结果分项回显
This commit is contained in:
ABAPPLO
2026-08-31 16:35:17 +08:00
parent ed13262166
commit a6f5a5fd4a
11 changed files with 2557 additions and 15 deletions

View File

@@ -58,6 +58,17 @@ import {
getAccountFieldRefreshStatus,
startAccountFieldRefresh,
} from "../../../lib/account-field-refresh-service";
import {
deleteProject,
getProjectDetail,
listGroupOwnerPartners,
listProjects,
ProjectError,
saveGroupOwnerPartner,
saveProject,
setProjectGroupChats,
} from "../../../lib/project-service";
import { pushProjectTask } from "../../../lib/project-push-service";
type ActionBody = {
action?: string;
@@ -119,6 +130,7 @@ export async function POST(request: Request) {
dueAt,
platform,
contentFormat,
projectId: String(body.projectId ?? "").trim(),
},
env as unknown as FeishuBindings,
);
@@ -131,6 +143,7 @@ export async function POST(request: Request) {
instructions: String(body.instructions ?? "").trim(),
quantity: numberValue(body.quantity),
exampleImageKey: String(body.exampleImageKey ?? "").trim(),
projectId: String(body.projectId ?? "").trim(),
});
} else if (body.action === "claim") {
const partnerId = String(body.partnerId ?? "");
@@ -687,6 +700,59 @@ export async function POST(request: Request) {
const taskId = String(body.taskId ?? "").trim();
const pushes = await listGroupPushes(db, taskId || undefined);
return Response.json({ pushes });
} else if (body.action === "project_list") {
return Response.json({ projects: await listProjects(db) });
} else if (body.action === "project_detail") {
return Response.json(await getProjectDetail(db, String(body.projectId ?? "")));
} else if (body.action === "project_save") {
return Response.json({
project: await saveProject(db, {
id: body.id,
name: body.name,
brand: body.brand,
mainGroupMemberIds: body.mainGroupMemberIds,
note: body.note,
}),
});
} else if (body.action === "project_delete") {
await deleteProject(db, String(body.projectId ?? ""));
return Response.json({ ok: true });
} else if (body.action === "project_set_group_chats") {
const detail = await setProjectGroupChats(
db,
String(body.projectId ?? ""),
Array.isArray(body.items) ? body.items : [],
);
return Response.json(detail);
} else if (body.action === "partner_save") {
return Response.json({
partner: await saveGroupOwnerPartner(db, {
id: body.id,
name: body.name,
wecomUserid: body.wecomUserid,
}),
});
} else if (body.action === "partner_group_owners") {
return Response.json({ partners: await listGroupOwnerPartners(db) });
} else if (body.action === "project_push_task") {
const wecomConfig = resolveWecomConfig(env as unknown as WecomBindings);
const outcome = await pushProjectTask(
db,
{
taskId: body.taskId,
sendMainGroup: body.sendMainGroup,
sendGroupChats: body.sendGroupChats,
text: body.text,
},
wecomConfig,
);
const appFailed = outcome.appResults.filter((item) => !item.ok);
return Response.json({
...outcome,
appSent: outcome.appResults.length - appFailed.length,
appFailedCount: appFailed.length,
hint: "任务群走企业群发,群主需在企微客户端「群发助手」点击发送后,消息才会送达客户群",
});
} else if (body.action === "refresh_account_fields") {
const status = startAccountFieldRefresh(
db,
@@ -711,7 +777,8 @@ export async function POST(request: Request) {
status:
error instanceof FeishuSourceError ||
error instanceof DistributionReleaseError ||
error instanceof WecomClientError
error instanceof WecomClientError ||
error instanceof ProjectError
? error.status
: 500,
},