From bd80b2d7d816f83abdf79faf74f3cb281538ec08 Mon Sep 17 00:00:00 2001 From: ABAPPLO <1134226402@qq.com> Date: Thu, 3 Sep 2026 11:30:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E8=B4=9F=E8=B4=A3?= =?UTF-8?q?=E4=BA=BA+=E5=86=85=E9=83=A8=E4=BB=BB=E5=8A=A1=E7=BE=A4+portal?= =?UTF-8?q?=20=E5=86=85=E9=83=A8=E8=BA=AB=E4=BB=BD=E9=A2=86=E5=8F=96+?= =?UTF-8?q?=E7=BE=A4=E4=B8=BB=E9=93=BE=E6=8E=A5=E5=BD=92=E5=B1=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 迁移 0012:projects.owner_userid / tasks.task_chat_id / claims.owner_partner_id - lib/task-group-service.ts:懒建 appchat 任务群(首个内部群主领取时创建,成员 diff 补员),播报/卡片文案 - wecom-client 新增 appchat create/update/get/send 封装 - OAuth ticket 增可选 uid(v:1 兼容),内部成员领取按 wecom_userid 解析群主身份 - 外部 OAuth 领取人 upsert 打 partner_type='group_owner' - portal 链接带 ?owner= 穿透 OAuth 往返,claims 记录归属群主 - 后台任务卡「群主链接」面板:复制链接/推送内部群主/任务群状态 - 催办与超期升级同步播报进任务群 --- app/admin-app.tsx | 223 +++++++++++++++- app/api/action/route.ts | 80 ++++++ app/api/partner/route.ts | 134 ++++++++-- app/api/wecom-oauth/route.ts | 12 +- db/schema.ts | 5 + koc-portal/app/page.tsx | 24 +- lib/project-service.ts | 19 +- lib/task-group-service.ts | 158 +++++++++++ lib/wecom-client.ts | 134 +++++++++- lib/wecom-notifier-service.ts | 35 +++ lib/wecom-oauth-service.ts | 21 +- mysql/0012_project_owner_task_chat.sql | 5 + tests/partner-wecom-claim.test.mjs | 71 +++++ tests/project-service.test.mjs | 14 +- tests/task-group-service.test.mjs | 352 +++++++++++++++++++++++++ tests/wecom-client.test.mjs | 176 +++++++++++++ tests/wecom-oauth-service.test.mjs | 42 +++ 17 files changed, 1466 insertions(+), 39 deletions(-) create mode 100644 lib/task-group-service.ts create mode 100644 mysql/0012_project_owner_task_chat.sql create mode 100644 tests/task-group-service.test.mjs diff --git a/app/admin-app.tsx b/app/admin-app.tsx index 5491764..0c47346 100644 --- a/app/admin-app.tsx +++ b/app/admin-app.tsx @@ -532,6 +532,7 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { const [taskModalOpen, setTaskModalOpen] = useState(false); const [groupPushTask, setGroupPushTask] = useState(null); const [onePushTask, setOnePushTask] = useState(null); + const [ownerLinksTask, setOwnerLinksTask] = useState(null); const [metricModal, setMetricModal] = useState(null); const [taskForm, setTaskForm] = useState({ taskType: "content_publish" as "content_publish" | "screenshot_collect", @@ -1175,6 +1176,7 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { onCopyShare={copyTaskShareLink} onPushToGroups={(task) => setGroupPushTask(task)} onOneClickPush={(task) => setOnePushTask(task)} + onOwnerLinks={(task) => setOwnerLinksTask(task)} onRelease={async (distribution) => runAction( { @@ -1515,6 +1517,14 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) { /> )} + {ownerLinksTask && ( + setOwnerLinksTask(null)} + setToast={setToast} + /> + )} + {toast &&
✓{toast}
} {working &&
}
@@ -2486,6 +2496,7 @@ type ProjectSummary = { note: string; createdAt: string; mainGroupMemberIds: string[]; + ownerUserid: string; taskCount: number; groupChatCount: number; }; @@ -2541,11 +2552,12 @@ type ProjectEditorDraft = { id: string; name: string; brand: string; + owner: string; members: string; note: string; }; -const EMPTY_PROJECT_DRAFT: ProjectEditorDraft = { id: "", name: "", brand: "", members: "", note: "" }; +const EMPTY_PROJECT_DRAFT: ProjectEditorDraft = { id: "", name: "", brand: "", owner: "", members: "", note: "" }; function ProjectSection({ project, @@ -2560,6 +2572,7 @@ function ProjectSection({ onCopyShare, onPushToGroups, onOneClickPush, + onOwnerLinks, }: { project: ProjectSummary; tasks: Task[]; @@ -2573,6 +2586,7 @@ function ProjectSection({ onCopyShare: (task: Task) => void; onPushToGroups: (task: Task) => void; onOneClickPush: (task: Task) => void; + onOwnerLinks: (task: Task) => void; }) { const [expanded, setExpanded] = useState(false); const [detail, setDetail] = useState(null); @@ -2711,6 +2725,7 @@ function ProjectSection({ onCopyShare={onCopyShare} onPushToGroups={onPushToGroups} onOneClickPush={onOneClickPush} + onOwnerLinks={onOwnerLinks} /> ))} @@ -2910,6 +2925,15 @@ function ProjectEditorModal({ /> +