task-127(记录与版本中心): 实现软件版本列表加载

新增 version-model.ts 与 version-api.ts(GET /api/admin/versions)。

TDD: task-127.test.ts 8 用例 RED→GREEN。
This commit is contained in:
2026-09-05 17:34:49 +08:00
parent 1d98315877
commit 154ec6e301
3 changed files with 104 additions and 0 deletions
@@ -0,0 +1,11 @@
/** 软件版本列表加载适配(任务 127):GET /api/admin/versions。 */
import { http } from '@/api/http'
import { parseSoftwareVersionList } from './version-model.ts'
import type { SoftwareVersionList } from './version-dto.ts'
export const SOFTWARE_VERSIONS_ENDPOINT = '/api/admin/versions'
export async function fetchSoftwareVersions(): Promise<SoftwareVersionList> {
const { data } = await http.get<unknown>(SOFTWARE_VERSIONS_ENDPOINT)
return parseSoftwareVersionList(data)
}
@@ -0,0 +1,35 @@
/** 软件版本列表加载模型(任务 127):解析 /api/admin/versions data.items(snake);纯逻辑。 */
import { unwrap } from '../../api/envelope.ts'
import { type SoftwareVersionItem, type SoftwareVersionList } from './version-dto.ts'
function text(value: unknown): string {
return typeof value === 'string' ? value.trim() : ''
}
function numberOrNull(value: unknown): number | null {
return typeof value === 'number' && Number.isFinite(value) ? Math.floor(value) : null
}
/** 解析单条软件版本行;缺 id 视为无效。 */
export function toSoftwareVersionItem(raw: unknown): SoftwareVersionItem | null {
if (!raw || typeof raw !== 'object') return null
const r = raw as Record<string, unknown>
const id = numberOrNull(r.id)
if (id === null) return null
return {
id,
version: text(r.version),
fileUrl: text(r.file_url ?? r.fileUrl),
createdAt: text(r.created_at ?? r.createdAt),
}
}
/** 归一化版本列表负载为前端结果;缺省回空列表。 */
export function parseSoftwareVersionList(payload: unknown): SoftwareVersionList {
const data = unwrap<unknown>(payload)
const record = data && typeof data === 'object' ? (data as Record<string, unknown>) : {}
const items = Array.isArray(record.items)
? record.items.map((raw) => toSoftwareVersionItem(raw)).filter((item): item is SoftwareVersionItem => item !== null)
: []
return { items }
}