Files
Migu2.0/frontends/apps/simple-platform-vue/src/api/vehicleOps.ts
T
黄兆尉andCursor c9e835aaf7 运维网关支持按车辆配置方法真实下发,并按用户过滤审计。
新增 ops.car.execute 路径与前端运维操作/选中面板联动。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 17:50:34 +08:00

110 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { executeOp } from './ops'
import { ReflectionApiError, reflectionApi } from './reflection'
export type VehicleMaintenanceMode = 'online' | 'offline' | 'repair' | 'blown'
/** 地图监控车辆列表快捷动作 */
export type VehicleQuickAction =
| 'online'
| 'offline'
| 'endTask'
| 'disable'
| 'enable'
const METHOD_MAP: Record<VehicleMaintenanceMode, string> = {
online: 'OnlineCar',
offline: 'OfflineCar',
repair: 'Repair',
blown: 'Blown'
}
/** 结束任务:按车型依次尝试(Dummy=ForceStopClumsy=ForceStopUI,通用=UIIntercept */
const END_TASK_METHODS = ['ForceStopUI', 'ForceStop', 'UIIntercept'] as const
const QUICK_METHOD_MAP: Record<Exclude<VehicleQuickAction, 'endTask'>, string> = {
online: 'OnlineCar',
offline: 'OfflineCar',
disable: 'DisableCar',
enable: 'EnableCar'
}
export const VEHICLE_QUICK_ACTIONS: {
value: VehicleQuickAction
label: string
danger?: boolean
confirm: string
}[] = [
{ value: 'online', label: '上线', confirm: '确认将车辆上线?' },
{ value: 'offline', label: '下线', confirm: '确认将车辆下线?下线后不再被任务选中。' },
{ value: 'endTask', label: '结束任务', danger: true, confirm: '确认结束该车当前任务?' },
{ value: 'disable', label: '禁用车辆', danger: true, confirm: '确认禁用该车?禁用后需先启用才能重新上线。' },
{ value: 'enable', label: '启用车辆', confirm: '确认启用该车?启用后仍需上线才能参与调度。' }
]
export async function setVehicleMaintenance(
carId: number,
mode: VehicleMaintenanceMode
): Promise<boolean> {
const method = METHOD_MAP[mode]
if (!method) return false
try {
await reflectionApi.execute('car', carId, method)
return true
} catch {
return false
}
}
function isUnsupportedMethodError(err: unknown): boolean {
if (err instanceof ReflectionApiError && (err.code === 404 || err.code === 405)) return true
const msg = err instanceof Error ? err.message : String(err)
return /method|not\s*found|unsupported|not\s*supported/i.test(msg)
}
async function executeCarMethodViaOps(carId: number, method: string): Promise<void> {
const resp = await executeOp({
opCode: 'ops.car.execute',
targetId: String(carId),
method
})
if (resp.ok) return
throw new Error(resp.message || `执行 ${method} 未成功`)
}
/** 执行车辆快捷动作;失败抛错,由调用方提示。经运维网关以便写入运维记录。 */
export async function executeVehicleQuickAction(
carId: number,
action: VehicleQuickAction
): Promise<void> {
if (!Number.isFinite(carId) || carId <= 0) {
throw new Error('无效车辆 ID')
}
if (action === 'endTask') {
let lastErr: unknown
for (const method of END_TASK_METHODS) {
try {
await executeCarMethodViaOps(carId, method)
return
} catch (err) {
lastErr = err
if (!isUnsupportedMethodError(err) && !isUnconfiguredMethodError(err)) throw err
}
}
if (lastErr) throw lastErr
throw new Error('当前车型不支持结束任务')
}
const method = QUICK_METHOD_MAP[action]
await executeCarMethodViaOps(carId, method)
}
function isUnconfiguredMethodError(err: unknown): boolean {
const msg = err instanceof Error ? err.message : String(err)
return /不在该车型已配置|未配置动作/.test(msg)
}
export function openOnboardWeb(url?: string | null, ip?: string | null): void {
const target = url ?? (ip ? `http://${ip}:8081` : null)
if (!target) return
window.open(target, '_blank', 'noopener,noreferrer')
}