task-66(ASIN 数据中心): 实现去重汇总导入轮询和终态

dedupe-import-model.ts 增 parseDedupeImportProgress(status/计数/errorMessage,缺省 pending、
未知状态不改) + importTaskFinished/importTaskSucceeded 终态判定;dedupe-import-api.ts 增
fetchDedupeImportProgress GET /api/admin/dedupe-total-data/import/{importId}。
8 用例全过,483 单测 + build 绿。
This commit is contained in:
2026-09-05 15:39:29 +08:00
parent abc8ed72d4
commit ce27161bbb
3 changed files with 146 additions and 1 deletions
@@ -1,6 +1,6 @@
/** 去重汇总导入启动适配(任务 65):multipart POST /import(file+groupId) → importId。 */
import { http } from '@/api/http'
import { parseDedupeImportStart } from './dedupe-import-model'
import { parseDedupeImportProgress, parseDedupeImportStart, type DedupeImportProgress } from './dedupe-import-model'
export const DEDUPE_IMPORT_ENDPOINT = '/api/admin/dedupe-total-data/import'
@@ -11,3 +11,9 @@ export async function startDedupeImport(file: File, groupId: number): Promise<st
const { data } = await http.post<unknown>(DEDUPE_IMPORT_ENDPOINT, form)
return parseDedupeImportStart(data)
}
/** 查询导入进度:GET /import/{importId}。 */
export async function fetchDedupeImportProgress(importId: string): Promise<DedupeImportProgress> {
const { data } = await http.get<unknown>(`${DEDUPE_IMPORT_ENDPOINT}/${importId}`)
return parseDedupeImportProgress(data)
}
@@ -16,3 +16,54 @@ export function parseDedupeImportStart(payload: unknown): string {
if (!importId) throw new Error('导入任务响应异常:缺少任务 ID')
return importId
}
export type DedupeImportStatus = 'pending' | 'running' | 'success' | 'failed'
export interface DedupeImportProgress {
status: DedupeImportStatus
totalRows: number
processedRows: number
asinCount: number
insertedCount: number
skippedCount: number
errorMessage?: string
}
function intOrZero(value: unknown): number {
return typeof value === 'number' && Number.isFinite(value) ? Math.floor(value) : 0
}
/** 归一化导入进度负载;缺省按未开始(pending)处理,未知状态不改。 */
export function parseDedupeImportProgress(payload: unknown): DedupeImportProgress {
const data = unwrap<unknown>(payload)
const record = data && typeof data === 'object' ? (data as Record<string, unknown>) : null
const rawStatus = typeof record?.status === 'string' ? record.status.trim().toLowerCase() : ''
const status: DedupeImportStatus =
rawStatus === 'running' || rawStatus === 'success' || rawStatus === 'failed' || rawStatus === 'pending'
? rawStatus
: 'pending'
const progress: DedupeImportProgress = {
status,
totalRows: intOrZero(record?.totalRows),
processedRows: intOrZero(record?.processedRows),
asinCount: intOrZero(record?.asinCount),
insertedCount: intOrZero(record?.insertedCount),
skippedCount: intOrZero(record?.skippedCount),
}
const errorMessage =
typeof record?.errorMessage === 'string' && record.errorMessage.trim()
? record.errorMessage.trim()
: undefined
if (errorMessage) progress.errorMessage = errorMessage
return progress
}
/** 是否到达终态(success/failed)。 */
export function importTaskFinished(progress: Pick<DedupeImportProgress, 'status'>): boolean {
return progress.status === 'success' || progress.status === 'failed'
}
/** 是否成功完成。 */
export function importTaskSucceeded(progress: Pick<DedupeImportProgress, 'status'>): boolean {
return progress.status === 'success'
}