Files
order_site/apps/backend/src/domain/task-status.ts
T
yml2213 81ae04dae0 接入 ESLint 并清理未使用代码
- 前后端接入 ESLint 10 扁平配置(typescript-eslint 类型感知检查 + react-hooks/react-refresh),新增 lint / lint:check / lint:fix 脚本并纳入 check 链路
- 清理全部 no-unused-vars 与 no-useless-assignment 警告,修复 floating promises、正则转义等问题
- 删除确认无引用的死代码(markKuaishouCloudBindUrlRefreshFailed、未使用 helper 等)
2026-08-16 18:04:55 +08:00

329 lines
9.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.WAITING_BINDING,
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,
])
const KUAISHOU_CLOUD_REBINDABLE_STATUSES = new Set<TaskStatus>([
TASK_STATUS.WAITING_BINDING,
TASK_STATUS.ROLE_CONFIRMED,
TASK_STATUS.MANUAL_REVIEW,
TASK_STATUS.RETRY_PENDING,
])
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 {
const normalized = normalizeTaskStatus(status)
// 允许 WAITING_BINDING:UID 匹配后可一键确认+兑换
return normalized === TASK_STATUS.ROLE_CONFIRMED || normalized === TASK_STATUS.WAITING_BINDING
}
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 canRebindKuaishouCloudRoleStatus(status: unknown): boolean {
return KUAISHOU_CLOUD_REBINDABLE_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 (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
}