import { getTaskById } from '../../repositories/task-repo.js' import { createHttpError } from '../../utils/http.js' import { safeParseJson } from './admin-query-utils.js' import { createAdminViewerContext, getTaskPrimaryClaimTokenId, } from './admin-read-shared-helpers.js' import type { AdminTaskBindingSummary, AdminTaskListItem, } from '../../types/admin/read-models.js' import type { AdminTaskActionPayload } from '../../types/admin/write-models.js' import type { TaskEventRow, TaskRow, } from '../../types/repository/rows.js' import type { AdminViewerContext } from './admin-read-shared-helpers.js' type JsonRecord = Record type TaskBindingState = { systemBindingStatus: string userBindingStatus: string } type OrderBindingSummary = { totalTaskCount: number systemBoundTaskCount: number completedBindingTaskCount: number totalBindingCount: number reservedBindingCount: number consumedBindingCount: number releasedBindingCount: number systemBindingStatus: string userBindingStatus: string } export function mapAdminTaskSummary( task: TaskRow, bindingSummary: AdminTaskBindingSummary = createEmptyTaskBindingSummary(), ): JsonRecord { const binding = buildTaskBindingState(task) return { taskId: task.id, taskNo: task.task_no, deliveryStatus: task.delivery_status || '', status: task.task_status, systemBindingStatus: binding.systemBindingStatus, userBindingStatus: binding.userBindingStatus, loginType: task.login_type, runtimeSessionId: task.runtime_session_id, claimedAt: task.claimed_at, roleConfirmedAt: task.role_confirmed_at, redeemedAt: task.redeemed_at, lastError: task.last_error, retryCount: getTaskRetryCount(task), bindingSummary, createdAt: task.created_at, updatedAt: task.updated_at, } } export function mapTaskActionPayload(task: any): AdminTaskActionPayload { const primaryClaimTokenId = getTaskPrimaryClaimTokenId(task) return { taskId: task.id, taskNo: task.task_no, status: task.task_status, deliveryStatus: task.delivery_status, resultCode: task.result_code, resultMessage: task.result_message, primaryClaimTokenId, lastError: task.last_error, updatedAt: task.updated_at, } } export async function getRequiredTask(taskId: number | string): Promise { const task = await getTaskById(Number(taskId)) if (!task) { throw createHttpError('任务不存在', { statusCode: 404, errorCode: 'admin_task_not_found', }) } return task } export function mapAdminTaskListItem( task: TaskRow, viewerContext: AdminViewerContext = createAdminViewerContext(), ): AdminTaskListItem { const binding = buildTaskBindingState(task) const bindingSummary = createEmptyTaskBindingSummary() return { taskId: task.id, taskNo: task.task_no, platformOrderId: task.platform_order_id, skuCode: task.sku_code || '', skuName: task.sku_name || '', status: task.task_status, executorKey: task.executor_key || '', deliveryStatus: task.delivery_status || '', resultCode: task.result_code || '', resultMessage: task.result_message || '', systemBindingStatus: binding.systemBindingStatus, userBindingStatus: binding.userBindingStatus, loginType: task.login_type, roleName: task.role_name, roleId: task.role_id, runtimeSessionId: task.runtime_session_id, claimedAt: task.claimed_at, roleConfirmedAt: task.role_confirmed_at, redeemedAt: task.redeemed_at, retryCount: getTaskRetryCount(task), bindingSummary, lastError: task.last_error, createdAt: task.created_at, updatedAt: task.updated_at, claimToken: viewerContext.canViewSensitiveTaskData ? (task.primary_claim_token || task.claim_token || '') : '', screenshotPath: viewerContext.role === 'support' ? '' : (task.screenshot_path || ''), } } export function mapAdminTaskEvent(event: TaskEventRow): JsonRecord { const payload = safeParseJson(event.payload_json) return { eventId: event.id, eventType: String(event.event_type || '').trim(), payload: normalizeRecord(payload), createdAt: event.created_at, } } export function createEmptyTaskBindingSummary(): AdminTaskBindingSummary { return { totalBindingCount: 0, reservedBindingCount: 0, consumedBindingCount: 0, releasedBindingCount: 0, roleKeys: [], } } export function buildOrderBindingSummary( tasks: TaskRow[] | null | undefined, ): OrderBindingSummary { const normalizedTasks = Array.isArray(tasks) ? tasks : [] const totalTaskCount = normalizedTasks.length const taskBindings = normalizedTasks.map((task) => buildTaskBindingState(task)) const systemBoundTaskCount = normalizedTasks.filter((task) => isTaskSystemBound(task)).length const completedBindingTaskCount = normalizedTasks.filter((task) => String(task?.task_status || '') === 'redeemed').length const totalBindingCount = 0 const reservedBindingCount = 0 const consumedBindingCount = 0 const releasedBindingCount = 0 let systemBindingStatus = 'pending_binding' let userBindingStatus = 'not_started' if (totalTaskCount === 0) { return { totalTaskCount, systemBoundTaskCount, completedBindingTaskCount, totalBindingCount, reservedBindingCount, consumedBindingCount, releasedBindingCount, systemBindingStatus, userBindingStatus, } } if (normalizedTasks.every((task) => String(task.task_status || '') === 'redeemed')) { systemBindingStatus = 'system_bound' userBindingStatus = 'binding_completed' } else if (taskBindings.some((item) => ['binding_in_progress', 'binding_confirmed', 'link_opened'].includes(item.userBindingStatus))) { systemBindingStatus = systemBoundTaskCount > 0 ? 'system_bound' : 'pending_binding' userBindingStatus = 'user_binding' } else if (taskBindings.some((item) => item.userBindingStatus === 'waiting_user_claim')) { systemBindingStatus = systemBoundTaskCount > 0 ? 'system_bound' : 'pending_binding' userBindingStatus = 'waiting_user_claim' } else if (taskBindings.some((item) => item.userBindingStatus === 'binding_exception')) { systemBindingStatus = systemBoundTaskCount > 0 ? 'system_bound' : 'pending_binding' userBindingStatus = 'binding_exception' } else if (systemBoundTaskCount > 0) { systemBindingStatus = 'system_bound' } else if (taskBindings.some((item) => ['manual_review', 'retry_pending'].includes(item.systemBindingStatus))) { systemBindingStatus = 'binding_exception' } return { totalTaskCount, systemBoundTaskCount, completedBindingTaskCount, totalBindingCount, reservedBindingCount, consumedBindingCount, releasedBindingCount, systemBindingStatus, userBindingStatus, } } function buildTaskBindingState(task: TaskRow | null | undefined): TaskBindingState { const normalizedStatus = String(task?.task_status || '').trim() if (!normalizedStatus) { return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started', } } if (normalizedStatus === 'pending_payment') { return { systemBindingStatus: 'pending_payment', userBindingStatus: 'not_started' } } if (normalizedStatus === 'paid') { return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started' } } if (normalizedStatus === 'pending_binding_prepare') { return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started' } } if (normalizedStatus === 'waiting_binding') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'waiting_user_claim' } } if (normalizedStatus === 'dispatched_pending_return') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_completed' } } if (normalizedStatus === 'completed') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_completed' } } if (normalizedStatus === 'manual_review') { return { systemBindingStatus: 'manual_review', userBindingStatus: 'binding_exception' } } if (normalizedStatus === 'retry_pending') { return { systemBindingStatus: 'retry_pending', userBindingStatus: 'binding_exception' } } if (normalizedStatus === 'closed') { return { systemBindingStatus: 'closed', userBindingStatus: 'closed' } } if (normalizedStatus === 'expired') { return { systemBindingStatus: 'expired', userBindingStatus: 'expired' } } if (normalizedStatus === 'link_generated') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'waiting_user_claim' } } if (normalizedStatus === 'claimed') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'link_opened' } } if (normalizedStatus === 'role_confirmed') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_confirmed' } } if (normalizedStatus === 'redeeming') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_in_progress' } } if (normalizedStatus === 'redeemed') { return { systemBindingStatus: 'system_bound', userBindingStatus: 'binding_completed' } } if (isTaskSystemBound(task)) { return { systemBindingStatus: 'system_bound', userBindingStatus: 'waiting_user_claim' } } return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started' } } function isTaskSystemBound(task: TaskRow | null | undefined): boolean { return Boolean(task && getTaskPrimaryClaimTokenId(task)) } function normalizeRecord(value: unknown): JsonRecord { return value && typeof value === 'object' && !Array.isArray(value) ? value : {} } function getTaskRetryCount(task: TaskRow | null | undefined): number { return Number(task?.attempt_count || 0) }