新增车辆运维 OTA 工作台前端。

支持包管理、车辆同步、任务与自定义文件下发,并按 ops.ota* 对齐可写权限。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zhaowei.huang
2026-07-26 11:31:52 +08:00
co-authored by Cursor
parent 4223a572c5
commit 7056cf0872
14 changed files with 2567 additions and 19 deletions
@@ -0,0 +1,123 @@
import http from './http'
import type {
OtaJob,
OtaPackageInfo,
OtaSettings,
OtaTarget,
OtaVehicleRow
} from '@/types/ota'
export async function getOtaSettings(): Promise<OtaSettings> {
const { data } = await http.get<OtaSettings>('/ota/settings')
return data
}
export async function putOtaSettings(settings: OtaSettings): Promise<OtaSettings> {
const { data } = await http.put<OtaSettings>('/ota/settings', settings)
return data
}
export async function getOtaTarget(): Promise<{ target: OtaTarget | null; summary?: Record<string, string> }> {
const { data } = await http.get<{ target: OtaTarget | null; summary?: Record<string, string> }>('/ota/target')
return data
}
export async function listOtaPackages(): Promise<OtaPackageInfo[]> {
const { data } = await http.get<OtaPackageInfo[]>('/ota/packages')
return data
}
export async function activateOtaPackage(id: string, name?: string): Promise<OtaTarget> {
const { data } = await http.post<OtaTarget>(`/ota/packages/${encodeURIComponent(id)}/activate`, null, {
params: name ? { name } : undefined
})
return data
}
export async function deleteOtaPackage(id: string): Promise<void> {
await http.delete(`/ota/packages/${encodeURIComponent(id)}`)
}
export async function pullOtaPackage(carId: string): Promise<OtaPackageInfo> {
const { data } = await http.post<OtaPackageInfo>('/ota/packages/pull', { carId }, { timeout: 120000 })
return data
}
export async function uploadOtaPackage(file: File): Promise<OtaPackageInfo> {
const form = new FormData()
form.append('file', file)
const { data } = await http.post<OtaPackageInfo>('/ota/packages/upload', form, {
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 300000
})
return data
}
export async function listOtaVehicles(latency?: boolean): Promise<OtaVehicleRow[]> {
const { data } = await http.get<OtaVehicleRow[]>('/ota/vehicles', {
params: latency === undefined ? undefined : { latency },
timeout: 60000
})
return data
}
export async function listOtaJobs(take = 100): Promise<OtaJob[]> {
const { data } = await http.get<OtaJob[]>('/ota/jobs', { params: { take } })
return data
}
export async function getOtaJob(id: string): Promise<OtaJob> {
const { data } = await http.get<OtaJob>(`/ota/jobs/${encodeURIComponent(id)}`)
return data
}
export async function createOtaSyncJob(body: {
carIds: string[]
components?: string[]
requireLatencyCheck?: boolean
}): Promise<OtaJob> {
const { data } = await http.post<OtaJob>('/ota/jobs', body)
return data
}
export async function cancelOtaJob(id: string): Promise<void> {
await http.post(`/ota/jobs/${encodeURIComponent(id)}/cancel`)
}
export async function retryOtaJob(id: string): Promise<OtaJob> {
const { data } = await http.post<OtaJob>(`/ota/jobs/${encodeURIComponent(id)}/retry`)
return data
}
export async function getOtaConfig(carId: string, app: string): Promise<{ json: string }> {
const { data } = await http.get<{ json: string }>(`/ota/config/${encodeURIComponent(carId)}/${encodeURIComponent(app)}`)
return data
}
export async function pushOtaConfig(body: {
carIds: string[]
app: string
json: string
requireLatencyCheck?: boolean
}): Promise<OtaJob> {
const { data } = await http.post<OtaJob>('/ota/config/push', body)
return data
}
export async function pushOtaCustomFile(opts: {
carIds: string[]
remotePath: string
restartOps: number[]
files: File[]
}): Promise<OtaJob> {
const form = new FormData()
form.append('carIds', JSON.stringify(opts.carIds))
form.append('remotePath', opts.remotePath)
form.append('restartOps', JSON.stringify(opts.restartOps.length ? opts.restartOps : [-1]))
for (const f of opts.files) form.append('files', f)
const { data } = await http.post<OtaJob>('/ota/custom-file', form, {
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 300000
})
return data
}