用了统一存储,之前显示系统日志的读方法需要修改

This commit is contained in:
2025-12-26 23:05:08 +08:00
parent 3d4eb34ca9
commit 39404c0acd
3 changed files with 188 additions and 146 deletions

View File

@@ -5,25 +5,24 @@ namespace SHH.CameraSdk;
/// <summary>
/// 视频源实时状态监控 API 控制器
/// 核心功能:提供相机设备遥测数据查询、单设备详情查询、设备截图获取接口
/// 适用场景Web 监控大屏、移动端状态查询、第三方系统集成
/// 核心功能:提供相机设备遥测数据查询、单设备详情查询、系统日志查询
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Route("api/monitor")] // [建议] 显式指定路由为小写,确保与前端 ${API}/monitor/... 匹配
public class MonitorController : ControllerBase
{
#region --- (Dependency Injection) ---
/// <summary> 相机管理器实例:提供设备状态与遥测数据访问能力 </summary>
private readonly CameraManager _cameraManager;
private readonly IStorageService _storage; // [新增] 存储服务引用
/// <summary>
/// 构造函数:通过依赖注入获取 CameraManager 实例
/// 构造函数:注入 CameraManager 和 IStorageService
/// </summary>
/// <param name="cameraManager">相机管理器</param>
public MonitorController(CameraManager cameraManager)
public MonitorController(CameraManager cameraManager, IStorageService storage)
{
_cameraManager = cameraManager;
_storage = storage;
}
#endregion
@@ -31,14 +30,9 @@ public class MonitorController : ControllerBase
#region --- API (API Endpoints) ---
/// <summary>
/// 获取全量相机实时遥测数据快照(支持跨域)
/// </summary>
/// <remarks>
/// 返回数据包含设备ID、名称、IP地址、运行状态、在线状态、实时FPS、累计帧数、健康度评分、最后错误信息
/// 获取全量相机实时遥测数据快照
/// 适用场景:监控大屏首页数据看板
/// [cite: 191, 194]
/// </remarks>
/// <returns>200 OK + 遥测数据列表</returns>
/// </summary>
[HttpGet("dashboard")]
public IActionResult GetDashboard()
{
@@ -49,18 +43,13 @@ public class MonitorController : ControllerBase
/// <summary>
/// 获取指定相机的详细运行指标
/// </summary>
/// <param name="id">相机设备唯一标识</param>
/// <returns>200 OK + 设备详情 | 404 Not Found</returns>
[HttpGet("{id}")]
public IActionResult GetDeviceDetail(long id)
{
// 查询指定设备
var device = _cameraManager.GetDevice(id);
// 设备不存在返回 404
if (device == null) return NotFound($"设备 ID: {id} 不存在");
// 构造设备详情返回对象
var deviceDetail = new
return Ok(new
{
device.Id,
device.Status,
@@ -69,53 +58,60 @@ public class MonitorController : ControllerBase
device.TotalFrames,
device.Config.Name,
device.Config.IpAddress
};
return Ok(deviceDetail);
});
}
/// <summary>
/// 获取指定相机的实时截图
/// </summary>
/// <param name="id">相机设备唯一标识</param>
/// <returns>200 OK + JPEG 图片流 | 504 Gateway Timeout</returns>
[HttpGet("snapshot/{id}")]
public async Task<IActionResult> GetSnapshot(long id)
{
// 调用截图协调器获取实时截图,设置 2 秒超时
// 超时保护:避免 HTTP 线程因设备异常长时间挂起
// 假设您有 SnapshotCoordinator 单例,此处保留原逻辑
var imageBytes = await SnapshotCoordinator.Instance.RequestSnapshotAsync(id, 2000);
// 截图超时或设备无响应,返回 504 超时状态码
if (imageBytes == null)
{
return StatusCode(StatusCodes.Status504GatewayTimeout, "截图请求超时或设备未响应");
}
// 返回 JPEG 格式图片流,支持浏览器直接预览
return File(imageBytes, "image/jpeg");
}
/// <summary>
/// 获取指定相机的诊断信息(审计日志)
/// 获取指定相机的深度诊断信息(包含持久化的审计日志)
/// </summary>
/// <param name="id">相机设备唯一标识</param>
/// <returns>200 OK + 诊断信息 | 404 Not Found</returns>
[HttpGet("diagnose/{id}")]
public IActionResult GetDeviceDiagnostic(long id)
public async Task<IActionResult> GetDeviceDiagnostic(long id)
{
var device = _cameraManager.GetDevice(id);
if (device == null) return NotFound();
if (device == null) return NotFound("设备不存在");
// [修正] 改为从 StorageService 读取文件日志
// 这样即使重启程序,历史日志也能查到
var logs = await _storage.GetDeviceLogsAsync((int)id, 50);
return Ok(new
{
// 基础信息
Id = device.Id,
Status = device.Status.ToString(),
RealFps = device.RealFps,
TotalFrames = device.TotalFrames,
// 关键:将 BaseVideoSource 中的日志列表返回给前端
// 注意:属性名 AuditLogs 会被序列化为 auditLogs (首字母小写),符合前端预期
AuditLogs = device.GetAuditLogs()
// 实时状态
BasicInfo = device.Config,
RealTimeStats = new
{
device.RealFps,
device.TotalFrames,
device.IsPhysicalOnline,
device.Width,
device.Height
},
// [关键] 持久化日志
AuditLogs = logs
});
}
@@ -125,26 +121,12 @@ public class MonitorController : ControllerBase
/// 获取系统操作日志(读取最新的 50 条)
/// </summary>
[HttpGet("system-logs")]
public IActionResult GetSystemLogs()
public async Task<IActionResult> GetSystemLogs()
{
try
{
var logPath = "user_actions.log";
if (!System.IO.File.Exists(logPath))
{
return Ok(new List<string> { "暂无操作记录" });
}
// [修正] 彻底废弃手动读文件,改用 Service
// Service 内部会自动处理锁、路径 (App_Data/Process_X/system.log) 和异常
var logs = await _storage.GetSystemLogsAsync(50);
// 读取文件 -> 取最后50行 -> 倒序排列(最新在前)
var logs = System.IO.File.ReadLines(logPath)
.TakeLast(50)
.Reverse()
.ToList();
return Ok(logs);
}
catch (Exception ex)
{
return StatusCode(500, $"读取日志失败: {ex.Message}");
}
return Ok(logs);
}
}