diff --git a/apps/backend/src/repositories/kuaishou-cloud-task-state-repo.test.ts b/apps/backend/src/repositories/kuaishou-cloud-task-state-repo.test.ts new file mode 100644 index 00000000..76b0620c --- /dev/null +++ b/apps/backend/src/repositories/kuaishou-cloud-task-state-repo.test.ts @@ -0,0 +1,43 @@ +import assert from 'node:assert/strict' +import test from 'node:test' + +import { syncKuaishouCloudTaskStateForTask } from './kuaishou-cloud-task-state-repo.js' + +test('syncKuaishouCloudTaskStateForTask 将 Date 更新时间规范化为 ISO 字符串', async () => { + const calls: Array<{ text: string; params?: unknown[] }> = [] + const executor = async (text: string, params?: unknown[]) => { + calls.push({ text, params }) + return { rows: [] } + } + + await syncKuaishouCloudTaskStateForTask({ + taskId: 9, + executorKey: 'kuaishou_ct_assisted', + contextJson: { + kuaishouCloudFulfillment: { + ticket: { + status: 'verified', + code: '597172E91CF18417', + }, + binding: { + bindUrl: 'https://example.test/bind', + vnPhone: '14062706492', + roleName: '测试角色', + roleId: '4212063544', + resolvedSourceKey: 'account_test', + }, + dispatch: { + status: 'pending', + }, + consume: { + status: 'pending', + }, + }, + }, + updatedAt: new Date('2026-05-29T09:05:46.658Z'), + }, executor) + + assert.equal(calls.length, 1) + assert.match(calls[0].text, /INSERT INTO kuaishou_cloud_task_states/) + assert.equal(calls[0].params?.[10], '2026-05-29T09:05:46.658Z') +}) diff --git a/apps/backend/src/repositories/kuaishou-cloud-task-state-repo.ts b/apps/backend/src/repositories/kuaishou-cloud-task-state-repo.ts index f925899b..539e3d95 100644 --- a/apps/backend/src/repositories/kuaishou-cloud-task-state-repo.ts +++ b/apps/backend/src/repositories/kuaishou-cloud-task-state-repo.ts @@ -1,6 +1,7 @@ import { query } from '../db/client.js' import { maskCode } from '../utils/masking.js' import { parseTaskContext } from '../utils/task-json.js' +import { normalizeTimestampIso } from '../utils/time.js' type QueryExecutor = (text: string, params?: unknown[]) => Promise<{ rows: unknown[] }> type JsonRecord = Record @@ -39,7 +40,7 @@ export async function syncKuaishouCloudTaskStateForTask( const consume = asRecord(flow.consume) const roleName = pickFirstNonEmpty([role.name, binding.roleName]) const roleId = pickFirstNonEmpty([role.rid, binding.roleId]) - const updatedAt = String(input.updatedAt || '').trim() || new Date().toISOString() + const updatedAt = normalizeTimestampIso(input.updatedAt) await executor( ` diff --git a/apps/backend/src/repositories/task-repo.ts b/apps/backend/src/repositories/task-repo.ts index 420e91b9..ac9fd781 100644 --- a/apps/backend/src/repositories/task-repo.ts +++ b/apps/backend/src/repositories/task-repo.ts @@ -2,6 +2,7 @@ import { query, withTransaction } from '../db/client.js' import type { PoolClient } from 'pg' import { syncKuaishouCloudTaskStateForTask } from './kuaishou-cloud-task-state-repo.js' +import { normalizeTimestampIso } from '../utils/time.js' import type { TaskCreateInput, TaskListQueryInput, @@ -245,7 +246,7 @@ export async function updateTaskStatusIfCurrent( currentStatus: string, patch: TaskUpdatePatch, ): Promise { - const now = String(patch.updated_at || '').trim() + const now = normalizeTimestampIso(patch.updated_at, '') return withTransaction(async (client) => { const result = await client.query<{ id: number diff --git a/apps/backend/src/utils/time.ts b/apps/backend/src/utils/time.ts index 8e5a9fac..78122d0e 100644 --- a/apps/backend/src/utils/time.ts +++ b/apps/backend/src/utils/time.ts @@ -6,3 +6,18 @@ export function addHours(baseIso: string | null | undefined, hours: number): str const baseTime = baseIso ? new Date(baseIso).getTime() : Date.now() return new Date(baseTime + hours * 60 * 60 * 1000).toISOString() } + +export function normalizeTimestampIso(value: unknown, fallbackIso = nowIso()): string { + if (value instanceof Date) { + const timestamp = value.getTime() + return Number.isFinite(timestamp) ? value.toISOString() : fallbackIso + } + + const normalized = String(value || '').trim() + if (!normalized) { + return fallbackIso + } + + const timestamp = Date.parse(normalized) + return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : fallbackIso +}