针对界面显示的优化
This commit is contained in:
@@ -237,60 +237,72 @@ public class CamerasController : ControllerBase
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [新增] 查询某台设备的当前流控策略
|
||||
/// </summary>
|
||||
[HttpGet("{id}/subscriptions")]
|
||||
public IActionResult GetSubscriptions(long id)
|
||||
{
|
||||
var device = _manager.GetDevice(id);
|
||||
if (device == null) return NotFound();
|
||||
|
||||
// 调用刚才在 FrameController 写的方法
|
||||
var subs = device.Controller.GetCurrentRequirements();
|
||||
|
||||
return Ok(subs);
|
||||
}
|
||||
|
||||
private readonly DisplayWindowManager _displayManager; // [新增]
|
||||
|
||||
/// <summary>
|
||||
/// 综合订阅策略更新接口
|
||||
/// 支持:本地 OpenCV 窗口、海康句柄穿透、本地录像、网络传输
|
||||
/// </summary>
|
||||
[HttpPost("{id}/subscriptions")]
|
||||
public IActionResult UpdateSubscription(int id, [FromBody] SubscriptionDto dto)
|
||||
{
|
||||
var device = _manager.GetDevice(id);
|
||||
if (device == null) return NotFound("设备不存在");
|
||||
|
||||
if (device is HikVideoSource hikCam)
|
||||
// 1. 自动生成 ID 逻辑
|
||||
if (string.IsNullOrWhiteSpace(dto.AppId))
|
||||
{
|
||||
// 1. 更新流控策略 (FrameController)
|
||||
// 告诉底层:这个 AppId 需要多少帧
|
||||
int totalFps = dto.DisplayFps + dto.AnalysisFps;
|
||||
|
||||
if (totalFps > 0)
|
||||
{
|
||||
// 情况 A: 这是一个新增或更新订阅
|
||||
hikCam.Controller.Register(dto.AppId, totalFps);
|
||||
|
||||
// 如果是预览模式,启动窗口
|
||||
if (dto.DisplayFps > 0)
|
||||
{
|
||||
_displayManager.StartDisplay(dto.AppId, id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 情况 B: 这是一个停止订阅请求 (FPS 为 0)
|
||||
// 1. 【核心修复】从调度中心物理删除,不再出现在列表中
|
||||
hikCam.Controller.Unregister(dto.AppId);
|
||||
|
||||
// 2. 关闭可能存在的本地窗口
|
||||
_displayManager.StopDisplay(dto.AppId);
|
||||
}
|
||||
|
||||
return Ok(new { message = "Policy updated", currentConfig = hikCam.Controller.GetCurrentRequirements() });
|
||||
dto.AppId = $"SUB_{Guid.NewGuid().ToString("N").Substring(0, 8).ToUpper()}";
|
||||
}
|
||||
|
||||
return BadRequest("Device implies no controller");
|
||||
// 2. 获取流控控制器
|
||||
var controller = device.Controller;
|
||||
if (controller == null) return BadRequest("该设备类型不支持流控调度");
|
||||
|
||||
// 3. 处理注销逻辑 (FPS 为 0 代表停止订阅)
|
||||
if (dto.DisplayFps <= 0)
|
||||
{
|
||||
controller.Unregister(dto.AppId);
|
||||
|
||||
// 停止显示管理器中所有相关的显示任务 (无论是本地窗口还是句柄绑定)
|
||||
_displayManager.StopDisplay(dto.AppId);
|
||||
|
||||
device.AddAuditLog($"注销订阅: {dto.AppId}");
|
||||
return Ok(new { Message = "Subscription removed", AppId = dto.AppId });
|
||||
}
|
||||
|
||||
// 4. 业务参数合法性校验
|
||||
switch (dto.Type)
|
||||
{
|
||||
case SubscriptionType.LocalRecord when string.IsNullOrEmpty(dto.SavePath):
|
||||
return BadRequest("录像模式必须指定存放路径");
|
||||
case SubscriptionType.HandleDisplay when string.IsNullOrEmpty(dto.Handle):
|
||||
return BadRequest("句柄显示模式必须提供窗口句柄");
|
||||
}
|
||||
|
||||
// 5. 将需求注册到流控控制器
|
||||
controller.Register(dto.AppId, dto.DisplayFps);
|
||||
|
||||
// 6. 路由显示逻辑 (核心整合点)
|
||||
if (dto.Type == SubscriptionType.LocalWindow)
|
||||
{
|
||||
// --- 保留旧版功能:启动本地 OpenCV 渲染窗口 ---
|
||||
_displayManager.StartDisplay(dto.AppId, id);
|
||||
}
|
||||
else if (dto.Type == SubscriptionType.HandleDisplay && !string.IsNullOrEmpty(dto.Handle))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
device.AddAuditLog($"更新订阅: {dto.AppId} ({dto.Type}), 目标 {dto.DisplayFps} FPS");
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
Success = true,
|
||||
AppId = dto.AppId,
|
||||
Message = "订阅策略已应用",
|
||||
CurrentConfig = controller.GetCurrentRequirements() // 返回当前所有订阅状态供前端同步
|
||||
});
|
||||
}
|
||||
|
||||
// 1. 获取单个设备详情(用于编辑回填)
|
||||
@@ -302,14 +314,6 @@ public class CamerasController : ControllerBase
|
||||
return Ok(cam.Config); // 返回原始配置对象
|
||||
}
|
||||
|
||||
// 2. 更新设备(保存功能)
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> UpdateDevice(int id, [FromBody] VideoSourceConfig config)
|
||||
{
|
||||
// 核心逻辑:先停止旧设备 -> 更新配置 -> 重新添加到容器 -> 如果之前在运行则重新启动
|
||||
await _manager.UpdateDeviceAsync(id, config);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// 3. 清除特定设备的日志
|
||||
[HttpDelete("{id}/logs")]
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace SHH.CameraSdk;
|
||||
|
||||
// ==============================================================================
|
||||
// 2. 订阅策略 DTO (对应 A/B/C/D 进程需求)
|
||||
// 用于多进程帧需求的注册与更新,支持显示帧和分析帧的独立配置
|
||||
// ==============================================================================
|
||||
/// <summary>
|
||||
/// 视频流订阅配置请求对象
|
||||
/// 用于定义第三方应用或内部模块对指定相机流的消费需求
|
||||
/// </summary>
|
||||
public class SubscriptionDto
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,17 +15,62 @@ public class SubscriptionDto
|
||||
[MaxLength(50, ErrorMessage = "AppId 长度不能超过 50 个字符")]
|
||||
public string AppId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 订阅业务类型。
|
||||
/// 决定了后端流控引擎后续的资源分配(如是否开启录像机或渲染器)。
|
||||
/// </summary>
|
||||
public SubscriptionType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示帧率需求 (单位: fps)
|
||||
/// <para>不需要显示则设为 0,控制器会自动注销该类型需求</para>
|
||||
/// </summary>
|
||||
[Range(0, 60, ErrorMessage = "显示帧率需在 0-60 fps 范围内")]
|
||||
[Range(0, 30, ErrorMessage = "显示帧率需在 0-30 fps 范围内")]
|
||||
public int DisplayFps { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分析帧率需求 (单位: fps)
|
||||
/// <para>不需要分析则设为 0,控制器会自动注销该类型需求</para>
|
||||
/// 备注信息。
|
||||
/// 用于记录订阅的用途、申请人或关联业务系统。
|
||||
/// </summary>
|
||||
[Range(0, 30, ErrorMessage = "分析帧率需在 0-30 fps 范围内")]
|
||||
public int AnalysisFps { get; set; }
|
||||
public string Memo { get; set; }
|
||||
= string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 窗口句柄(HWND)。
|
||||
/// 仅在 Type 为 HandleDisplay 时必填。格式通常为十六进制或十进制字符串。
|
||||
/// </summary>
|
||||
public string Handle { get; set; }
|
||||
= string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 录像持续时长(分钟,范围 1-60)。
|
||||
/// 仅在 Type 为 LocalRecord 时有效。
|
||||
/// </summary>
|
||||
public int RecordDuration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 录像文件存放绝对路径。
|
||||
/// 仅在 Type 为 LocalRecord 时有效,例如:C:\Recordings\Room01。
|
||||
/// </summary>
|
||||
public string SavePath { get; set; }
|
||||
= string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 通讯方式协议。
|
||||
/// 仅在 Type 为 NetworkTrans 或 WebPush 时有效,默认为 Network。
|
||||
/// </summary>
|
||||
public TransportProtocol Protocol { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目标接收端 IP 地址。
|
||||
/// 仅在 Type 为 NetworkTrans 或 WebPush 且 Protocol 为 Network 时必填。
|
||||
/// </summary>
|
||||
public string TargetIp { get; set; }
|
||||
= string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 目标接收端端口号。
|
||||
/// 仅在 Type 为 NetworkTrans 或 WebPush 时必填。
|
||||
/// </summary>
|
||||
public int TargetPort { get; set; }
|
||||
}
|
||||
19
SHH.CameraSdk/Controllers/Dto/UpdateProcessingRequest.cs
Normal file
19
SHH.CameraSdk/Controllers/Dto/UpdateProcessingRequest.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SHH.CameraSdk
|
||||
{
|
||||
public class UpdateProcessingRequest
|
||||
{
|
||||
public long DeviceId { get; set; }
|
||||
public bool EnableShrink { get; set; }
|
||||
public bool EnableExpand { get; set; }
|
||||
public int TargetWidth { get; set; }
|
||||
public int TargetHeight { get; set; }
|
||||
public bool EnableEnhance { get; set; }
|
||||
public double BrightnessLevel { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,27 +8,50 @@ namespace SHH.CameraSdk;
|
||||
/// 核心功能:提供相机设备遥测数据查询、单设备详情查询、系统日志查询
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/monitor")] // [建议] 显式指定路由为小写,确保与前端 ${API}/monitor/... 匹配
|
||||
[Route("api/[controller]")]
|
||||
public class MonitorController : ControllerBase
|
||||
{
|
||||
#region --- 依赖注入 (Dependency Injection) ---
|
||||
|
||||
private readonly CameraManager _cameraManager;
|
||||
private readonly IStorageService _storage; // [新增] 存储服务引用
|
||||
private readonly ProcessingConfigManager _configManager;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数:注入 CameraManager 和 IStorageService
|
||||
/// </summary>
|
||||
public MonitorController(CameraManager cameraManager, IStorageService storage)
|
||||
public MonitorController(CameraManager cameraManager, IStorageService storage, ProcessingConfigManager configManager)
|
||||
{
|
||||
_cameraManager = cameraManager;
|
||||
_storage = storage;
|
||||
_configManager = configManager;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- API 接口定义 (API Endpoints) ---
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有设备及配置 (对应前端 /api/Monitor/all)
|
||||
/// </summary>
|
||||
[HttpGet("all")] // <--- 必须明确写上 "all",否则前端找不到
|
||||
public IActionResult GetAll()
|
||||
{
|
||||
var cameras = _cameraManager.GetAllDevices();
|
||||
var list = cameras.Select(c => new {
|
||||
c.Id,
|
||||
Status = c.Status.ToString(),
|
||||
c.IsPhysicalOnline,
|
||||
c.RealFps,
|
||||
c.TotalFrames,
|
||||
c.Config.Name,
|
||||
c.Config.IpAddress,
|
||||
// 务必包含配置信息,供前端回显
|
||||
ProcessingOptions = _configManager.GetOptions(c.Id)
|
||||
});
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全量相机实时遥测数据快照
|
||||
/// 适用场景:监控大屏首页数据看板
|
||||
@@ -52,12 +75,18 @@ public class MonitorController : ControllerBase
|
||||
return Ok(new
|
||||
{
|
||||
device.Id,
|
||||
device.Status,
|
||||
Status = device.Status.ToString(),
|
||||
device.IsOnline,
|
||||
device.RealFps,
|
||||
device.TotalFrames,
|
||||
device.Config.Name,
|
||||
device.Config.IpAddress
|
||||
device.Config.IpAddress,
|
||||
// --- 新增:将内存中的订阅需求列表传给前端 ---
|
||||
Requirements = device.Controller.GetCurrentRequirements().Select(r => new {
|
||||
r.AppId,
|
||||
r.TargetFps,
|
||||
r.LastActive
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -129,4 +158,27 @@ public class MonitorController : ControllerBase
|
||||
|
||||
return Ok(logs);
|
||||
}
|
||||
|
||||
[HttpPost("update-processing")]
|
||||
public IActionResult UpdateProcessing([FromBody] UpdateProcessingRequest request)
|
||||
{
|
||||
// 1. 验证设备是否存在 (可选)
|
||||
|
||||
// 2. 构造配置对象
|
||||
var options = new ProcessingOptions
|
||||
{
|
||||
EnableShrink = request.EnableShrink,
|
||||
EnableExpand = request.EnableExpand,
|
||||
TargetWidth = request.TargetWidth,
|
||||
TargetHeight = request.TargetHeight,
|
||||
EnableEnhance = request.EnableEnhance,
|
||||
BrightnessLevel = request.BrightnessLevel
|
||||
};
|
||||
|
||||
// 3. 提交给配置管理器 (实时生效)
|
||||
// 这里的 _configManager 是通过构造函数注入的单例
|
||||
_configManager.UpdateOptions(request.DeviceId, options);
|
||||
|
||||
return Ok(new { msg = $"设备 {request.DeviceId} 配置已更新", time = DateTime.Now });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user