优化快手 Cloud 主链路状态机
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
import test from 'node:test'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
|
||||||
|
import {
|
||||||
|
TASK_STATUS,
|
||||||
|
canRedeemKuaishouCloudClaimStatus,
|
||||||
|
canTaskTransition,
|
||||||
|
isClaimInactiveTaskStatus,
|
||||||
|
isOpen91FailedTaskStatus,
|
||||||
|
shouldEnsureKuaishouCloudClaimLink,
|
||||||
|
} from './task-status.js'
|
||||||
|
|
||||||
|
test('任务状态机声明快手 Cloud 主流程跳转', () => {
|
||||||
|
assert.equal(canTaskTransition(TASK_STATUS.PENDING_BINDING_PREPARE, TASK_STATUS.WAITING_BINDING), true)
|
||||||
|
assert.equal(canTaskTransition(TASK_STATUS.WAITING_BINDING, TASK_STATUS.ROLE_CONFIRMED), true)
|
||||||
|
assert.equal(canTaskTransition(TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING), true)
|
||||||
|
assert.equal(canTaskTransition(TASK_STATUS.REDEEMING, TASK_STATUS.DISPATCHED_PENDING_RETURN), true)
|
||||||
|
assert.equal(canTaskTransition(TASK_STATUS.DISPATCHED_PENDING_RETURN, TASK_STATUS.COMPLETED), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('任务状态机收敛领取和 91 查询的业务判断', () => {
|
||||||
|
assert.equal(shouldEnsureKuaishouCloudClaimLink(TASK_STATUS.PENDING_BINDING_PREPARE), true)
|
||||||
|
assert.equal(canRedeemKuaishouCloudClaimStatus(TASK_STATUS.ROLE_CONFIRMED), true)
|
||||||
|
assert.equal(canRedeemKuaishouCloudClaimStatus(TASK_STATUS.WAITING_BINDING), false)
|
||||||
|
assert.equal(isClaimInactiveTaskStatus(TASK_STATUS.MANUAL_REVIEW), true)
|
||||||
|
assert.equal(isOpen91FailedTaskStatus(TASK_STATUS.CLOSED), true)
|
||||||
|
})
|
||||||
@@ -0,0 +1,313 @@
|
|||||||
|
export const TASK_STATUS = {
|
||||||
|
PENDING_PAYMENT: 'pending_payment',
|
||||||
|
PAID: 'paid',
|
||||||
|
LINK_GENERATED: 'link_generated',
|
||||||
|
CLAIMED: 'claimed',
|
||||||
|
PENDING_BINDING_PREPARE: 'pending_binding_prepare',
|
||||||
|
WAITING_BINDING: 'waiting_binding',
|
||||||
|
ROLE_CONFIRMED: 'role_confirmed',
|
||||||
|
REDEEMING: 'redeeming',
|
||||||
|
DISPATCHED_PENDING_RETURN: 'dispatched_pending_return',
|
||||||
|
COMPLETED: 'completed',
|
||||||
|
REDEEMED: 'redeemed',
|
||||||
|
RETRY_PENDING: 'retry_pending',
|
||||||
|
MANUAL_REVIEW: 'manual_review',
|
||||||
|
FAILED: 'failed',
|
||||||
|
EXPIRED: 'expired',
|
||||||
|
CLOSED: 'closed',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type KnownTaskStatus = typeof TASK_STATUS[keyof typeof TASK_STATUS]
|
||||||
|
export type TaskStatus = KnownTaskStatus | (string & {})
|
||||||
|
|
||||||
|
const TASK_TRANSITIONS: Record<KnownTaskStatus, readonly KnownTaskStatus[]> = {
|
||||||
|
[TASK_STATUS.PENDING_PAYMENT]: [
|
||||||
|
TASK_STATUS.PAID,
|
||||||
|
TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.PAID]: [
|
||||||
|
TASK_STATUS.LINK_GENERATED,
|
||||||
|
TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.LINK_GENERATED]: [
|
||||||
|
TASK_STATUS.CLAIMED,
|
||||||
|
TASK_STATUS.WAITING_BINDING,
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.CLAIMED]: [
|
||||||
|
TASK_STATUS.WAITING_BINDING,
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.PENDING_BINDING_PREPARE]: [
|
||||||
|
TASK_STATUS.WAITING_BINDING,
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.WAITING_BINDING]: [
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.REDEEMING,
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.ROLE_CONFIRMED]: [
|
||||||
|
TASK_STATUS.REDEEMING,
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.REDEEMING]: [
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.DISPATCHED_PENDING_RETURN]: [
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.RETRY_PENDING]: [
|
||||||
|
TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
|
TASK_STATUS.WAITING_BINDING,
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.REDEEMING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.MANUAL_REVIEW]: [
|
||||||
|
TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
|
TASK_STATUS.WAITING_BINDING,
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.REDEEMING,
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.FAILED]: [
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
],
|
||||||
|
[TASK_STATUS.COMPLETED]: [],
|
||||||
|
[TASK_STATUS.REDEEMED]: [],
|
||||||
|
[TASK_STATUS.EXPIRED]: [],
|
||||||
|
[TASK_STATUS.CLOSED]: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
const FINAL_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
])
|
||||||
|
|
||||||
|
const OPEN_91_FAILED_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.FAILED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
])
|
||||||
|
|
||||||
|
const CLAIM_INACTIVE_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.FAILED,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
])
|
||||||
|
|
||||||
|
const PAID_PREPARATION_STABLE_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.LINK_GENERATED,
|
||||||
|
TASK_STATUS.CLAIMED,
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.REDEEMING,
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
])
|
||||||
|
|
||||||
|
const KUAISHOU_CLOUD_CLAIM_LINK_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
|
TASK_STATUS.WAITING_BINDING,
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.FAILED,
|
||||||
|
])
|
||||||
|
|
||||||
|
const KUAISHOU_CLOUD_ROLE_CONFIRM_SETTLED_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.REDEEMING,
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
])
|
||||||
|
|
||||||
|
const KUAISHOU_CLOUD_REDEEM_SETTLED_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.REDEEMING,
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
])
|
||||||
|
|
||||||
|
const CLAIM_LINK_REGENERATABLE_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.LINK_GENERATED,
|
||||||
|
TASK_STATUS.CLAIMED,
|
||||||
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
])
|
||||||
|
|
||||||
|
const KUAISHOU_CLOUD_RESULT_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.FAILED,
|
||||||
|
])
|
||||||
|
|
||||||
|
const FULFILLMENT_COMPLETED_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
])
|
||||||
|
|
||||||
|
const RETRYABLE_TASK_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.RETRY_PENDING,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
])
|
||||||
|
|
||||||
|
const KUAISHOU_CLOUD_PREPARABLE_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.FAILED,
|
||||||
|
])
|
||||||
|
|
||||||
|
export function normalizeTaskStatus(value: unknown): TaskStatus {
|
||||||
|
return String(value || '').trim() as TaskStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canTaskTransition(from: unknown, to: unknown): boolean {
|
||||||
|
const current = normalizeTaskStatus(from) as KnownTaskStatus
|
||||||
|
const next = normalizeTaskStatus(to) as KnownTaskStatus
|
||||||
|
if (!current || !next || current === next) {
|
||||||
|
return Boolean(current && next)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boolean(TASK_TRANSITIONS[current]?.includes(next))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTaskNextStatuses(status: unknown): readonly KnownTaskStatus[] {
|
||||||
|
return TASK_TRANSITIONS[normalizeTaskStatus(status) as KnownTaskStatus] || []
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTaskFinalStatus(status: unknown): boolean {
|
||||||
|
return FINAL_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isOpen91FailedTaskStatus(status: unknown): boolean {
|
||||||
|
return OPEN_91_FAILED_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isClaimInactiveTaskStatus(status: unknown): boolean {
|
||||||
|
return CLAIM_INACTIVE_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPaidPreparationStableStatus(status: unknown): boolean {
|
||||||
|
return PAID_PREPARATION_STABLE_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldEnsureKuaishouCloudClaimLink(status: unknown): boolean {
|
||||||
|
return KUAISHOU_CLOUD_CLAIM_LINK_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isKuaishouCloudRoleConfirmSettledStatus(status: unknown): boolean {
|
||||||
|
return KUAISHOU_CLOUD_ROLE_CONFIRM_SETTLED_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isKuaishouCloudRedeemSettledStatus(status: unknown): boolean {
|
||||||
|
return KUAISHOU_CLOUD_REDEEM_SETTLED_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canRedeemKuaishouCloudClaimStatus(status: unknown): boolean {
|
||||||
|
return normalizeTaskStatus(status) === TASK_STATUS.ROLE_CONFIRMED
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canRegenerateClaimLinkStatus(status: unknown): boolean {
|
||||||
|
return CLAIM_LINK_REGENERATABLE_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasKuaishouCloudRedeemResultStatus(status: unknown): boolean {
|
||||||
|
return KUAISHOU_CLOUD_RESULT_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTaskFulfillmentCompletedStatus(status: unknown): boolean {
|
||||||
|
return FULFILLMENT_COMPLETED_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canRetryTaskStatus(status: unknown): boolean {
|
||||||
|
return RETRYABLE_TASK_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canMarkManualReviewTaskStatus(status: unknown): boolean {
|
||||||
|
const normalized = normalizeTaskStatus(status)
|
||||||
|
return normalized !== TASK_STATUS.MANUAL_REVIEW && !isTaskFinalStatus(normalized)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canCompleteManualDispatchTaskStatus(status: unknown): boolean {
|
||||||
|
return !isTaskFinalStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canPrepareKuaishouCloudFulfillmentStatus(status: unknown): boolean {
|
||||||
|
return KUAISHOU_CLOUD_PREPARABLE_STATUSES.has(normalizeTaskStatus(status))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canDispatchKuaishouCloudFulfillmentStatus(status: unknown): boolean {
|
||||||
|
return normalizeTaskStatus(status) === TASK_STATUS.WAITING_BINDING
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canReturnKuaishouCloudFulfillmentStatus(status: unknown): boolean {
|
||||||
|
return normalizeTaskStatus(status) === TASK_STATUS.DISPATCHED_PENDING_RETURN
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveInitialPaidTaskStatus(profile: {
|
||||||
|
requires_claim?: boolean
|
||||||
|
executor_key?: unknown
|
||||||
|
} | null | undefined): TaskStatus {
|
||||||
|
if (Boolean(profile?.requires_claim)) {
|
||||||
|
return TASK_STATUS.PAID
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(profile?.executor_key || '').trim() === 'kuaishou_ct_assisted') {
|
||||||
|
return TASK_STATUS.PENDING_BINDING_PREPARE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(profile?.executor_key || '').trim() === 'manual_dispatch') {
|
||||||
|
return TASK_STATUS.MANUAL_REVIEW
|
||||||
|
}
|
||||||
|
|
||||||
|
return TASK_STATUS.PAID
|
||||||
|
}
|
||||||
@@ -8,6 +8,14 @@ import { listCloudtentaclesSources } from '../platforms/cloudtentacles/source-co
|
|||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
||||||
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
|
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
|
||||||
|
import {
|
||||||
|
canCompleteManualDispatchTaskStatus,
|
||||||
|
canDispatchKuaishouCloudFulfillmentStatus,
|
||||||
|
canMarkManualReviewTaskStatus,
|
||||||
|
canPrepareKuaishouCloudFulfillmentStatus,
|
||||||
|
canReturnKuaishouCloudFulfillmentStatus,
|
||||||
|
canRetryTaskStatus,
|
||||||
|
} from '../../domain/task-status.js'
|
||||||
import {
|
import {
|
||||||
canViewerCloseTask,
|
canViewerCloseTask,
|
||||||
canRegenerateClaimLinkForViewer,
|
canRegenerateClaimLinkForViewer,
|
||||||
@@ -228,25 +236,25 @@ export async function getAdminTaskDetail(
|
|||||||
operations: {
|
operations: {
|
||||||
canRetry: viewerContext.canManageTaskLifecycle
|
canRetry: viewerContext.canManageTaskLifecycle
|
||||||
&& !isManualDispatchTask(task)
|
&& !isManualDispatchTask(task)
|
||||||
&& ['retry_pending', 'manual_review'].includes(task.task_status),
|
&& canRetryTaskStatus(task.task_status),
|
||||||
canRegenerateClaimLink: canRegenerateClaimLinkForViewer(task, viewerContext),
|
canRegenerateClaimLink: canRegenerateClaimLinkForViewer(task, viewerContext),
|
||||||
canClose: canViewerCloseTask(task, viewerContext),
|
canClose: canViewerCloseTask(task, viewerContext),
|
||||||
canMarkManualReview: viewerContext.canManageTaskLifecycle && !['redeemed', 'closed', 'manual_review'].includes(task.task_status),
|
canMarkManualReview: viewerContext.canManageTaskLifecycle && canMarkManualReviewTaskStatus(task.task_status),
|
||||||
canCompleteManualDispatch: viewerContext.canManageTaskLifecycle && isManualDispatchTask(task) && !['redeemed', 'closed'].includes(task.task_status),
|
canCompleteManualDispatch: viewerContext.canManageTaskLifecycle && isManualDispatchTask(task) && canCompleteManualDispatchTaskStatus(task.task_status),
|
||||||
canPrepareKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
canPrepareKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
||||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||||
&& String(kuaishouCloudFulfillment?.dispatch.status || 'pending').trim() === 'pending'
|
&& String(kuaishouCloudFulfillment?.dispatch.status || 'pending').trim() === 'pending'
|
||||||
&& String(kuaishouCloudFulfillment?.returnNumber.status || 'pending').trim() === 'pending'
|
&& String(kuaishouCloudFulfillment?.returnNumber.status || 'pending').trim() === 'pending'
|
||||||
&& ['pending_binding_prepare', 'manual_review', 'failed'].includes(String(task.task_status || '').trim()),
|
&& canPrepareKuaishouCloudFulfillmentStatus(task.task_status),
|
||||||
canRefreshKuaishouCloudRoleInfo: viewerContext.canOperateAssistedTask
|
canRefreshKuaishouCloudRoleInfo: viewerContext.canOperateAssistedTask
|
||||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||||
&& Number(kuaishouCloudFulfillment?.binding.vnId || 0) > 0,
|
&& Number(kuaishouCloudFulfillment?.binding.vnId || 0) > 0,
|
||||||
canDispatchKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
canDispatchKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
||||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||||
&& ['waiting_binding'].includes(String(task.task_status || '').trim()),
|
&& canDispatchKuaishouCloudFulfillmentStatus(task.task_status),
|
||||||
canReturnKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
canReturnKuaishouCloudFulfillment: viewerContext.canManageTaskLifecycle
|
||||||
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
&& String(task.executor_key || '').trim() === 'kuaishou_ct_assisted'
|
||||||
&& ['dispatched_pending_return'].includes(String(task.task_status || '').trim()),
|
&& canReturnKuaishouCloudFulfillmentStatus(task.task_status),
|
||||||
canViewSensitiveTaskData: viewerContext.canViewSensitiveTaskData,
|
canViewSensitiveTaskData: viewerContext.canViewSensitiveTaskData,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import {
|
|||||||
parseTaskContext as parseTaskContextValue,
|
parseTaskContext as parseTaskContextValue,
|
||||||
parseTaskState as parseTaskStateValue,
|
parseTaskState as parseTaskStateValue,
|
||||||
} from '../../utils/task-json.js'
|
} from '../../utils/task-json.js'
|
||||||
|
import {
|
||||||
|
canRegenerateClaimLinkStatus,
|
||||||
|
isTaskFinalStatus,
|
||||||
|
} from '../../domain/task-status.js'
|
||||||
|
|
||||||
import type { AdminViewerSessionInput } from '../../types/admin/read-inputs.js'
|
import type { AdminViewerSessionInput } from '../../types/admin/read-inputs.js'
|
||||||
import type { OrderItemRow, TaskRow } from '../../types/repository/rows.js'
|
import type { OrderItemRow, TaskRow } from '../../types/repository/rows.js'
|
||||||
@@ -220,7 +224,7 @@ export function canViewerCloseTask(task: TaskLike, viewerContext: AdminViewerCon
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return !['redeemed', 'completed', 'closed'].includes(String(task?.task_status || '').trim())
|
return !isTaskFinalStatus(task?.task_status)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveDisplayShopName(provider: unknown, shopId: unknown, shopName: unknown): string {
|
export function resolveDisplayShopName(provider: unknown, shopId: unknown, shopName: unknown): string {
|
||||||
@@ -295,7 +299,7 @@ export function canRegenerateClaimLinkForViewer(task: TaskLike, viewerContext: A
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseAllowed = ['link_generated', 'claimed', 'role_confirmed', 'retry_pending', 'manual_review'].includes(String(task.task_status || '').trim())
|
const baseAllowed = canRegenerateClaimLinkStatus(task.task_status)
|
||||||
|
|
||||||
if (!baseAllowed) {
|
if (!baseAllowed) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import { getTaskById } from '../../repositories/task-repo.js'
|
import { getTaskById } from '../../repositories/task-repo.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { safeParseJson } from './admin-query-utils.js'
|
import { safeParseJson } from './admin-query-utils.js'
|
||||||
|
import {
|
||||||
|
TASK_STATUS,
|
||||||
|
isTaskFulfillmentCompletedStatus,
|
||||||
|
normalizeTaskStatus,
|
||||||
|
} from '../../domain/task-status.js'
|
||||||
import {
|
import {
|
||||||
createAdminViewerContext,
|
createAdminViewerContext,
|
||||||
getTaskPrimaryClaimTokenId,
|
getTaskPrimaryClaimTokenId,
|
||||||
@@ -173,7 +178,7 @@ export function buildOrderFulfillmentProgress(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildTaskFulfillmentState(task: TaskRow | null | undefined): TaskFulfillmentState {
|
function buildTaskFulfillmentState(task: TaskRow | null | undefined): TaskFulfillmentState {
|
||||||
const normalizedStatus = String(task?.task_status || '').trim()
|
const normalizedStatus = normalizeTaskStatus(task?.task_status)
|
||||||
|
|
||||||
if (!normalizedStatus) {
|
if (!normalizedStatus) {
|
||||||
return {
|
return {
|
||||||
@@ -182,63 +187,63 @@ function buildTaskFulfillmentState(task: TaskRow | null | undefined): TaskFulfil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'pending_payment') {
|
if (normalizedStatus === TASK_STATUS.PENDING_PAYMENT) {
|
||||||
return { resourceStatus: 'pending_payment', customerStatus: 'not_started' }
|
return { resourceStatus: 'pending_payment', customerStatus: 'not_started' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'paid') {
|
if (normalizedStatus === TASK_STATUS.PAID) {
|
||||||
return { resourceStatus: 'pending_prepare', customerStatus: 'not_started' }
|
return { resourceStatus: 'pending_prepare', customerStatus: 'not_started' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'pending_binding_prepare') {
|
if (normalizedStatus === TASK_STATUS.PENDING_BINDING_PREPARE) {
|
||||||
return { resourceStatus: 'pending_prepare', customerStatus: 'not_started' }
|
return { resourceStatus: 'pending_prepare', customerStatus: 'not_started' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'waiting_binding') {
|
if (normalizedStatus === TASK_STATUS.WAITING_BINDING) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'waiting_customer' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'waiting_customer' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'dispatched_pending_return') {
|
if (normalizedStatus === TASK_STATUS.DISPATCHED_PENDING_RETURN) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'customer_completed' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'customer_completed' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'completed') {
|
if (normalizedStatus === TASK_STATUS.COMPLETED) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'customer_completed' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'customer_completed' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'manual_review') {
|
if (normalizedStatus === TASK_STATUS.MANUAL_REVIEW) {
|
||||||
return { resourceStatus: 'manual_review', customerStatus: 'customer_exception' }
|
return { resourceStatus: 'manual_review', customerStatus: 'customer_exception' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'retry_pending') {
|
if (normalizedStatus === TASK_STATUS.RETRY_PENDING) {
|
||||||
return { resourceStatus: 'retry_pending', customerStatus: 'customer_exception' }
|
return { resourceStatus: 'retry_pending', customerStatus: 'customer_exception' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'closed') {
|
if (normalizedStatus === TASK_STATUS.CLOSED) {
|
||||||
return { resourceStatus: 'closed', customerStatus: 'closed' }
|
return { resourceStatus: 'closed', customerStatus: 'closed' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'expired') {
|
if (normalizedStatus === TASK_STATUS.EXPIRED) {
|
||||||
return { resourceStatus: 'expired', customerStatus: 'expired' }
|
return { resourceStatus: 'expired', customerStatus: 'expired' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'link_generated') {
|
if (normalizedStatus === TASK_STATUS.LINK_GENERATED) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'waiting_customer' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'waiting_customer' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'claimed') {
|
if (normalizedStatus === TASK_STATUS.CLAIMED) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'link_opened' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'link_opened' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'role_confirmed') {
|
if (normalizedStatus === TASK_STATUS.ROLE_CONFIRMED) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'customer_confirmed' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'customer_confirmed' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'redeeming') {
|
if (normalizedStatus === TASK_STATUS.REDEEMING) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'customer_processing' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'customer_processing' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedStatus === 'redeemed') {
|
if (normalizedStatus === TASK_STATUS.REDEEMED) {
|
||||||
return { resourceStatus: 'resource_ready', customerStatus: 'customer_completed' }
|
return { resourceStatus: 'resource_ready', customerStatus: 'customer_completed' }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +259,7 @@ function isTaskResourcePrepared(task: TaskRow | null | undefined): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isTaskFulfillmentCompleted(task: TaskRow | null | undefined): boolean {
|
function isTaskFulfillmentCompleted(task: TaskRow | null | undefined): boolean {
|
||||||
return ['redeemed', 'completed', 'dispatched_pending_return'].includes(String(task?.task_status || '').trim())
|
return isTaskFulfillmentCompletedStatus(task?.task_status)
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeRecord(value: unknown): JsonRecord {
|
function normalizeRecord(value: unknown): JsonRecord {
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import { createHttpError } from '../../utils/http.js'
|
|||||||
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
||||||
import { parseTaskContext as parseTaskContextValue } from '../../utils/task-json.js'
|
import { parseTaskContext as parseTaskContextValue } from '../../utils/task-json.js'
|
||||||
import { nowIso } from '../../utils/time.js'
|
import { nowIso } from '../../utils/time.js'
|
||||||
|
import { TASK_STATUS, isTaskFinalStatus } from '../../domain/task-status.js'
|
||||||
import { buildClaimUrl } from './claim-service.js'
|
import { buildClaimUrl } from './claim-service.js'
|
||||||
import type { ClaimTokenRow, OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
|
import type { ClaimTokenRow, OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
|
||||||
|
|
||||||
export const CLAIM_TERMINAL_STATUSES = new Set(['expired', 'closed'])
|
export const CLAIM_TERMINAL_STATUSES = new Set([TASK_STATUS.EXPIRED, TASK_STATUS.CLOSED])
|
||||||
export const KUAISHOU_CLOUD_CLAIM_GUIDE_BASE_PATH = '/kuaishou-cloud-guide'
|
export const KUAISHOU_CLOUD_CLAIM_GUIDE_BASE_PATH = '/kuaishou-cloud-guide'
|
||||||
|
|
||||||
type JsonObject = Record<string, any>
|
type JsonObject = Record<string, any>
|
||||||
@@ -410,16 +411,16 @@ function isClaimPlaceholderSkuName(value: string) {
|
|||||||
async function expireClaimContext(claimToken: ClaimTokenRow, task: TaskRow) {
|
async function expireClaimContext(claimToken: ClaimTokenRow, task: TaskRow) {
|
||||||
const now = nowIso()
|
const now = nowIso()
|
||||||
const nextClaimToken = await updateClaimToken(claimToken.id, {
|
const nextClaimToken = await updateClaimToken(claimToken.id, {
|
||||||
status: 'expired',
|
status: TASK_STATUS.EXPIRED,
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
})
|
})
|
||||||
|
|
||||||
let nextTask = task
|
let nextTask = task
|
||||||
|
|
||||||
if (!CLAIM_TERMINAL_STATUSES.has(String(task.task_status || '')) && task.task_status !== 'redeemed') {
|
if (!isTaskFinalStatus(task.task_status)) {
|
||||||
nextTask = await updateTask(task.id, {
|
nextTask = await updateTask(task.id, {
|
||||||
task_status: 'expired',
|
task_status: TASK_STATUS.EXPIRED,
|
||||||
user_action_status: 'expired',
|
user_action_status: TASK_STATUS.EXPIRED,
|
||||||
last_error: '领取链接已过期',
|
last_error: '领取链接已过期',
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
}) || task
|
}) || task
|
||||||
|
|||||||
@@ -6,6 +6,13 @@ import { createTaskEvent } from '../../repositories/task-event-repo.js'
|
|||||||
import { getTaskById, updateTask, updateTaskStatusIfCurrent } from '../../repositories/task-repo.js'
|
import { getTaskById, updateTask, updateTaskStatusIfCurrent } from '../../repositories/task-repo.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { addHours, nowIso } from '../../utils/time.js'
|
import { addHours, nowIso } from '../../utils/time.js'
|
||||||
|
import {
|
||||||
|
TASK_STATUS,
|
||||||
|
canRedeemKuaishouCloudClaimStatus,
|
||||||
|
isKuaishouCloudRedeemSettledStatus,
|
||||||
|
isKuaishouCloudRoleConfirmSettledStatus,
|
||||||
|
normalizeTaskStatus,
|
||||||
|
} from '../../domain/task-status.js'
|
||||||
import {
|
import {
|
||||||
getKuaishouEticketSourceConfig,
|
getKuaishouEticketSourceConfig,
|
||||||
listKuaishouEticketShopConfigs,
|
listKuaishouEticketShopConfigs,
|
||||||
@@ -119,7 +126,7 @@ export async function verifyKuaishouCloudClaimTicket(token: unknown, payload: Js
|
|||||||
kuaishouCloudFulfillment: mockFlow,
|
kuaishouCloudFulfillment: mockFlow,
|
||||||
}),
|
}),
|
||||||
claimed_at: context.task.claimed_at || now,
|
claimed_at: context.task.claimed_at || now,
|
||||||
task_status: 'waiting_binding',
|
task_status: TASK_STATUS.WAITING_BINDING,
|
||||||
user_action_status: 'pending_claim',
|
user_action_status: 'pending_claim',
|
||||||
last_error: '',
|
last_error: '',
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
@@ -357,7 +364,7 @@ export async function confirmKuaishouCloudClaimRole(token: unknown) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['role_confirmed', 'redeeming', 'dispatched_pending_return', 'completed', 'manual_review'].includes(String(context.task.task_status || '').trim())) {
|
if (isKuaishouCloudRoleConfirmSettledStatus(context.task.task_status)) {
|
||||||
return getKuaishouCloudClaimDetail(token)
|
return getKuaishouCloudClaimDetail(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,10 +395,10 @@ export async function confirmKuaishouCloudClaimRole(token: unknown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await updateTask(context.task.id, {
|
await updateTask(context.task.id, {
|
||||||
task_status: 'role_confirmed',
|
task_status: TASK_STATUS.ROLE_CONFIRMED,
|
||||||
role_id: flow.binding.roleId,
|
role_id: flow.binding.roleId,
|
||||||
role_name: flow.binding.roleName,
|
role_name: flow.binding.roleName,
|
||||||
user_action_status: 'role_confirmed',
|
user_action_status: TASK_STATUS.ROLE_CONFIRMED,
|
||||||
role_confirmed_at: now,
|
role_confirmed_at: now,
|
||||||
last_error: '',
|
last_error: '',
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
@@ -417,20 +424,20 @@ export async function redeemKuaishouCloudClaim(token: unknown) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentStatus = String(context.task.task_status || '').trim()
|
const currentStatus = normalizeTaskStatus(context.task.task_status)
|
||||||
if (['redeeming', 'dispatched_pending_return', 'completed', 'manual_review'].includes(currentStatus)) {
|
if (isKuaishouCloudRedeemSettledStatus(currentStatus)) {
|
||||||
return getKuaishouCloudClaimDetail(token)
|
return getKuaishouCloudClaimDetail(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentStatus !== 'role_confirmed') {
|
if (!canRedeemKuaishouCloudClaimStatus(currentStatus)) {
|
||||||
throw createHttpError('请先确认角色信息', {
|
throw createHttpError('请先确认角色信息', {
|
||||||
statusCode: 409,
|
statusCode: 409,
|
||||||
errorCode: 'claim_kuaishou_cloud_role_not_confirmed',
|
errorCode: 'claim_kuaishou_cloud_role_not_confirmed',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const lockedTask = await updateTaskStatusIfCurrent(context.task.id, 'role_confirmed', {
|
const lockedTask = await updateTaskStatusIfCurrent(context.task.id, TASK_STATUS.ROLE_CONFIRMED, {
|
||||||
task_status: 'redeeming',
|
task_status: TASK_STATUS.REDEEMING,
|
||||||
user_action_status: 'not_required',
|
user_action_status: 'not_required',
|
||||||
last_error: '',
|
last_error: '',
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
@@ -453,13 +460,13 @@ export async function redeemKuaishouCloudClaim(token: unknown) {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const latestTask = await getTaskById(lockedTask.id)
|
const latestTask = await getTaskById(lockedTask.id)
|
||||||
if (latestTask && String(latestTask.task_status || '').trim() !== 'redeeming') {
|
if (latestTask && normalizeTaskStatus(latestTask.task_status) !== TASK_STATUS.REDEEMING) {
|
||||||
return getKuaishouCloudClaimDetail(token)
|
return getKuaishouCloudClaimDetail(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = error instanceof Error ? error.message : '兑换请求提交失败,请联系客服处理'
|
const message = error instanceof Error ? error.message : '兑换请求提交失败,请联系客服处理'
|
||||||
await updateTask(lockedTask.id, {
|
await updateTask(lockedTask.id, {
|
||||||
task_status: 'manual_review',
|
task_status: TASK_STATUS.MANUAL_REVIEW,
|
||||||
user_action_status: 'not_required',
|
user_action_status: 'not_required',
|
||||||
last_error: message,
|
last_error: message,
|
||||||
result_code: 'kuaishou_cloud_redeem_failed',
|
result_code: 'kuaishou_cloud_redeem_failed',
|
||||||
@@ -569,7 +576,7 @@ async function completeMockKuaishouCloudClaimTask(task: TaskRow, timestamp: stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
await updateTask(task.id, {
|
await updateTask(task.id, {
|
||||||
task_status: 'completed',
|
task_status: TASK_STATUS.COMPLETED,
|
||||||
delivery_status: 'success',
|
delivery_status: 'success',
|
||||||
result_code: 'mock_success',
|
result_code: 'mock_success',
|
||||||
result_message: '开发 mock 已模拟兑换成功',
|
result_message: '开发 mock 已模拟兑换成功',
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
} from "../../notification/domain-notifications.js";
|
} from "../../notification/domain-notifications.js";
|
||||||
import { createHttpError } from "../../../utils/http.js";
|
import { createHttpError } from "../../../utils/http.js";
|
||||||
import { nowIso } from "../../../utils/time.js";
|
import { nowIso } from "../../../utils/time.js";
|
||||||
|
import { TASK_STATUS, normalizeTaskStatus } from "../../../domain/task-status.js";
|
||||||
import {
|
import {
|
||||||
KUAISHOU_CLOUD_FIXED_VN_KEY,
|
KUAISHOU_CLOUD_FIXED_VN_KEY,
|
||||||
isKuaishouCloudBindUrlFresh,
|
isKuaishouCloudBindUrlFresh,
|
||||||
@@ -126,9 +127,9 @@ export async function prepareKuaishouCloudFulfillmentTask(
|
|||||||
|
|
||||||
let readyTask = task;
|
let readyTask = task;
|
||||||
|
|
||||||
if (String(task.task_status || "").trim() !== "waiting_binding") {
|
if (normalizeTaskStatus(task.task_status) !== TASK_STATUS.WAITING_BINDING) {
|
||||||
readyTask = (await updateTask(task.id, {
|
readyTask = (await updateTask(task.id, {
|
||||||
task_status: "waiting_binding",
|
task_status: TASK_STATUS.WAITING_BINDING,
|
||||||
claim_token: claimLinkState.token || task.claim_token || "",
|
claim_token: claimLinkState.token || task.claim_token || "",
|
||||||
claim_expires_at:
|
claim_expires_at:
|
||||||
claimLinkState.expiredAt || getTaskClaimExpiresAt(task),
|
claimLinkState.expiredAt || getTaskClaimExpiresAt(task),
|
||||||
@@ -314,7 +315,7 @@ export async function prepareKuaishouCloudFulfillmentTask(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updatedTask = await updateTask(task.id, {
|
const updatedTask = await updateTask(task.id, {
|
||||||
task_status: "waiting_binding",
|
task_status: TASK_STATUS.WAITING_BINDING,
|
||||||
user_action_status: "pending_claim",
|
user_action_status: "pending_claim",
|
||||||
claim_token: claimLinkState.token || task.claim_token || "",
|
claim_token: claimLinkState.token || task.claim_token || "",
|
||||||
claim_expires_at: claimLinkState.expiredAt || getTaskClaimExpiresAt(task),
|
claim_expires_at: claimLinkState.expiredAt || getTaskClaimExpiresAt(task),
|
||||||
@@ -462,16 +463,16 @@ export async function refreshKuaishouCloudTaskBindUrl(
|
|||||||
bindProbeStatus: "pending",
|
bindProbeStatus: "pending",
|
||||||
bindProbeMessage: "",
|
bindProbeMessage: "",
|
||||||
roleName:
|
roleName:
|
||||||
String(task.task_status || "").trim() === "role_confirmed"
|
normalizeTaskStatus(task.task_status) === TASK_STATUS.ROLE_CONFIRMED
|
||||||
? flow.binding.roleName
|
? flow.binding.roleName
|
||||||
: "",
|
: "",
|
||||||
roleId:
|
roleId:
|
||||||
String(task.task_status || "").trim() === "role_confirmed"
|
normalizeTaskStatus(task.task_status) === TASK_STATUS.ROLE_CONFIRMED
|
||||||
? flow.binding.roleId
|
? flow.binding.roleId
|
||||||
: "",
|
: "",
|
||||||
},
|
},
|
||||||
role:
|
role:
|
||||||
String(task.task_status || "").trim() === "role_confirmed"
|
normalizeTaskStatus(task.task_status) === TASK_STATUS.ROLE_CONFIRMED
|
||||||
? flow.role
|
? flow.role
|
||||||
: {
|
: {
|
||||||
status: "pending",
|
status: "pending",
|
||||||
@@ -488,17 +489,17 @@ export async function refreshKuaishouCloudTaskBindUrl(
|
|||||||
options.claimLinkState || (await ensureTaskClaimLink(task));
|
options.claimLinkState || (await ensureTaskClaimLink(task));
|
||||||
const updatedTask = await updateTask(task.id, {
|
const updatedTask = await updateTask(task.id, {
|
||||||
task_status:
|
task_status:
|
||||||
String(task.task_status || "").trim() === "role_confirmed"
|
normalizeTaskStatus(task.task_status) === TASK_STATUS.ROLE_CONFIRMED
|
||||||
? task.task_status
|
? task.task_status
|
||||||
: "waiting_binding",
|
: TASK_STATUS.WAITING_BINDING,
|
||||||
claim_token: claimLinkState.token || task.claim_token || "",
|
claim_token: claimLinkState.token || task.claim_token || "",
|
||||||
claim_expires_at: claimLinkState.expiredAt || getTaskClaimExpiresAt(task),
|
claim_expires_at: claimLinkState.expiredAt || getTaskClaimExpiresAt(task),
|
||||||
role_id:
|
role_id:
|
||||||
String(task.task_status || "").trim() === "role_confirmed"
|
normalizeTaskStatus(task.task_status) === TASK_STATUS.ROLE_CONFIRMED
|
||||||
? task.role_id
|
? task.role_id
|
||||||
: "",
|
: "",
|
||||||
role_name:
|
role_name:
|
||||||
String(task.task_status || "").trim() === "role_confirmed"
|
normalizeTaskStatus(task.task_status) === TASK_STATUS.ROLE_CONFIRMED
|
||||||
? task.role_name
|
? task.role_name
|
||||||
: "",
|
: "",
|
||||||
last_error: "",
|
last_error: "",
|
||||||
@@ -665,7 +666,7 @@ async function markKuaishouCloudBindUrlRefreshFailed(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updatedTask = await updateTask(task.id, {
|
const updatedTask = await updateTask(task.id, {
|
||||||
task_status: "pending_binding_prepare",
|
task_status: TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
role_id: "",
|
role_id: "",
|
||||||
role_name: "",
|
role_name: "",
|
||||||
last_error: `绑定链接过期,旧号码已退还,新链接准备失败:${errorMessage}`,
|
last_error: `绑定链接过期,旧号码已退还,新链接准备失败:${errorMessage}`,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { createTaskEvent } from "../../../repositories/task-event-repo.js";
|
|||||||
import { updateTask } from "../../../repositories/task-repo.js";
|
import { updateTask } from "../../../repositories/task-repo.js";
|
||||||
import { createHttpError } from "../../../utils/http.js";
|
import { createHttpError } from "../../../utils/http.js";
|
||||||
import { nowIso } from "../../../utils/time.js";
|
import { nowIso } from "../../../utils/time.js";
|
||||||
|
import { TASK_STATUS, normalizeTaskStatus, type TaskStatus } from "../../../domain/task-status.js";
|
||||||
import { notifyKuaishouCloudConsumeFailed } from "../../notification/domain-notifications.js";
|
import { notifyKuaishouCloudConsumeFailed } from "../../notification/domain-notifications.js";
|
||||||
import { useCloudtentaclesSku } from "../../platforms/cloudtentacles/catalog-service.js";
|
import { useCloudtentaclesSku } from "../../platforms/cloudtentacles/catalog-service.js";
|
||||||
import { backCloudtentaclesVirtualNumber } from "../../platforms/cloudtentacles/virtual-number-service.js";
|
import { backCloudtentaclesVirtualNumber } from "../../platforms/cloudtentacles/virtual-number-service.js";
|
||||||
@@ -78,7 +79,7 @@ export async function dispatchKuaishouCloudFulfillmentTask(
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
flow.dispatch.status === "success" &&
|
flow.dispatch.status === "success" &&
|
||||||
String(task.task_status || "").trim() === "dispatched_pending_return"
|
normalizeTaskStatus(task.task_status) === TASK_STATUS.DISPATCHED_PENDING_RETURN
|
||||||
) {
|
) {
|
||||||
return { task, flow };
|
return { task, flow };
|
||||||
}
|
}
|
||||||
@@ -163,7 +164,7 @@ export async function dispatchKuaishouCloudFulfillmentTask(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let updatedTask = await updateTask(task.id, {
|
let updatedTask = await updateTask(task.id, {
|
||||||
task_status: "dispatched_pending_return",
|
task_status: TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
delivery_status: "delivered",
|
delivery_status: "delivered",
|
||||||
result_code: "kuaishou_cloud_dispatched",
|
result_code: "kuaishou_cloud_dispatched",
|
||||||
result_message: dispatchSummary,
|
result_message: dispatchSummary,
|
||||||
@@ -285,11 +286,10 @@ export async function returnKuaishouCloudFulfillmentTask(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const taskStatus = normalizeTaskStatus(task.task_status);
|
||||||
if (
|
if (
|
||||||
flow.returnNumber.status === "success" &&
|
flow.returnNumber.status === "success" &&
|
||||||
["completed", "manual_review"].includes(
|
(taskStatus === TASK_STATUS.COMPLETED || taskStatus === TASK_STATUS.MANUAL_REVIEW)
|
||||||
String(task.task_status || "").trim()
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
return { task, flow };
|
return { task, flow };
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,7 @@ export async function returnKuaishouCloudFulfillmentTask(
|
|||||||
let consumeStatus = "pending";
|
let consumeStatus = "pending";
|
||||||
let consumeErrorMessage = "";
|
let consumeErrorMessage = "";
|
||||||
let consumedAt = null;
|
let consumedAt = null;
|
||||||
let nextTaskStatus = "completed";
|
let nextTaskStatus: TaskStatus = TASK_STATUS.COMPLETED;
|
||||||
let nextResultCode = "kuaishou_cloud_completed";
|
let nextResultCode = "kuaishou_cloud_completed";
|
||||||
let nextResultMessage = "cloudtentacles 发货、退号并完成快手核销";
|
let nextResultMessage = "cloudtentacles 发货、退号并完成快手核销";
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ export async function returnKuaishouCloudFulfillmentTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (consumeStatus !== "success") {
|
if (consumeStatus !== "success") {
|
||||||
nextTaskStatus = "manual_review";
|
nextTaskStatus = TASK_STATUS.MANUAL_REVIEW;
|
||||||
nextResultCode = "kuaishou_cloud_consume_failed";
|
nextResultCode = "kuaishou_cloud_consume_failed";
|
||||||
nextResultMessage =
|
nextResultMessage =
|
||||||
consumeErrorMessage || "号码已退还,但快手核销未完成,请人工处理";
|
consumeErrorMessage || "号码已退还,但快手核销未完成,请人工处理";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
OPEN_91_DEFAULT_FAIL_CODE,
|
OPEN_91_DEFAULT_FAIL_CODE,
|
||||||
OPEN_91_SUCCESS_MESSAGE,
|
OPEN_91_SUCCESS_MESSAGE,
|
||||||
} from './config.js'
|
} from './config.js'
|
||||||
|
import { isOpen91FailedTaskStatus } from '../../domain/task-status.js'
|
||||||
import { normalizeOpen91String } from './payload.js'
|
import { normalizeOpen91String } from './payload.js'
|
||||||
|
|
||||||
type JsonObject = Record<string, any>
|
type JsonObject = Record<string, any>
|
||||||
@@ -88,7 +89,7 @@ export function resolveOpen91QueryState(
|
|||||||
|
|
||||||
const failedTask = normalizedTasks.find((task) => {
|
const failedTask = normalizedTasks.find((task) => {
|
||||||
const status = normalizeOpen91String(task?.task_status)
|
const status = normalizeOpen91String(task?.task_status)
|
||||||
return ['failed', 'manual_review', 'closed'].includes(status) && !readyTaskIdSet.has(Number(task?.id || 0))
|
return isOpen91FailedTaskStatus(status) && !readyTaskIdSet.has(Number(task?.id || 0))
|
||||||
})
|
})
|
||||||
|
|
||||||
if (failedTask) {
|
if (failedTask) {
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ import { createTaskClaimToken } from '../claim/claim-service.js'
|
|||||||
import { notifyTaskAutoManualReview } from '../notification/domain-notifications.js'
|
import { notifyTaskAutoManualReview } from '../notification/domain-notifications.js'
|
||||||
import { nowIso } from '../../utils/time.js'
|
import { nowIso } from '../../utils/time.js'
|
||||||
import { randomId } from '../../utils/random.js'
|
import { randomId } from '../../utils/random.js'
|
||||||
|
import {
|
||||||
|
TASK_STATUS,
|
||||||
|
isPaidPreparationStableStatus,
|
||||||
|
resolveInitialPaidTaskStatus,
|
||||||
|
shouldEnsureKuaishouCloudClaimLink,
|
||||||
|
} from '../../domain/task-status.js'
|
||||||
import type { OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
|
import type { OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>
|
type JsonObject = Record<string, unknown>
|
||||||
@@ -130,7 +136,7 @@ export async function syncDeliveryTasksForOrderWithDeps(
|
|||||||
const createdAt = getNowIso()
|
const createdAt = getNowIso()
|
||||||
const initialStatus = order.pay_status === 'paid'
|
const initialStatus = order.pay_status === 'paid'
|
||||||
? resolvePaidTaskStatus(profile)
|
? resolvePaidTaskStatus(profile)
|
||||||
: 'pending_payment'
|
: TASK_STATUS.PENDING_PAYMENT
|
||||||
|
|
||||||
const task = await createDeliveryTask({
|
const task = await createDeliveryTask({
|
||||||
orderId: order.id,
|
orderId: order.id,
|
||||||
@@ -271,19 +277,12 @@ async function preparePaidTask(
|
|||||||
|
|
||||||
const now = getNowIso()
|
const now = getNowIso()
|
||||||
|
|
||||||
if (['link_generated', 'claimed', 'role_confirmed', 'redeeming', 'redeemed', 'closed'].includes(task.task_status)) {
|
if (isPaidPreparationStableStatus(task.task_status)) {
|
||||||
return task
|
return task
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isKuaishouCloudExecutor(task.executor_key)) {
|
if (isKuaishouCloudExecutor(task.executor_key)) {
|
||||||
if ([
|
if (shouldEnsureKuaishouCloudClaimLink(task.task_status)) {
|
||||||
'pending_binding_prepare',
|
|
||||||
'waiting_binding',
|
|
||||||
'dispatched_pending_return',
|
|
||||||
'completed',
|
|
||||||
'manual_review',
|
|
||||||
'failed',
|
|
||||||
].includes(String(task.task_status || '').trim())) {
|
|
||||||
if (!task.primary_claim_token_id && !String(task.claim_token || '').trim()) {
|
if (!task.primary_claim_token_id && !String(task.claim_token || '').trim()) {
|
||||||
const claimToken = await createClaimToken(task.id)
|
const claimToken = await createClaimToken(task.id)
|
||||||
return updateDeliveryTask(task.id, {
|
return updateDeliveryTask(task.id, {
|
||||||
@@ -300,7 +299,7 @@ async function preparePaidTask(
|
|||||||
const claimToken = await createClaimToken(task.id)
|
const claimToken = await createClaimToken(task.id)
|
||||||
|
|
||||||
return updateDeliveryTask(task.id, {
|
return updateDeliveryTask(task.id, {
|
||||||
task_status: 'pending_binding_prepare',
|
task_status: TASK_STATUS.PENDING_BINDING_PREPARE,
|
||||||
claim_token: claimToken.token,
|
claim_token: claimToken.token,
|
||||||
claim_expires_at: claimToken.expired_at,
|
claim_expires_at: claimToken.expired_at,
|
||||||
user_action_status: 'pending_claim',
|
user_action_status: 'pending_claim',
|
||||||
@@ -312,7 +311,7 @@ async function preparePaidTask(
|
|||||||
if (!task.requires_claim || String(task.executor_key || '').trim() === 'manual_dispatch') {
|
if (!task.requires_claim || String(task.executor_key || '').trim() === 'manual_dispatch') {
|
||||||
const lastError = task.last_error || '当前任务需要人工履约处理'
|
const lastError = task.last_error || '当前任务需要人工履约处理'
|
||||||
const updatedTask = await updateDeliveryTask(task.id, {
|
const updatedTask = await updateDeliveryTask(task.id, {
|
||||||
task_status: 'manual_review',
|
task_status: TASK_STATUS.MANUAL_REVIEW,
|
||||||
user_action_status: 'not_required',
|
user_action_status: 'not_required',
|
||||||
last_error: lastError,
|
last_error: lastError,
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
@@ -329,19 +328,7 @@ async function preparePaidTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolvePaidTaskStatus(profile: FulfillmentBindingLike | null | undefined): string {
|
function resolvePaidTaskStatus(profile: FulfillmentBindingLike | null | undefined): string {
|
||||||
if (Boolean(profile?.requires_claim)) {
|
return resolveInitialPaidTaskStatus(profile)
|
||||||
return 'paid'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isKuaishouCloudExecutor(profile?.executor_key)) {
|
|
||||||
return 'pending_binding_prepare'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (String(profile?.executor_key || '').trim() === 'manual_dispatch') {
|
|
||||||
return 'manual_review'
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'paid'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTaskContext(task: { context_json?: unknown } | null | undefined): TaskContext {
|
function parseTaskContext(task: { context_json?: unknown } | null | undefined): TaskContext {
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
export const TASK_STATUS = {
|
||||||
|
PENDING_PAYMENT: "pending_payment",
|
||||||
|
PAID: "paid",
|
||||||
|
LINK_GENERATED: "link_generated",
|
||||||
|
CLAIMED: "claimed",
|
||||||
|
PENDING_BINDING_PREPARE: "pending_binding_prepare",
|
||||||
|
WAITING_BINDING: "waiting_binding",
|
||||||
|
ROLE_CONFIRMED: "role_confirmed",
|
||||||
|
REDEEMING: "redeeming",
|
||||||
|
DISPATCHED_PENDING_RETURN: "dispatched_pending_return",
|
||||||
|
COMPLETED: "completed",
|
||||||
|
REDEEMED: "redeemed",
|
||||||
|
RETRY_PENDING: "retry_pending",
|
||||||
|
MANUAL_REVIEW: "manual_review",
|
||||||
|
FAILED: "failed",
|
||||||
|
EXPIRED: "expired",
|
||||||
|
CLOSED: "closed",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type KnownTaskStatus = (typeof TASK_STATUS)[keyof typeof TASK_STATUS];
|
||||||
|
export type TaskStatus = KnownTaskStatus | (string & {});
|
||||||
|
|
||||||
|
const CLAIM_INACTIVE_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.FAILED,
|
||||||
|
TASK_STATUS.EXPIRED,
|
||||||
|
TASK_STATUS.CLOSED,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const KUAISHOU_CLOUD_RESULT_STATUSES = new Set<TaskStatus>([
|
||||||
|
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||||
|
TASK_STATUS.COMPLETED,
|
||||||
|
TASK_STATUS.REDEEMED,
|
||||||
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
|
TASK_STATUS.FAILED,
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function normalizeTaskStatus(value: unknown): TaskStatus {
|
||||||
|
return String(value || "").trim() as TaskStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isClaimInactiveTaskStatus(status: unknown): boolean {
|
||||||
|
return CLAIM_INACTIVE_STATUSES.has(normalizeTaskStatus(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isKuaishouCloudRoleConfirmedStatus(status: unknown): boolean {
|
||||||
|
return normalizeTaskStatus(status) === TASK_STATUS.ROLE_CONFIRMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isKuaishouCloudCompletedStatus(status: unknown): boolean {
|
||||||
|
const normalized = normalizeTaskStatus(status);
|
||||||
|
return normalized === TASK_STATUS.COMPLETED || normalized === TASK_STATUS.REDEEMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasKuaishouCloudRedeemResultStatus(status: unknown): boolean {
|
||||||
|
return KUAISHOU_CLOUD_RESULT_STATUSES.has(normalizeTaskStatus(status));
|
||||||
|
}
|
||||||
@@ -1,23 +1,8 @@
|
|||||||
|
import type { KnownTaskStatus } from '@/domain/task-status'
|
||||||
|
|
||||||
export type ClaimTokenStatus = 'active' | 'used' | 'expired' | 'revoked' | (string & {})
|
export type ClaimTokenStatus = 'active' | 'used' | 'expired' | 'revoked' | (string & {})
|
||||||
|
|
||||||
export type ClaimTaskStatus =
|
export type ClaimTaskStatus = KnownTaskStatus | (string & {})
|
||||||
| 'pending_payment'
|
|
||||||
| 'paid'
|
|
||||||
| 'pending_binding_prepare'
|
|
||||||
| 'waiting_binding'
|
|
||||||
| 'dispatched_pending_return'
|
|
||||||
| 'completed'
|
|
||||||
| 'failed'
|
|
||||||
| 'link_generated'
|
|
||||||
| 'claimed'
|
|
||||||
| 'role_confirmed'
|
|
||||||
| 'redeeming'
|
|
||||||
| 'redeemed'
|
|
||||||
| 'retry_pending'
|
|
||||||
| 'manual_review'
|
|
||||||
| 'expired'
|
|
||||||
| 'closed'
|
|
||||||
| (string & {})
|
|
||||||
|
|
||||||
export interface ClaimTaskInfo {
|
export interface ClaimTaskInfo {
|
||||||
taskId: number
|
taskId: number
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ import QRCode from "qrcode";
|
|||||||
import { ElMessageBox } from "element-plus";
|
import { ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
import { showError, showSuccess } from "@/lib/feedback";
|
import { showError, showSuccess } from "@/lib/feedback";
|
||||||
|
import {
|
||||||
|
hasKuaishouCloudRedeemResultStatus,
|
||||||
|
isClaimInactiveTaskStatus,
|
||||||
|
isKuaishouCloudCompletedStatus,
|
||||||
|
isKuaishouCloudRoleConfirmedStatus,
|
||||||
|
} from "@/domain/task-status";
|
||||||
import { formatAdminDateTime } from "@/utils/admin-time";
|
import { formatAdminDateTime } from "@/utils/admin-time";
|
||||||
import {
|
import {
|
||||||
confirmKuaishouCloudClaimRole,
|
confirmKuaishouCloudClaimRole,
|
||||||
@@ -75,7 +81,7 @@ export function useKuaishouCloudClaim(token: () => string) {
|
|||||||
const canEnterBindingStep = computed(() => isTicketVerified.value);
|
const canEnterBindingStep = computed(() => isTicketVerified.value);
|
||||||
const isRoleReady = computed(() => Boolean(roleName.value || roleId.value));
|
const isRoleReady = computed(() => Boolean(roleName.value || roleId.value));
|
||||||
const isRoleConfirmed = computed(
|
const isRoleConfirmed = computed(
|
||||||
() => String(task.value?.status || "").trim() === "role_confirmed"
|
() => isKuaishouCloudRoleConfirmedStatus(task.value?.status)
|
||||||
);
|
);
|
||||||
const isDispatched = computed(
|
const isDispatched = computed(
|
||||||
() => String(flow.value?.dispatch.status || "").trim() === "success"
|
() => String(flow.value?.dispatch.status || "").trim() === "success"
|
||||||
@@ -83,28 +89,17 @@ export function useKuaishouCloudClaim(token: () => string) {
|
|||||||
|
|
||||||
const isCompleted = computed(
|
const isCompleted = computed(
|
||||||
() =>
|
() =>
|
||||||
String(task.value?.status || "").trim() === "completed" ||
|
isKuaishouCloudCompletedStatus(task.value?.status) ||
|
||||||
String(flow.value?.consume.status || "").trim() === "success"
|
String(flow.value?.consume.status || "").trim() === "success"
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasRedeemResult = computed(() => {
|
const hasRedeemResult = computed(() => {
|
||||||
const status = String(task.value?.status || "").trim();
|
return isDispatched.value || hasKuaishouCloudRedeemResultStatus(task.value?.status);
|
||||||
return (
|
|
||||||
isDispatched.value ||
|
|
||||||
[
|
|
||||||
"dispatched_pending_return",
|
|
||||||
"completed",
|
|
||||||
"manual_review",
|
|
||||||
"failed",
|
|
||||||
].includes(status)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const canSubmitTicket = computed(
|
const canSubmitTicket = computed(
|
||||||
() =>
|
() =>
|
||||||
!["completed", "manual_review", "closed", "expired"].includes(
|
!isClaimInactiveTaskStatus(task.value?.status) && !submitting.value
|
||||||
String(task.value?.status || "").trim()
|
|
||||||
) && !submitting.value
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentStep = computed(() => {
|
const currentStep = computed(() => {
|
||||||
@@ -323,12 +318,10 @@ export function useKuaishouCloudClaim(token: () => string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveNextPollDelay() {
|
function resolveNextPollDelay() {
|
||||||
const taskStatus = String(task.value?.status || "").trim();
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!flow.value ||
|
!flow.value ||
|
||||||
hasRedeemResult.value ||
|
hasRedeemResult.value ||
|
||||||
["closed", "expired", "manual_review", "failed"].includes(taskStatus)
|
isClaimInactiveTaskStatus(task.value?.status)
|
||||||
) {
|
) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user