feat: 任务领取/找回支持企微身份票据,领取自动绑定催办通道

This commit is contained in:
ABAPPLO
2026-08-31 17:13:03 +08:00
parent b83a6a53c9
commit 6e590e3b08
2 changed files with 109 additions and 18 deletions

View File

@@ -23,6 +23,11 @@ import {
} from "../../../lib/partner-utils";
import { extractPublishUrl } from "../../../lib/publish-url";
import { parseClaimantIdentifier } from "../../../lib/claimant-identifier";
import {
resolveWecomClaimant,
verifyWecomIdentityTicket,
type WecomIdentity,
} from "../../../lib/wecom-oauth-service";
import {
partnerOptions,
withPartnerCors,
@@ -39,6 +44,7 @@ type PartnerBody = {
delegationBundleId?: string;
claimantIdentifier?: string;
claimantName?: string;
identityTicket?: string;
quantity?: number;
publishUrl?: string;
exposure?: number | string;
@@ -446,13 +452,27 @@ async function handlePost(request: Request) {
}
const db = getRawDb();
let wecomIdentity: WecomIdentity | null = null;
if (body.identityTicket) {
try {
wecomIdentity = await verifyWecomIdentityTicket(
textValue(body.identityTicket, 512),
);
} catch {
wecomIdentity = null;
}
}
if (body.action === "recover") {
const identifierInput = textValue(
body.claimantIdentifier ?? body.claimantName,
64,
);
const claimantIdentifier = parseClaimantIdentifier(identifierInput);
if (!claimantIdentifier && identifierInput.length < 2) {
const wecomPartnerId = wecomIdentity
? (await resolveWecomClaimant(db, wecomIdentity.externalUserId)).partnerId
: null;
if (!claimantIdentifier && identifierInput.length < 2 && !wecomPartnerId) {
return Response.json(
{ error: "请输入领取时使用的正确微信号或手机号" },
{ status: 400 },
@@ -466,6 +486,11 @@ async function handlePost(request: Request) {
`claimant:${claimantIdentifier.canonical}`,
)}`
: legacyPartnerId;
const partnerCandidates = [
...new Set(
wecomPartnerId ? [wecomPartnerId] : [partnerId, legacyPartnerId],
),
];
const recovered = await db
.prepare(
`SELECT
@@ -481,12 +506,14 @@ async function handlePost(request: Request) {
FROM claims c
LEFT JOIN distributions d ON d.claim_id = c.id
LEFT JOIN contents co ON co.id = d.content_id
WHERE c.task_id = ? AND c.partner_id IN (?, ?)
WHERE c.task_id = ? AND c.partner_id IN (${partnerCandidates
.map(() => "?")
.join(", ")})
GROUP BY c.id, c.claim_token, c.quantity, c.created_at
ORDER BY c.created_at DESC, c.id DESC
LIMIT 20`,
)
.bind(task.task_type, task.task_type, task.id, partnerId, legacyPartnerId)
.bind(task.task_type, task.task_type, task.id, ...partnerCandidates)
.all<{
claim_token: string;
quantity: number;
@@ -522,7 +549,7 @@ async function handlePost(request: Request) {
);
const claimantIdentifier = parseClaimantIdentifier(identifierInput);
const quantity = quantityValue(body.quantity);
if (!claimantIdentifier) {
if (!claimantIdentifier && !wecomIdentity) {
return Response.json(
{ error: "请输入正确的微信号或手机号" },
{ status: 400 },
@@ -540,23 +567,45 @@ async function handlePost(request: Request) {
if (available.results.length === 0) {
return Response.json({ error: "当前任务已领完" }, { status: 409 });
}
const partnerId = `partner-ext-${hashText(
`claimant:${claimantIdentifier.canonical}`,
)}`;
const claimantName = claimantIdentifier.display;
const partnerId = wecomIdentity
? (await resolveWecomClaimant(db, wecomIdentity.externalUserId)).partnerId
: `partner-ext-${hashText(
`claimant:${claimantIdentifier?.canonical}`,
)}`;
const claimantName = wecomIdentity
? wecomIdentity.displayName
: (claimantIdentifier?.display ?? "");
const claimId = uid("claim");
const claimToken = crypto.randomUUID().replaceAll("-", "");
const statements: DatabaseStatement[] = [
db
.prepare(
`INSERT INTO partners
(id, name, wecom_name, owner, claimed_total, completed_total)
VALUES (?, ?, ?, '外部KOC', 0, 0)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
wecom_name = excluded.wecom_name`,
)
.bind(partnerId, claimantName, claimantName),
wecomIdentity
? db
.prepare(
`INSERT INTO partners
(id, name, wecom_name, owner, claimed_total, completed_total,
wecom_external_user_id)
VALUES (?, ?, ?, '外部KOC', 0, 0, ?)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
wecom_name = excluded.wecom_name,
wecom_external_user_id = excluded.wecom_external_user_id`,
)
.bind(
partnerId,
claimantName,
claimantName,
wecomIdentity.externalUserId,
)
: db
.prepare(
`INSERT INTO partners
(id, name, wecom_name, owner, claimed_total, completed_total)
VALUES (?, ?, ?, '外部KOC', 0, 0)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
wecom_name = excluded.wecom_name`,
)
.bind(partnerId, claimantName, claimantName),
db
.prepare(
`INSERT INTO claims