using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace SHH.CameraSdk; /// /// 视频源实时状态监控 API 控制器 /// 核心功能:提供相机设备遥测数据查询、单设备详情查询、设备截图获取接口 /// 适用场景:Web 监控大屏、移动端状态查询、第三方系统集成 /// [ApiController] [Route("api/[controller]")] public class MonitorController : ControllerBase { #region --- 依赖注入 (Dependency Injection) --- /// 相机管理器实例:提供设备状态与遥测数据访问能力 private readonly CameraManager _cameraManager; /// /// 构造函数:通过依赖注入获取 CameraManager 实例 /// /// 相机管理器 public MonitorController(CameraManager cameraManager) { _cameraManager = cameraManager; } #endregion #region --- API 接口定义 (API Endpoints) --- /// /// 获取全量相机实时遥测数据快照(支持跨域) /// /// /// 返回数据包含:设备ID、名称、IP地址、运行状态、在线状态、实时FPS、累计帧数、健康度评分、最后错误信息 /// 适用场景:监控大屏首页数据看板 /// [cite: 191, 194] /// /// 200 OK + 遥测数据列表 [HttpGet("dashboard")] public IActionResult GetDashboard() { var telemetrySnapshot = _cameraManager.GetTelemetrySnapshot(); return Ok(telemetrySnapshot); } /// /// 获取指定相机的详细运行指标 /// /// 相机设备唯一标识 /// 200 OK + 设备详情 | 404 Not Found [HttpGet("{id}")] public IActionResult GetDeviceDetail(long id) { // 查询指定设备 var device = _cameraManager.GetDevice(id); // 设备不存在返回 404 if (device == null) return NotFound($"设备 ID: {id} 不存在"); // 构造设备详情返回对象 var deviceDetail = new { device.Id, device.Status, device.IsOnline, device.RealFps, device.TotalFrames, device.Config.Name, device.Config.IpAddress }; return Ok(deviceDetail); } /// /// 获取指定相机的实时截图 /// /// 相机设备唯一标识 /// 200 OK + JPEG 图片流 | 504 Gateway Timeout [HttpGet("snapshot/{id}")] public async Task GetSnapshot(long id) { // 调用截图协调器获取实时截图,设置 2 秒超时 // 超时保护:避免 HTTP 线程因设备异常长时间挂起 var imageBytes = await SnapshotCoordinator.Instance.RequestSnapshotAsync(id, 2000); // 截图超时或设备无响应,返回 504 超时状态码 if (imageBytes == null) { return StatusCode(StatusCodes.Status504GatewayTimeout, "截图请求超时或设备未响应"); } // 返回 JPEG 格式图片流,支持浏览器直接预览 return File(imageBytes, "image/jpeg"); } /// /// 获取指定相机的诊断信息(含审计日志) /// /// 相机设备唯一标识 /// 200 OK + 诊断信息 | 404 Not Found [HttpGet("diagnose/{id}")] public IActionResult GetDeviceDiagnostic(long id) { var device = _cameraManager.GetDevice(id); if (device == null) return NotFound(); return Ok(new { Id = device.Id, Status = device.Status.ToString(), RealFps = device.RealFps, TotalFrames = device.TotalFrames, // 关键:将 BaseVideoSource 中的日志列表返回给前端 // 注意:属性名 AuditLogs 会被序列化为 auditLogs (首字母小写),符合前端预期 AuditLogs = device.GetAuditLogs() }); } #endregion /// /// 获取系统操作日志(读取最新的 50 条) /// [HttpGet("system-logs")] public IActionResult GetSystemLogs() { try { var logPath = "user_actions.log"; if (!System.IO.File.Exists(logPath)) { return Ok(new List { "暂无操作记录" }); } // 读取文件 -> 取最后50行 -> 倒序排列(最新在前) var logs = System.IO.File.ReadLines(logPath) .TakeLast(50) .Reverse() .ToList(); return Ok(logs); } catch (Exception ex) { return StatusCode(500, $"读取日志失败: {ex.Message}"); } } }