60 lines
2.0 KiB
TypeScript
60 lines
2.0 KiB
TypeScript
/**
|
|
* live progress 合并(Task 144)。
|
|
*
|
|
* history 条目缺失 file 进度时保留实时缓存(live)进度;live 有值且有效时
|
|
* 以 live 为准;history 已可下载(fileReady/downloadUrl 就绪)时不覆盖——
|
|
* 结果文件既成,实时进度无意义。纯函数无副作用,入参不修改。
|
|
*/
|
|
export const FILE_PROGRESS_KEYS = [
|
|
'fileProgressPercent',
|
|
'fileProgressCurrent',
|
|
'fileProgressTotal',
|
|
'fileProgressMessage',
|
|
'fileReady',
|
|
'fileStatus',
|
|
] as const
|
|
|
|
export interface DownloadableItem {
|
|
resultId?: number | null
|
|
fileReady?: boolean | null
|
|
fileStatus?: string | null
|
|
downloadUrl?: string | null
|
|
}
|
|
|
|
/**
|
|
* 可下载判定(Task 145):有结果记录,且满足其一——
|
|
* fileReady=true、downloadUrl 非空、fileStatus 为终态(SUCCESS 可下载结果文件,
|
|
* FAILED 可下载错误文件或用于展示错误)。
|
|
*/
|
|
export function canDownloadItem(item: DownloadableItem | null | undefined): boolean {
|
|
if (!item) return false
|
|
const ready = item.fileReady || Boolean(item.downloadUrl)
|
|
const terminalStatus = item.fileStatus === 'SUCCESS' || item.fileStatus === 'FAILED'
|
|
return Boolean(item.resultId && (ready || terminalStatus))
|
|
}
|
|
|
|
/** 有效进度值:仅 fileProgressPercent 需要严格 >0,其余字段非空即可(0 是合法计数)。 */
|
|
export function hasMeaningfulProgress(key: string, value: unknown): boolean {
|
|
if (value === undefined || value === null) return false
|
|
if (key === 'fileProgressPercent' && typeof value === 'number') {
|
|
return value > 0
|
|
}
|
|
return true
|
|
}
|
|
|
|
export function mergeHistoryItemPreservingLiveProgress<T extends Record<string, unknown>>(
|
|
history: T,
|
|
live: T | undefined,
|
|
): T {
|
|
if (!live) return history
|
|
if (canDownloadItem(history as unknown as DownloadableItem)) return history
|
|
const result: Record<string, unknown> = { ...history }
|
|
for (const key of FILE_PROGRESS_KEYS) {
|
|
const value = (live as Record<string, unknown>)[key]
|
|
if (hasMeaningfulProgress(key, value)) {
|
|
result[key] = value
|
|
}
|
|
}
|
|
return result as T
|
|
}
|