diff --git a/apps/backend/src/services/admin/write/task-actions.js b/apps/backend/src/services/admin/write/task-actions.ts similarity index 85% rename from apps/backend/src/services/admin/write/task-actions.js rename to apps/backend/src/services/admin/write/task-actions.ts index c7d64eee..b65f6ad3 100644 --- a/apps/backend/src/services/admin/write/task-actions.js +++ b/apps/backend/src/services/admin/write/task-actions.ts @@ -1,5 +1,3 @@ -// @ts-check - import { markInventoryItemDelivered, releaseReservedInventoryItem, @@ -41,15 +39,31 @@ import { resolveTaskInventoryGroupCodes, } from './shared.js' -/** @typedef {import('../../../types/admin-read-inputs.js').AdminEntityIdInput} AdminEntityIdInput */ -/** @typedef {import('../../../types/admin-read-inputs.js').AdminViewerSessionInput} AdminViewerSessionInput */ -/** @typedef {import('../../../types/admin-write-models.js').AdminTaskActionResponse} AdminTaskActionResponse */ -/** @typedef {import('../../../types/admin-write-models.js').AdminTaskBindingReleaseResponse} AdminTaskBindingReleaseResponse */ -/** @typedef {import('../../../types/admin-write-models.js').AdminTaskManualDispatchResponse} AdminTaskManualDispatchResponse */ +import type { + AdminEntityIdInput, + AdminViewerSessionInput, +} from '../../../types/admin-read-inputs.js' +import type { AdminTaskManualDispatchInput } from '../../../types/admin-write-inputs.js' +import type { + AdminTaskActionResponse, + AdminTaskBindingReleaseResponse, + AdminTaskManualDispatchResponse, +} from '../../../types/admin-write-models.js' +import type { TaskRow } from '../../../types/repository-rows.js' +import type { TaskUpdatePatch } from '../../../types/repository-inputs.js' -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -export async function releaseAdminTaskInventory(taskId) { +type CloseAdminTaskDeps = { + getRequiredTask?: (taskId: AdminEntityIdInput) => Promise + listTaskInventoryBindingsByTaskId?: (taskId: AdminEntityIdInput) => Promise + releaseReservedInventoryItem?: (inventoryItemId: AdminEntityIdInput, updatedAt: string) => Promise + updateClaimToken?: (tokenId: AdminEntityIdInput, patch: Record) => Promise + updateTask?: (taskId: AdminEntityIdInput, patch: TaskUpdatePatch) => Promise + createTaskEvent?: (taskId: AdminEntityIdInput, eventType: string, payload: Record, createdAt: string) => Promise + closeTencentBrowserSession?: (sessionId: string) => Promise + nowIso?: () => string +} + +export async function releaseAdminTaskInventory(taskId: AdminEntityIdInput): Promise { const task = await getRequiredTask(taskId) const primaryInventoryItemId = getTaskPrimaryInventoryItemId(task) @@ -81,10 +95,10 @@ export async function releaseAdminTaskInventory(taskId) { } } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -/** @param {AdminEntityIdInput} bindingId */ -export async function releaseAdminTaskInventoryBinding(taskId, bindingId) { +export async function releaseAdminTaskInventoryBinding( + taskId: AdminEntityIdInput, + bindingId: AdminEntityIdInput, +): Promise { const task = await getRequiredTask(taskId) const binding = await getTaskInventoryBindingById(Number(bindingId)) @@ -151,10 +165,10 @@ export async function releaseAdminTaskInventoryBinding(taskId, bindingId) { } } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -/** @param {AdminViewerSessionInput | null} [session] */ -export async function regenerateAdminTaskClaimLink(taskId, session = null) { +export async function regenerateAdminTaskClaimLink( + taskId: AdminEntityIdInput, + session: AdminViewerSessionInput | null = null, +): Promise { const task = await getRequiredTask(taskId) const primaryClaimTokenId = getTaskPrimaryClaimTokenId(task) const viewerContext = createAdminViewerContext(session) @@ -204,10 +218,10 @@ export async function regenerateAdminTaskClaimLink(taskId, session = null) { } } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -/** @param {AdminViewerSessionInput | null} [session] */ -export async function confirmAdminTaskAssistedRole(taskId, session = null) { +export async function confirmAdminTaskAssistedRole( + taskId: AdminEntityIdInput, + session: AdminViewerSessionInput | null = null, +): Promise { const task = await getRequiredTask(taskId) const viewerContext = createAdminViewerContext(session) ensureViewerCanOperateAssistedTask(task, viewerContext, 'confirm') @@ -219,10 +233,10 @@ export async function confirmAdminTaskAssistedRole(taskId, session = null) { } } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -/** @param {AdminViewerSessionInput | null} [session] */ -export async function redeemAdminTaskAssisted(taskId, session = null) { +export async function redeemAdminTaskAssisted( + taskId: AdminEntityIdInput, + session: AdminViewerSessionInput | null = null, +): Promise { const task = await getRequiredTask(taskId) const viewerContext = createAdminViewerContext(session) ensureViewerCanOperateAssistedTask(task, viewerContext, 'redeem') @@ -234,16 +248,12 @@ export async function redeemAdminTaskAssisted(taskId, session = null) { } } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -export async function closeAdminTask(taskId) { +export async function closeAdminTask(taskId: AdminEntityIdInput): Promise { return closeAdminTaskWithDeps(taskId) } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ export async function closeAdminTaskWithDeps( - taskId, + taskId: AdminEntityIdInput, { getRequiredTask: getTask = getRequiredTask, listTaskInventoryBindingsByTaskId: listBindings = listTaskInventoryBindingsByTaskId, @@ -253,8 +263,8 @@ export async function closeAdminTaskWithDeps( createTaskEvent: createEvent = createTaskEvent, closeTencentBrowserSession: closeSession = closeTencentBrowserSession, nowIso: getNowIso = nowIso, - } = {}, -) { + }: CloseAdminTaskDeps = {}, +): Promise { const task = await getTask(taskId) if (task.task_status === 'redeemed') { @@ -326,9 +336,7 @@ export async function closeAdminTaskWithDeps( } } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -export async function markAdminTaskManualReview(taskId) { +export async function markAdminTaskManualReview(taskId: AdminEntityIdInput): Promise { const task = await getRequiredTask(taskId) const updatedTask = await updateTask(task.id, { task_status: 'manual_review', @@ -342,9 +350,7 @@ export async function markAdminTaskManualReview(taskId) { } } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -export async function retryAdminTask(taskId) { +export async function retryAdminTask(taskId: AdminEntityIdInput): Promise { const task = await getRequiredTask(taskId) const now = nowIso() @@ -408,7 +414,7 @@ export async function retryAdminTask(taskId) { updated_at: now, }) - const response = { + const response: AdminTaskActionResponse = { task: mapTaskActionPayload(updatedTask), } @@ -420,11 +426,11 @@ export async function retryAdminTask(taskId) { return response } -/** @returns {Promise} */ -/** @param {AdminEntityIdInput} taskId */ -/** @param {{ outcome?: string, resultMessage?: string, deliveryReference?: string, deliveredCredential?: string }} [payload] */ -/** @param {AdminViewerSessionInput | null} [session] */ -export async function completeAdminTaskManualDispatch(taskId, payload = {}, session = null) { +export async function completeAdminTaskManualDispatch( + taskId: AdminEntityIdInput, + payload: AdminTaskManualDispatchInput = {}, + session: AdminViewerSessionInput | null = null, +): Promise { const task = await getRequiredTask(taskId) if (!isManualDispatchTask(task)) { diff --git a/docs/backend-typescript-migration-plan.md b/docs/backend-typescript-migration-plan.md index e73ed73a..8948e195 100644 --- a/docs/backend-typescript-migration-plan.md +++ b/docs/backend-typescript-migration-plan.md @@ -768,6 +768,14 @@ - `npm run typecheck` - `npm run build` - `npm test` 共 139 个用例通过 +195. 后台 Admin 任务写操作迁移到 `.ts`: + - `src/services/admin/write/task-actions.ts` +196. Admin 任务库存释放、绑定释放、领取链接重建、半自动确认 / 兑换、关闭任务、转人工复核、重试、人工履约回写已进入 TS 编译链路;entity id、viewer session、手动履约 input、action response、binding release response、依赖注入 close deps 与 task patch 补齐类型 +197. Docker 内验证通过: + - `src/services/admin/*.test.js` 共 8 个用例通过 + - `npm run typecheck` + - `npm run build` + - `npm test` 共 139 个用例通过 ## 下一步建议