新增车辆运维 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,69 @@
import { computed, ref } from 'vue'
import { getOtaSettings, getOtaTarget, listOtaJobs } from '@/api/ota'
import type { OtaJob, OtaSettings, OtaTarget } from '@/types/ota'
import { OTA_COPY } from '@/views/shared/ota/otaCopy'
const settings = ref<OtaSettings | null>(null)
const target = ref<OtaTarget | null>(null)
const targetSummary = ref<Record<string, string>>({})
const activeJobCount = ref(0)
const loadingMeta = ref(false)
let pollTimer: ReturnType<typeof setInterval> | null = null
let started = false
export async function refreshOtaMeta() {
loadingMeta.value = true
try {
const [s, t, jobs] = await Promise.all([
getOtaSettings(),
getOtaTarget(),
listOtaJobs(30)
])
settings.value = s
target.value = t.target
targetSummary.value = t.summary ?? {}
activeJobCount.value = jobs.filter((j) =>
['pending', 'probing', 'running'].includes(j.status)
).length
} finally {
loadingMeta.value = false
}
}
export function startOtaMetaPolling() {
if (started) return
started = true
void refreshOtaMeta()
pollTimer = setInterval(() => {
void refreshOtaMeta()
}, 8000)
}
export function stopOtaMetaPolling() {
started = false
if (pollTimer) {
clearInterval(pollTimer)
pollTimer = null
}
}
export function useOtaWorkbench() {
const targetLabel = computed(() => {
if (!target.value) return OTA_COPY.unsetTarget
return target.value.name || target.value.packageId
})
return {
settings,
target,
targetSummary,
targetLabel,
activeJobCount,
loadingMeta,
refreshMeta: refreshOtaMeta,
startPolling: startOtaMetaPolling,
stopPolling: stopOtaMetaPolling
}
}
export type { OtaJob, OtaSettings, OtaTarget }