修复feifei领取链接直返

This commit is contained in:
yml2213
2026-07-07 15:46:08 +08:00
parent 177f72dd2c
commit affba7e924
4 changed files with 72 additions and 35 deletions
@@ -0,0 +1,27 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { resolveKuaishouFeifeiClaimUrl } from './index.js'
test('resolveKuaishouFeifeiClaimUrl prefers feifei h5 url over local claim url', () => {
assert.equal(
resolveKuaishouFeifeiClaimUrl({
claimUrl: 'https://ks.khhao.com/#/claim/local-token',
h5: {
entryUrl: 'https://feifei.example.com/h5/exchange',
rechargeUrl: 'https://feifei.example.com/h5/bind?code=abc',
},
}),
'https://feifei.example.com/h5/bind?code=abc',
)
})
test('resolveKuaishouFeifeiClaimUrl does not expose local claim token fallback', () => {
assert.equal(
resolveKuaishouFeifeiClaimUrl({
claimUrl: 'local-token',
h5: {},
}),
'',
)
})
@@ -4,7 +4,6 @@ import { createHttpError } from '../../../utils/http.js'
import { parseTaskContext } from '../../../utils/task-json.js'
import { nowIso } from '../../../utils/time.js'
import { TASK_STATUS } from '../../../domain/task-status.js'
import { buildClaimUrl, createTaskClaimToken } from '../../claim/claim-service.js'
import {
createKuaishouFeifeiOrder,
queryKuaishouFeifeiOrder,
@@ -29,20 +28,18 @@ export async function prepareKuaishouFeifeiTask(task: TaskRow) {
const now = nowIso()
const taskContext = parseTaskContext(task)
const flow = normalizeKuaishouFeifeiFlow(taskContext.kuaishouFeifei)
const claimLinkState = await ensureTaskClaimLink(task)
if (flow.orderNo && flow.h5.rechargeUrl) {
const existingClaimUrl = resolveKuaishouFeifeiClaimUrl(flow)
if (flow.orderNo && existingClaimUrl) {
const nextContext = {
...taskContext,
kuaishouFeifei: {
...flow,
claimUrl: claimLinkState.claimUrl,
claimUrl: existingClaimUrl,
},
}
return updateTask(task.id, {
task_status: TASK_STATUS.LINK_GENERATED,
claim_token: claimLinkState.token || task.claim_token || '',
claim_expires_at: claimLinkState.expiredAt || task.claim_expires_at || null,
user_action_status: 'pending_claim',
context_json: JSON.stringify(nextContext),
updated_at: now,
@@ -62,15 +59,21 @@ export async function prepareKuaishouFeifeiTask(task: TaskRow) {
productCode: flow.productCode,
platformBuyNum: 1,
})
const feifeiClaimUrl = resolveKuaishouFeifeiOrderClaimUrl(order)
if (!feifeiClaimUrl) {
throw createHttpError('kuaishou-feifei 未返回领取链接', {
statusCode: 502,
errorCode: 'kuaishou_feifei_missing_claim_url',
})
}
const nextFlow = mergeKuaishouFeifeiOrder(flow, order, {
platformOrderNo,
claimUrl: claimLinkState.claimUrl,
claimUrl: feifeiClaimUrl,
syncedAt: now,
})
const updatedTask = await updateTask(task.id, {
task_status: TASK_STATUS.LINK_GENERATED,
claim_token: claimLinkState.token || task.claim_token || '',
claim_expires_at: claimLinkState.expiredAt || task.claim_expires_at || null,
user_action_status: 'pending_claim',
result_code: 'kuaishou_feifei_order_created',
result_message: order.rechargeStatusLabel || 'kuaishou-feifei 订单已创建',
@@ -122,7 +125,7 @@ export async function syncKuaishouFeifeiTaskStatus(task: TaskRow) {
let lastError = task.last_error
const nextFlow = mergeKuaishouFeifeiOrder(flow, order, {
syncedAt: now,
claimUrl: flow.claimUrl,
claimUrl: resolveKuaishouFeifeiOrderClaimUrl(order) || resolveKuaishouFeifeiClaimUrl(flow),
})
if (order.rechargeStatus === 30) {
@@ -197,6 +200,16 @@ export function normalizeKuaishouFeifeiFlow(value: unknown) {
}
}
export function resolveKuaishouFeifeiClaimUrl(value: unknown) {
const flow = normalizeKuaishouFeifeiFlow(value)
const h5ClaimUrl = flow.h5.rechargeUrl || flow.h5.entryUrl
if (h5ClaimUrl) {
return h5ClaimUrl
}
return isLocalClaimUrl(flow.claimUrl) ? '' : flow.claimUrl
}
function mergeKuaishouFeifeiOrder(
flow: ReturnType<typeof normalizeKuaishouFeifeiFlow>,
order: Awaited<ReturnType<typeof createKuaishouFeifeiOrder>>,
@@ -225,25 +238,13 @@ function mergeKuaishouFeifeiOrder(
}
}
async function ensureTaskClaimLink(task: TaskRow) {
const tokenStatus = String(task?.primary_claim_token_status || '').trim()
const token = String(task?.primary_claim_token || task?.claim_token || '').trim()
const expiredAt = task?.primary_claim_expires_at || task?.claim_expires_at || null
function resolveKuaishouFeifeiOrderClaimUrl(order: Awaited<ReturnType<typeof createKuaishouFeifeiOrder>>) {
return String(order.h5.rechargeUrl || order.h5.entryUrl || '').trim()
}
if (tokenStatus === 'active' && token && expiredAt && new Date(expiredAt).getTime() > Date.now()) {
return {
token,
expiredAt,
claimUrl: buildClaimUrl(token),
}
}
const claimToken = await createTaskClaimToken(task.id)
return {
token: claimToken.token,
expiredAt: claimToken.expired_at,
claimUrl: claimToken.claimUrl,
}
function isLocalClaimUrl(value: unknown) {
const url = String(value || '').trim()
return !/^https?:\/\//i.test(url) || url.includes('/#/claim/')
}
function buildFeifeiPlatformOrderNo(task: TaskRow) {