task-10: types/task.ts 共享类型(TaskStatus/ResultFilePhase/PageResult/TaskProgressBatchVo)
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
/** 任务状态联合类型(与 Java 后端 status 字段对应) */
|
||||||
|
export type TaskStatus =
|
||||||
|
| 'PENDING'
|
||||||
|
| 'RUNNING'
|
||||||
|
| 'SUCCESS'
|
||||||
|
| 'FAILED'
|
||||||
|
| 'CANCELLED'
|
||||||
|
|
||||||
|
/** 结果文件阶段字段:旧 Java 版本可能缺失,全部可选 */
|
||||||
|
export interface ResultFilePhase {
|
||||||
|
/** 文件是否就绪可下载 */
|
||||||
|
fileReady?: boolean
|
||||||
|
/** 文件级状态 */
|
||||||
|
fileStatus?: string
|
||||||
|
/** 文件处理进度 0-100 */
|
||||||
|
fileProgress?: number
|
||||||
|
/** 进度文案 */
|
||||||
|
fileProgressLabel?: string
|
||||||
|
/** 进度阶段标记 */
|
||||||
|
fileProgressStage?: string
|
||||||
|
/** 新鲜下载链接(优先于 downloadUrl) */
|
||||||
|
freshDownloadUrl?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分页结果 */
|
||||||
|
export interface PageResult<T> {
|
||||||
|
items: T[]
|
||||||
|
total: number
|
||||||
|
page: number
|
||||||
|
pageSize: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 进度批量查询响应 */
|
||||||
|
export interface TaskProgressBatchVo<T = { taskId: number; status: string }> {
|
||||||
|
items: T[]
|
||||||
|
missingTaskIds: number[]
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { test } from 'node:test'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import type {
|
||||||
|
TaskStatus,
|
||||||
|
ResultFilePhase,
|
||||||
|
PageResult,
|
||||||
|
TaskProgressBatchVo,
|
||||||
|
} from '../src/shared/api/types/task.ts'
|
||||||
|
|
||||||
|
test('test_type_task_status_assignable', () => {
|
||||||
|
const values: TaskStatus[] = ['PENDING', 'RUNNING', 'SUCCESS', 'FAILED', 'CANCELLED']
|
||||||
|
assert.equal(values.length, 5)
|
||||||
|
// @ts-expect-error 未知状态字符串不应可赋值
|
||||||
|
const invalid: TaskStatus = 'SYNCING'
|
||||||
|
assert.ok(invalid)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_type_result_file_phase_all_optional', () => {
|
||||||
|
const empty: ResultFilePhase = {}
|
||||||
|
const partial: ResultFilePhase = { fileReady: true }
|
||||||
|
const full: ResultFilePhase = {
|
||||||
|
fileReady: true,
|
||||||
|
fileStatus: 'SUCCESS',
|
||||||
|
fileProgress: 100,
|
||||||
|
fileProgressLabel: '完成',
|
||||||
|
fileProgressStage: 'done',
|
||||||
|
freshDownloadUrl: '/newApi/api/x',
|
||||||
|
}
|
||||||
|
assert.deepEqual(empty, {})
|
||||||
|
assert.equal(partial.fileReady, true)
|
||||||
|
assert.equal(full.fileProgress, 100)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_type_page_result_shape', () => {
|
||||||
|
const page: PageResult<{ id: number }> = {
|
||||||
|
items: [{ id: 1 }],
|
||||||
|
total: 1,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
}
|
||||||
|
assert.equal(page.items.length, 1)
|
||||||
|
assert.equal(page.total, 1)
|
||||||
|
// @ts-expect-error items 必须是元素数组,不是裸对象
|
||||||
|
const invalid: PageResult<{ id: number }> = { items: { id: 1 }, total: 1 }
|
||||||
|
assert.ok(invalid)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_type_progress_batch_shape', () => {
|
||||||
|
const batch: TaskProgressBatchVo<{ taskId: number }> = {
|
||||||
|
items: [{ taskId: 1 }],
|
||||||
|
missingTaskIds: [99],
|
||||||
|
}
|
||||||
|
assert.equal(batch.items.length, 1)
|
||||||
|
assert.deepEqual(batch.missingTaskIds, [99])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_type_compat_compile', () => {
|
||||||
|
// 类型与值在同一包内可被引用;运行时检查命名导出存在性由 vue-tsc 全量检查兜底
|
||||||
|
const s: TaskStatus = 'SUCCESS'
|
||||||
|
const statuses: string[] = [s, 'FAILED', 'CANCELLED']
|
||||||
|
assert.deepEqual(statuses, ['SUCCESS', 'FAILED', 'CANCELLED'])
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user