新增 OTA WatchDog 编排与车队健康/报警后端。
覆盖包库回传、任务下发、CDM 任务同步与报警采集,并为包/任务 ID 与上传文件名加上路径安全校验。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MiGu.Server.Fleet;
|
||||
using MiGu.Server.Persistence;
|
||||
|
||||
namespace MiGu.Server.Controllers;
|
||||
|
||||
/// <summary>车队运维健康探针(延迟走 WatchDog TCP)+ CDM 任务平台侧快照读取。</summary>
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[Route("api/fleet")]
|
||||
public sealed class FleetController : ControllerBase
|
||||
{
|
||||
private readonly FleetHealthService _health;
|
||||
private readonly CdmTaskSyncer _cdmSyncer;
|
||||
private readonly AlarmCollector _alarmCollector;
|
||||
private readonly PlatformDbContext _db;
|
||||
|
||||
public FleetController(FleetHealthService health, CdmTaskSyncer cdmSyncer, AlarmCollector alarmCollector, PlatformDbContext db)
|
||||
{
|
||||
_health = health;
|
||||
_cdmSyncer = cdmSyncer;
|
||||
_alarmCollector = alarmCollector;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
[HttpGet("health")]
|
||||
public async Task<ActionResult<List<FleetHealthRowDto>>> Health(CancellationToken ct)
|
||||
=> Ok(await _health.GetAsync(ct));
|
||||
|
||||
/// <summary>
|
||||
/// CDM 搬运任务列表(读平台快照库 cdm_tasks)。在线时先即时同步一次拿最新,
|
||||
/// SimpleLite 关闭时回退最近快照,并通过 online/lastSyncAt 告知前端数据是否滞后。
|
||||
/// </summary>
|
||||
[HttpGet("tasks")]
|
||||
public async Task<ActionResult<object>> Tasks([FromQuery] int limit = 1000, CancellationToken ct = default)
|
||||
{
|
||||
await _cdmSyncer.SyncOnceAsync(ct);
|
||||
|
||||
var take = Math.Clamp(limit, 1, 5000);
|
||||
var tasks = await _db.CdmTasks.AsNoTracking()
|
||||
.OrderByDescending(t => t.CreateTime)
|
||||
.Take(take)
|
||||
.Select(t => new
|
||||
{
|
||||
id = t.Id,
|
||||
taskId = t.TaskId,
|
||||
missionId = t.MissionId,
|
||||
missionName = t.MissionName,
|
||||
missionTypeName = t.MissionTypeName,
|
||||
srcSiteId = t.SrcSiteId,
|
||||
srcLabel = t.SrcLabel,
|
||||
dstSiteId = t.DstSiteId,
|
||||
dstLabel = t.DstLabel,
|
||||
status = t.Status,
|
||||
statusCode = t.StatusCode,
|
||||
carId = t.CarId,
|
||||
carName = t.CarName,
|
||||
priority = t.Priority,
|
||||
createTime = t.CreateTime,
|
||||
startTime = t.StartTime,
|
||||
finishTime = t.FinishTime,
|
||||
stuckReason = t.StuckReason,
|
||||
overdue = t.Overdue
|
||||
})
|
||||
.ToListAsync(ct);
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
online = _cdmSyncer.Online,
|
||||
lastSyncAt = _cdmSyncer.LastSyncAt,
|
||||
count = tasks.Count,
|
||||
tasks
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 车辆报警列表(读平台记录 vehicle_alarms)。含活跃 + 历史;SimpleLite 离线时回退最近记录,
|
||||
/// 通过 online/lastSyncAt 告知数据是否滞后。activeOnly=true 仅返回未恢复的报警。
|
||||
/// </summary>
|
||||
[HttpGet("alarms")]
|
||||
public async Task<ActionResult<object>> Alarms(
|
||||
[FromQuery] int limit = 2000,
|
||||
[FromQuery] bool activeOnly = false,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
// 在线时先即时对帐一次,保证打开页面能拿到最新活跃报警。
|
||||
await _alarmCollector.SyncOnceAsync(ct);
|
||||
|
||||
var take = Math.Clamp(limit, 1, 10000);
|
||||
var query = _db.VehicleAlarms.AsNoTracking().AsQueryable();
|
||||
if (activeOnly) query = query.Where(a => a.Status == "active");
|
||||
|
||||
var alarms = await query
|
||||
.OrderByDescending(a => a.Status == "active")
|
||||
.ThenByDescending(a => a.LastAt)
|
||||
.Take(take)
|
||||
.Select(a => new
|
||||
{
|
||||
id = a.Id,
|
||||
carId = a.CarId,
|
||||
carName = a.CarName,
|
||||
info = a.Info,
|
||||
level = a.Level,
|
||||
status = a.Status,
|
||||
firstAt = a.FirstAt,
|
||||
lastAt = a.LastAt,
|
||||
resolvedAt = a.ResolvedAt,
|
||||
durationSecs = a.DurationSecs,
|
||||
acknowledged = a.Acknowledged
|
||||
})
|
||||
.ToListAsync(ct);
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
online = _alarmCollector.Online,
|
||||
lastSyncAt = _alarmCollector.LastSyncAt,
|
||||
count = alarms.Count,
|
||||
alarms
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user