具备界面基础功能

This commit is contained in:
2026-01-01 22:40:32 +08:00
parent 0c86b4dad3
commit d039559402
81 changed files with 8333 additions and 1905 deletions

View File

@@ -0,0 +1,105 @@
namespace SHH.CameraDashboard;
public partial class CameraRepository
{
#region GetListByAddressAsync
/// <summary>
/// [新增] 动态检测方法。
/// 专门用于向导界面,根据临时输入的 IP 地址和端口号来获取摄像头列表。
/// </summary>
/// <param name="ipAddress">目标服务器的 IP 地址。</param>
/// <param name="port">目标服务器的端口号。</param>
/// <param name="pageName">调用此方法的页面或步骤名称,用于日志记录。</param>
/// <returns>
/// 一个异步任务,其结果包含一个 <see cref="WebApiCameraModel"/> 对象的列表。
/// - 如果成功获取到列表,返回该列表(可能为空)。
/// - 如果获取过程中发生任何异常(如网络错误、服务器无响应等),返回 <c>null</c>。
/// </returns>
public async Task<List<WebApiCameraModel>?> GetListByAddressAsync(string ipAddress, string port, string pageName)
{
// 1. 统一管理并拼接请求 URL
// 在这里将基础地址与 API 路径组合ViewModel 无需关心具体的路由细节。
// WebApiRoutes.Cameras.Root 是一个假设的常量,例如 "/api/Cameras"。
string requestUrl = $"http://{ipAddress}:{port}{WebApiRoutes.Cameras.Root}";
try
{
// 2. 调用底层的 WebApiService 发送 GET 请求
// 传入 "Wizard" 相关的模块名,便于在日志中区分请求来源。
string jsonResponse = await WebApiService.Instance.GetAsync(requestUrl, moduleName: $"摄像头列表-{pageName}", default, true);
// 3. 使用 JsonHelper 进行反序列化
// 利用 JsonHelper 的防御性实现,即使 JSON 格式错误或内容为 "null",也不会抛出异常。
var cameraList = JsonHelper.Deserialize<List<WebApiCameraModel>>(jsonResponse);
// 4. 确保返回的列表不为 null
// 如果反序列化结果为 null例如API 返回 "null"),则返回一个空列表,
// 这样调用方可以安全地遍历,而无需进行 null 检查。
return cameraList ?? new List<WebApiCameraModel>();
}
catch (Exception)
{
// 5. 捕获所有异常
// 在动态检测阶段,网络不通、服务器宕机等都是预期内的情况。
// 返回 null 作为明确的失败信号ViewModel 可以据此向用户显示“连接失败”等提示。
return null;
}
}
#endregion
#region ControlPowerAsync
/// <summary>
/// 调用服务端的接口来控制指定摄像头的启停状态(开机/关机)。
/// </summary>
/// <param name="ipAddress">目标服务器的 IP 地址。</param>
/// <param name="port">目标服务器的端口号。</param>
/// <param name="cameraId">要控制的摄像头的唯一ID。</param>
/// <param name="enable">true 表示开机false 表示关机。</param>
/// <param name="pageName">调用此方法的页面或功能名称,用于日志记录。</param>
/// <returns>
/// 一个异步任务,其结果为一个布尔值:
/// - <c>true</c>表示操作成功HTTP 响应为 200 OK
/// - <c>false</c>:表示操作失败(如网络错误、服务器返回 4xx/5xx 错误等)。
/// </returns>
public async Task<bool> ControlPowerAsync(long cameraId, bool enable, string pageName)
{
var useServiceNode = AppGlobal.UseServiceNode;
if (useServiceNode == null)
return false;
var ipAddress = useServiceNode.ServiceNodeIp;
var port = useServiceNode.ServiceNodePort;
// 1. 拼接请求 URL
// 将控制参数cameraId 和 enable作为 URL 的一部分发送。
string requestUrl = $"http://{ipAddress}:{port}/api/Cameras/{cameraId}/power?enabled={enable}";
try
{
// 2. 调用底层服务发送 POST 请求
// 关键点:
// a. 即使服务端不关心请求体Body`PostAsync` 方法也要求一个非 null 的 JSON 字符串。
// 因此,我们传入一个空的 JSON 对象 "{}" 作为占位符。
// b. 我们不检查响应内容,因为如果请求失败(例如,服务器返回 404 Not Found 或 500 Internal Server Error
// `WebApiService` 会抛出异常。
await WebApiService.Instance.PostAsync(requestUrl, "{}", moduleName: $"设备启停-{pageName}");
// 3. 如果代码执行到这里,说明请求成功且没有抛出异常。
return true;
}
catch (Exception ex)
{
// 4. 捕获所有可能发生的异常
// 这包括网络连接问题、DNS解析失败、服务器无响应或返回错误状态码等。
// 记录异常信息到调试输出,以便于排查问题。
System.Diagnostics.Debug.WriteLine($"控制摄像头电源失败 [IP: {ipAddress}, CameraId: {cameraId}]: {ex.Message}");
// 返回 false 通知调用方操作已失败。
return false;
}
}
#endregion
}