refactor(fulfillment): 移除飞飞/乐玩通道,仅保留 affiliate_dash
新单只路由 affiliate_dash(未命中走 manual_dispatch);历史飞飞/乐玩任务保留只读 stub,避免订单重同步失败。同步清理 cloudtentacles 调度、Admin 写路径与相关 env。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,22 +15,18 @@ import {
|
||||
import { buildClaimUrl, createTaskClaimToken } from '../claim/claim-service.js'
|
||||
import { assertValidClaimUid, normalizeClaimUid } from '../claim/claim-identity.js'
|
||||
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER, assertOpen91Config } from '../open-91/config.js'
|
||||
import { parseOpen91ProductNo } from '../platforms/ninetyone/order-service.js'
|
||||
import {
|
||||
getKuaishouIndustrySourceConfig,
|
||||
listKuaishouIndustryShopConfigs,
|
||||
} from '../platforms/kuaishou-industry/source-config-service.js'
|
||||
import { isProductionLike } from '../../config/runtime-validation.js'
|
||||
import { createHttpError } from '../../utils/http.js'
|
||||
import { addHours, nowIso } from '../../utils/time.js'
|
||||
import { nowIso } from '../../utils/time.js'
|
||||
import { randomId } from '../../utils/random.js'
|
||||
import { TASK_STATUS } from '../../domain/task-status.js'
|
||||
|
||||
export type LewanMockStep = 'uid' | 'binding' | 'confirm' | 'result'
|
||||
export type FeifeiMockStep = 'uid' | 'ready' | 'completed' | 'failed'
|
||||
|
||||
export type DevMockCreateResult = {
|
||||
platform: 'lewan' | 'feifei' | 'affiliate_dash'
|
||||
platform: 'affiliate_dash'
|
||||
orderId: number
|
||||
orderNo: string
|
||||
taskId: number
|
||||
@@ -55,12 +51,6 @@ export type DevMockKuaishouIndustryVoucherResult = {
|
||||
}>
|
||||
}
|
||||
|
||||
type DeliveryItem = {
|
||||
cloudSkuId: number
|
||||
cloudSkuName: string
|
||||
quantity: number
|
||||
}
|
||||
|
||||
export function isDevMockEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
if (String(env.ENABLE_DEV_MOCK || '').trim() === '1') {
|
||||
return true
|
||||
@@ -91,18 +81,6 @@ export function getDevMockStatus() {
|
||||
nodeEnv: String(process.env.NODE_ENV || 'development'),
|
||||
platforms: enabled
|
||||
? [
|
||||
{
|
||||
key: 'lewan',
|
||||
name: 'kuaishou-lewan',
|
||||
description: '本站 claim + 强制 UID 匹配 + mock 兑换(不调 CloudTentacles)',
|
||||
steps: ['uid', 'binding', 'confirm', 'result'],
|
||||
},
|
||||
{
|
||||
key: 'feifei',
|
||||
name: 'kuaishou-feifei',
|
||||
description: '本站 claim + 拼 uid 的 H5 链接(不调真实 feifei 下单)',
|
||||
steps: ['uid', 'ready', 'completed', 'failed'],
|
||||
},
|
||||
{
|
||||
key: 'affiliate_dash',
|
||||
name: 'affiliate-dash',
|
||||
@@ -115,287 +93,6 @@ export function getDevMockStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function createLewanMockClaim(
|
||||
input: {
|
||||
step?: unknown
|
||||
orderNo?: unknown
|
||||
productNo?: unknown
|
||||
uid?: unknown
|
||||
items?: unknown
|
||||
frontendBaseUrl?: unknown
|
||||
} = {},
|
||||
): Promise<DevMockCreateResult> {
|
||||
assertDevMockEnabled()
|
||||
|
||||
const step = normalizeLewanStep(input.step)
|
||||
const orderNo = String(input.orderNo || `MOCK91${Date.now()}`).trim()
|
||||
const productNo = String(input.productNo || '套餐_1----3676797936').trim()
|
||||
const productInfo = parseOpen91ProductNo(productNo)
|
||||
const productName = productInfo.productName || productInfo.rawProductNo || '套餐_1'
|
||||
const consumeShopId = productInfo.shopId || '3676797936'
|
||||
const expectedUid = resolveMockUid(input.uid, step === 'uid' ? '' : '10001')
|
||||
const deliveryItems = parseDeliveryItems(input.items)
|
||||
const now = nowIso()
|
||||
|
||||
await assertOrderNoAvailable(orderNo)
|
||||
|
||||
const profile = await ensureProfile('kuaishou_ct_assisted', 'kuaishou-lewan 履约', false)
|
||||
const order = await createBaseOrder({
|
||||
orderNo,
|
||||
productNo,
|
||||
productName,
|
||||
now,
|
||||
platformTag: 'lewan',
|
||||
})
|
||||
const orderItem = await createBaseOrderItem({
|
||||
orderId: order.id,
|
||||
orderNo,
|
||||
productNo,
|
||||
productName,
|
||||
consumeShopId,
|
||||
deliveryItems,
|
||||
now,
|
||||
executor: 'lewan',
|
||||
})
|
||||
|
||||
const task = await createTask({
|
||||
orderId: order.id,
|
||||
orderItemId: orderItem.id,
|
||||
unitIndex: 1,
|
||||
provider: OPEN_91_PROVIDER,
|
||||
platform: OPEN_91_PLATFORM,
|
||||
shopId: OPEN_91_PROVIDER,
|
||||
shopName: '91卡券',
|
||||
platformOrderId: orderNo,
|
||||
taskNo: randomId('DT'),
|
||||
profileId: profile.id,
|
||||
executorKey: 'kuaishou_ct_assisted',
|
||||
taskStatus: resolveLewanTaskStatus(step),
|
||||
deliveryStatus: step === 'result' ? 'success' : 'pending',
|
||||
resultCode: step === 'result' ? 'mock_success' : '',
|
||||
resultMessage: step === 'result' ? '开发 mock 已模拟兑换成功' : '',
|
||||
claimToken: '',
|
||||
claimExpiresAt: null,
|
||||
automationMode: 'manual',
|
||||
requiresClaim: true,
|
||||
userActionStatus: step === 'result' ? 'not_required' : 'pending_claim',
|
||||
attemptCount: 0,
|
||||
lastError: '',
|
||||
contextJson: JSON.stringify(
|
||||
buildLewanMockContext({
|
||||
step,
|
||||
orderNo,
|
||||
productName,
|
||||
productNo,
|
||||
consumeShopId,
|
||||
deliveryItems,
|
||||
expectedUid,
|
||||
timestamp: now,
|
||||
}),
|
||||
),
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
|
||||
if (!task) {
|
||||
throw createHttpError('履约任务创建失败', {
|
||||
statusCode: 500,
|
||||
errorCode: 'dev_mock_task_failed',
|
||||
})
|
||||
}
|
||||
|
||||
const claimToken = await createTaskClaimToken(task.id)
|
||||
await updateTask(task.id, {
|
||||
claim_token: claimToken.token,
|
||||
claim_expires_at: claimToken.expired_at,
|
||||
claimed_at: step === 'uid' ? null : now,
|
||||
role_confirmed_at: step === 'confirm' || step === 'result' ? now : null,
|
||||
redeemed_at: step === 'result' ? now : null,
|
||||
role_id: ['binding', 'confirm', 'result'].includes(step) ? expectedUid || '10001' : '',
|
||||
role_name: ['binding', 'confirm', 'result'].includes(step) ? '测试角色' : '',
|
||||
updated_at: now,
|
||||
})
|
||||
|
||||
return buildCreateResult({
|
||||
platform: 'lewan',
|
||||
orderId: order.id,
|
||||
orderNo,
|
||||
taskId: task.id,
|
||||
taskNo: task.task_no,
|
||||
claimToken: claimToken.token,
|
||||
claimUrl: buildClaimUrl(claimToken.token),
|
||||
frontendBaseUrl: input.frontendBaseUrl,
|
||||
expectedUid: expectedUid || '10001',
|
||||
step,
|
||||
productName,
|
||||
tips: buildLewanTips(step, expectedUid || '10001'),
|
||||
})
|
||||
}
|
||||
|
||||
export async function createFeifeiMockClaim(
|
||||
input: {
|
||||
step?: unknown
|
||||
orderNo?: unknown
|
||||
productName?: unknown
|
||||
productCode?: unknown
|
||||
uid?: unknown
|
||||
h5Url?: unknown
|
||||
frontendBaseUrl?: unknown
|
||||
} = {},
|
||||
): Promise<DevMockCreateResult> {
|
||||
assertDevMockEnabled()
|
||||
|
||||
const step = normalizeFeifeiStep(input.step)
|
||||
const orderNo = String(input.orderNo || `MOCKFF${Date.now()}`).trim()
|
||||
const productName = String(input.productName || '套装-浪漫天命').trim()
|
||||
const productCode = String(input.productCode || `MOCK-FF-${Date.now()}`).trim()
|
||||
const expectedUid = resolveMockUid(input.uid, step === 'uid' ? '' : '166909256')
|
||||
const rawH5 =
|
||||
String(input.h5Url || '').trim() ||
|
||||
`http://skin-exchange.yiquyou.icu/h5/bind?code=mock_${encodeURIComponent(orderNo)}&product_name=${encodeURIComponent(productName)}`
|
||||
const now = nowIso()
|
||||
|
||||
await assertOrderNoAvailable(orderNo)
|
||||
|
||||
const profile = await ensureProfile('kuaishou_feifei', 'kuaishou-feifei 履约', true)
|
||||
const order = await createBaseOrder({
|
||||
orderNo,
|
||||
productNo: productName,
|
||||
productName,
|
||||
now,
|
||||
platformTag: 'feifei',
|
||||
})
|
||||
const orderItem = await createBaseOrderItem({
|
||||
orderId: order.id,
|
||||
orderNo,
|
||||
productNo: productName,
|
||||
productName,
|
||||
consumeShopId: '',
|
||||
deliveryItems: [],
|
||||
now,
|
||||
executor: 'feifei',
|
||||
productCode,
|
||||
})
|
||||
|
||||
const rechargeStatus =
|
||||
step === 'completed' ? 30 : step === 'failed' ? 40 : step === 'ready' ? 15 : 15
|
||||
const rechargeStatusLabel =
|
||||
step === 'completed'
|
||||
? '充值成功'
|
||||
: step === 'failed'
|
||||
? '充值失败'
|
||||
: step === 'ready'
|
||||
? '待绑定'
|
||||
: '待领取'
|
||||
|
||||
const task = await createTask({
|
||||
orderId: order.id,
|
||||
orderItemId: orderItem.id,
|
||||
unitIndex: 1,
|
||||
provider: OPEN_91_PROVIDER,
|
||||
platform: OPEN_91_PLATFORM,
|
||||
shopId: OPEN_91_PROVIDER,
|
||||
shopName: '91卡券',
|
||||
platformOrderId: orderNo,
|
||||
taskNo: randomId('DT'),
|
||||
profileId: profile.id,
|
||||
executorKey: 'kuaishou_feifei',
|
||||
taskStatus:
|
||||
step === 'completed'
|
||||
? TASK_STATUS.COMPLETED
|
||||
: step === 'failed'
|
||||
? TASK_STATUS.MANUAL_REVIEW
|
||||
: TASK_STATUS.LINK_GENERATED,
|
||||
deliveryStatus: step === 'completed' ? 'delivered' : 'pending',
|
||||
resultCode:
|
||||
step === 'completed'
|
||||
? 'kuaishou_feifei_completed'
|
||||
: step === 'failed'
|
||||
? 'kuaishou_feifei_status_40'
|
||||
: '',
|
||||
resultMessage: rechargeStatusLabel,
|
||||
claimToken: '',
|
||||
claimExpiresAt: null,
|
||||
automationMode: 'manual',
|
||||
requiresClaim: true,
|
||||
userActionStatus: step === 'completed' ? 'not_required' : 'pending_claim',
|
||||
attemptCount: 0,
|
||||
lastError: step === 'failed' ? '开发 mock 模拟 feifei 失败' : '',
|
||||
contextJson: JSON.stringify({
|
||||
profileKey: 'kuaishou_feifei',
|
||||
profileName: 'kuaishou-feifei 履约',
|
||||
skuCode: productName,
|
||||
skuName: productName,
|
||||
claimIdentity: expectedUid
|
||||
? {
|
||||
expectedUid,
|
||||
submittedAt: now,
|
||||
source: 'dev_mock',
|
||||
}
|
||||
: {
|
||||
expectedUid: '',
|
||||
submittedAt: null,
|
||||
source: '',
|
||||
},
|
||||
kuaishouFeifei: {
|
||||
flowType: 'kuaishou_feifei',
|
||||
productCode,
|
||||
productName,
|
||||
platformOrderNo: orderNo,
|
||||
orderNo: `FF-${orderNo}`,
|
||||
rechargeStatus,
|
||||
rechargeStatusLabel,
|
||||
rechargeResultMessage: step === 'failed' ? '开发 mock 失败' : '',
|
||||
claimUrl: '',
|
||||
consumeStatus: step === 'completed' ? 'not_required' : 'pending',
|
||||
h5: {
|
||||
entryUrl: rawH5,
|
||||
rechargeUrl: rawH5,
|
||||
},
|
||||
lastSyncedAt: now,
|
||||
mock: {
|
||||
enabled: true,
|
||||
orderNo,
|
||||
createdAt: now,
|
||||
},
|
||||
},
|
||||
}),
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
|
||||
if (!task) {
|
||||
throw createHttpError('履约任务创建失败', {
|
||||
statusCode: 500,
|
||||
errorCode: 'dev_mock_task_failed',
|
||||
})
|
||||
}
|
||||
|
||||
const claimToken = await createTaskClaimToken(task.id)
|
||||
await updateTask(task.id, {
|
||||
claim_token: claimToken.token,
|
||||
claim_expires_at: claimToken.expired_at,
|
||||
claimed_at: expectedUid ? now : null,
|
||||
redeemed_at: step === 'completed' ? now : null,
|
||||
updated_at: now,
|
||||
})
|
||||
|
||||
return buildCreateResult({
|
||||
platform: 'feifei',
|
||||
orderId: order.id,
|
||||
orderNo,
|
||||
taskId: task.id,
|
||||
taskNo: task.task_no,
|
||||
claimToken: claimToken.token,
|
||||
claimUrl: buildClaimUrl(claimToken.token),
|
||||
frontendBaseUrl: input.frontendBaseUrl,
|
||||
expectedUid: expectedUid || '166909256',
|
||||
step,
|
||||
productName,
|
||||
tips: buildFeifeiTips(step, expectedUid || '166909256'),
|
||||
})
|
||||
}
|
||||
|
||||
type AffiliateDashMockStep = 'uid' | 'bind' | 'submitted' | 'completed' | 'failed'
|
||||
|
||||
/**
|
||||
@@ -450,10 +147,7 @@ export async function createAffiliateDashMockClaim(
|
||||
orderNo,
|
||||
productNo: productSku,
|
||||
productName,
|
||||
consumeShopId: '',
|
||||
deliveryItems: [],
|
||||
now,
|
||||
executor: 'affiliate_dash',
|
||||
productCode: productSku,
|
||||
})
|
||||
|
||||
@@ -848,51 +542,20 @@ async function createBaseOrderItem(input: {
|
||||
orderNo: string
|
||||
productNo: string
|
||||
productName: string
|
||||
consumeShopId: string
|
||||
deliveryItems: DeliveryItem[]
|
||||
now: string
|
||||
executor: 'lewan' | 'feifei' | 'affiliate_dash'
|
||||
productCode?: string
|
||||
}) {
|
||||
const snapshot =
|
||||
input.executor === 'feifei'
|
||||
? {
|
||||
source: OPEN_91_PROVIDER,
|
||||
orderNo: input.orderNo,
|
||||
productNo: input.productNo,
|
||||
productName: input.productName,
|
||||
kuaishouFeifei: {
|
||||
productCode: input.productCode || '',
|
||||
productName: input.productName,
|
||||
matchMode: 'mock',
|
||||
},
|
||||
}
|
||||
: input.executor === 'affiliate_dash'
|
||||
? {
|
||||
source: OPEN_91_PROVIDER,
|
||||
orderNo: input.orderNo,
|
||||
productNo: input.productNo,
|
||||
productName: input.productName,
|
||||
affiliateDash: {
|
||||
sku: input.productCode || input.productNo,
|
||||
productName: input.productName,
|
||||
matchMode: 'mock',
|
||||
},
|
||||
}
|
||||
: {
|
||||
source: OPEN_91_PROVIDER,
|
||||
orderNo: input.orderNo,
|
||||
productNo: input.productNo,
|
||||
productName: input.productName,
|
||||
shopId: input.consumeShopId,
|
||||
cloudtentacles: {
|
||||
matchMode: 'mock',
|
||||
normalizedProductName: input.productName,
|
||||
cloudSourceKeys: ['mock-cloudtentacles'],
|
||||
resolvedSourceKey: 'mock-cloudtentacles',
|
||||
deliveryItems: input.deliveryItems,
|
||||
},
|
||||
}
|
||||
const snapshot = {
|
||||
source: OPEN_91_PROVIDER,
|
||||
orderNo: input.orderNo,
|
||||
productNo: input.productNo,
|
||||
productName: input.productName,
|
||||
affiliateDash: {
|
||||
sku: input.productCode || input.productNo,
|
||||
productName: input.productName,
|
||||
matchMode: 'mock',
|
||||
},
|
||||
}
|
||||
|
||||
const [orderItem] = await replaceOrderItems(input.orderId, [
|
||||
{
|
||||
@@ -920,157 +583,6 @@ async function createBaseOrderItem(input: {
|
||||
return orderItem
|
||||
}
|
||||
|
||||
function buildLewanMockContext(input: {
|
||||
step: LewanMockStep
|
||||
orderNo: string
|
||||
productName: string
|
||||
productNo: string
|
||||
consumeShopId: string
|
||||
deliveryItems: DeliveryItem[]
|
||||
expectedUid: string
|
||||
timestamp: string
|
||||
}) {
|
||||
const roleReady = ['binding', 'confirm', 'result'].includes(input.step)
|
||||
const completed = input.step === 'result'
|
||||
const boundUid = roleReady ? input.expectedUid || '10001' : ''
|
||||
const primaryItem = input.deliveryItems[0] || {
|
||||
cloudSkuId: 910001,
|
||||
cloudSkuName: 'Mock 商品',
|
||||
quantity: 1,
|
||||
}
|
||||
|
||||
return {
|
||||
profileKey: 'kuaishou_ct_assisted',
|
||||
profileName: 'kuaishou-lewan 履约',
|
||||
skuCode: input.productName,
|
||||
skuName: input.productName,
|
||||
claimIdentity: input.expectedUid
|
||||
? {
|
||||
expectedUid: input.expectedUid,
|
||||
submittedAt: input.timestamp,
|
||||
source: 'dev_mock',
|
||||
}
|
||||
: {
|
||||
expectedUid: '',
|
||||
submittedAt: null,
|
||||
source: '',
|
||||
},
|
||||
kuaishouCloudFulfillment: {
|
||||
flowType: 'kuaishou_cloud_fulfillment',
|
||||
configId: `mock:${input.productName}`,
|
||||
internalSkuCode: input.productName,
|
||||
internalSkuName: input.productName,
|
||||
deliveryItems: input.deliveryItems.length ? input.deliveryItems : [primaryItem],
|
||||
mock: {
|
||||
enabled: true,
|
||||
orderNo: input.orderNo,
|
||||
productNo: input.productNo,
|
||||
createdAt: input.timestamp,
|
||||
},
|
||||
ticket: {
|
||||
code: roleReady ? `MOCK-${input.orderNo}` : '',
|
||||
status: roleReady ? 'verified' : 'pending',
|
||||
capturedAt: roleReady ? input.timestamp : null,
|
||||
capturedBy: roleReady ? { source: 'dev_mock' } : null,
|
||||
verifiedAt: roleReady ? input.timestamp : null,
|
||||
oid: roleReady ? `MOCK-OID-${input.orderNo}` : '',
|
||||
formToken: roleReady ? `MOCK-FORM-${input.orderNo}` : '',
|
||||
leftCount: roleReady ? 1 : 0,
|
||||
goodsTitle: roleReady ? input.productName : '',
|
||||
},
|
||||
binding: {
|
||||
prepareStatus: roleReady ? 'ready' : 'pending',
|
||||
cloudSourceKeys: ['mock-cloudtentacles'],
|
||||
resolvedSourceKey: 'mock-cloudtentacles',
|
||||
skuId: primaryItem.cloudSkuId,
|
||||
skuName: primaryItem.cloudSkuName,
|
||||
vnKey: '1',
|
||||
vnId: roleReady ? 900001 : 0,
|
||||
vnPhone: roleReady ? '13800000000' : '',
|
||||
bindUrl: roleReady ? `https://example.com/mock-kuaishou-cloud-bind/${input.orderNo}` : '',
|
||||
bindPreparedAt: roleReady ? input.timestamp : null,
|
||||
bindExpiresAt: roleReady ? addHours(input.timestamp, 24) : null,
|
||||
bindProbeAt: roleReady ? input.timestamp : null,
|
||||
bindProbeStatus: roleReady ? 'success' : '',
|
||||
bindProbeMessage: '',
|
||||
roleName: roleReady ? '测试角色' : '',
|
||||
roleId: boundUid,
|
||||
},
|
||||
role: {
|
||||
status: roleReady ? 'ready' : 'pending',
|
||||
name: roleReady ? '测试角色' : '',
|
||||
rid: boundUid,
|
||||
refreshedAt: roleReady ? input.timestamp : null,
|
||||
errorMessage: '',
|
||||
rawInfo: roleReady ? { mock: true } : null,
|
||||
defaultName: roleReady ? '默认机位角色' : '',
|
||||
defaultRid: roleReady ? 'DEFAULT-000' : '',
|
||||
defaultCapturedAt: roleReady ? input.timestamp : null,
|
||||
defaultCaptureStatus: roleReady ? 'captured' : '',
|
||||
defaultErrorMessage: '',
|
||||
isDefaultRole: false,
|
||||
},
|
||||
purchase: {
|
||||
autoBuyEnabled: true,
|
||||
minAssetReserve: 0,
|
||||
usedKnapsack: false,
|
||||
purchaseTriggered: false,
|
||||
assetBefore: 0,
|
||||
assetAfter: 0,
|
||||
purchaseAt: null,
|
||||
items: [],
|
||||
},
|
||||
dispatch: {
|
||||
status: completed ? 'success' : 'pending',
|
||||
dispatchAt: completed ? input.timestamp : null,
|
||||
dispatchBy: completed ? { source: 'dev_mock' } : null,
|
||||
sendType: 0,
|
||||
note: completed ? '开发 mock 已模拟发货成功' : '',
|
||||
items: completed ? input.deliveryItems : [],
|
||||
},
|
||||
returnNumber: {
|
||||
status: completed ? 'success' : 'pending',
|
||||
returnedAt: completed ? input.timestamp : null,
|
||||
returnedBy: completed ? { source: 'dev_mock' } : null,
|
||||
autoReturnEnabled: true,
|
||||
},
|
||||
consume: {
|
||||
status: completed ? 'success' : 'pending',
|
||||
shopId: input.consumeShopId,
|
||||
shopName: '',
|
||||
autoConsumeEnabled: true,
|
||||
consumedAt: completed ? input.timestamp : null,
|
||||
errorMessage: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function resolveLewanTaskStatus(step: LewanMockStep) {
|
||||
if (step === 'result') return TASK_STATUS.COMPLETED
|
||||
if (step === 'confirm') return TASK_STATUS.ROLE_CONFIRMED
|
||||
if (step === 'binding') return TASK_STATUS.WAITING_BINDING
|
||||
return TASK_STATUS.LINK_GENERATED
|
||||
}
|
||||
|
||||
function normalizeLewanStep(value: unknown): LewanMockStep {
|
||||
const step = String(value || 'uid').trim()
|
||||
if (['uid', 'binding', 'confirm', 'result'].includes(step)) {
|
||||
return step as LewanMockStep
|
||||
}
|
||||
// 兼容旧 ticket 命名
|
||||
if (step === 'ticket') return 'uid'
|
||||
return 'uid'
|
||||
}
|
||||
|
||||
function normalizeFeifeiStep(value: unknown): FeifeiMockStep {
|
||||
const step = String(value || 'uid').trim()
|
||||
if (['uid', 'ready', 'completed', 'failed'].includes(step)) {
|
||||
return step as FeifeiMockStep
|
||||
}
|
||||
return 'uid'
|
||||
}
|
||||
|
||||
function normalizeAffiliateDashStep(value: unknown): AffiliateDashMockStep {
|
||||
const step = String(value || 'uid').trim()
|
||||
if (['uid', 'bind', 'submitted', 'completed', 'failed'].includes(step)) {
|
||||
@@ -1099,48 +611,8 @@ function resolveMockIndustrySellerId(value: unknown): string {
|
||||
return String(shop?.sellerId || shop?.shopId || '141242642').trim()
|
||||
}
|
||||
|
||||
function parseDeliveryItems(value: unknown): DeliveryItem[] {
|
||||
if (!value) {
|
||||
return [
|
||||
{
|
||||
cloudSkuId: 910001,
|
||||
cloudSkuName: 'Mock 商品',
|
||||
quantity: 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
return parseDeliveryItems(JSON.parse(value))
|
||||
} catch {
|
||||
return parseDeliveryItems(null)
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray(value)) {
|
||||
return parseDeliveryItems(null)
|
||||
}
|
||||
|
||||
const items = value
|
||||
.map((item) => {
|
||||
const source = item && typeof item === 'object' ? (item as Record<string, unknown>) : {}
|
||||
const cloudSkuId = Number(source.cloudSkuId || source.skuId || 0) || 0
|
||||
const quantity = Number(source.quantity || 1) || 1
|
||||
if (!cloudSkuId) return null
|
||||
return {
|
||||
cloudSkuId,
|
||||
cloudSkuName: String(source.cloudSkuName || source.skuName || 'Mock 商品').trim(),
|
||||
quantity: quantity > 0 ? quantity : 1,
|
||||
}
|
||||
})
|
||||
.filter((item): item is DeliveryItem => Boolean(item))
|
||||
|
||||
return items.length > 0 ? items : parseDeliveryItems(null)
|
||||
}
|
||||
|
||||
function buildCreateResult(input: {
|
||||
platform: 'lewan' | 'feifei' | 'affiliate_dash'
|
||||
platform: 'affiliate_dash'
|
||||
orderId: number
|
||||
orderNo: string
|
||||
taskId: number
|
||||
@@ -1178,38 +650,6 @@ function buildFrontendClaimUrl(token: string, frontendBaseUrl?: unknown) {
|
||||
return `http://127.0.0.1/#/claim/${token}`
|
||||
}
|
||||
|
||||
function buildLewanTips(step: LewanMockStep, uid: string) {
|
||||
if (step === 'uid') {
|
||||
return [
|
||||
`打开领取链接后,Step1 填写 UID:${uid}`,
|
||||
'提交后进入绑定步;mock 绑定链接仅作展示,点击刷新/确认前请保证 UID 与角色 ID 一致',
|
||||
]
|
||||
}
|
||||
if (step === 'binding') {
|
||||
return [
|
||||
`已预填 UID=${uid} 且角色 ID 已匹配`,
|
||||
'可直接点「UID 已匹配,下一步」→ 确认兑换(mock 不会真实发货)',
|
||||
]
|
||||
}
|
||||
if (step === 'confirm') {
|
||||
return ['已进入确认兑换步,点击确认兑换即可模拟成功']
|
||||
}
|
||||
return ['已模拟兑换完成,可直接看结果页']
|
||||
}
|
||||
|
||||
function buildFeifeiTips(step: FeifeiMockStep, uid: string) {
|
||||
if (step === 'uid') {
|
||||
return [`打开领取链接,Step1 填 UID:${uid}`, '提交后点「打开领取链接」,URL 应带 uid 参数']
|
||||
}
|
||||
if (step === 'ready') {
|
||||
return [`已预填 UID=${uid},可直接打开带 uid 的 H5(mock 链接,无需真实平台)`]
|
||||
}
|
||||
if (step === 'failed') {
|
||||
return ['已模拟 feifei 失败态,用于看领取页结果展示']
|
||||
}
|
||||
return ['已模拟 feifei 成功完成态']
|
||||
}
|
||||
|
||||
function buildAffiliateDashTips(step: AffiliateDashMockStep, uid: string) {
|
||||
if (step === 'uid') {
|
||||
return [`打开领取链接,Step1 填 UID:${uid}(或自定义)`, '提交后进入绑定步,mock 会给出二维码']
|
||||
|
||||
Reference in New Issue
Block a user