188 lines
6.2 KiB
C#
188 lines
6.2 KiB
C#
using System.Collections.ObjectModel;
|
||
using System.ComponentModel;
|
||
using System.Windows;
|
||
using System.Windows.Input;
|
||
|
||
namespace SHH.CameraDashboard
|
||
{
|
||
/// <summary>
|
||
/// 客户端配置向导的 ViewModel
|
||
/// 实现了 <see cref="IOverlayClosable"/> 接口,用于与父窗口的蒙板交互。
|
||
/// </summary>
|
||
public class WizardClientsViewModel : INotifyPropertyChanged, IOverlayClosable
|
||
{
|
||
/// <summary>
|
||
/// 绑定到 ListView 的数据源
|
||
/// </summary>
|
||
public static ObservableCollection<ServiceNodeModel> ServiceNodes
|
||
=> AppGlobal.ServiceNodes;
|
||
|
||
#region --- 业务数据属性 ---
|
||
|
||
private string _statusText = "准备就绪";
|
||
/// <summary>
|
||
/// 获取或设置向导的当前状态文本。
|
||
/// </summary>
|
||
public string StatusText
|
||
{
|
||
get => _statusText;
|
||
set { _statusText = value; OnPropertyChanged(); }
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region --- 命令属性 ---
|
||
|
||
/// <summary>
|
||
/// 获取用于确认操作的命令。
|
||
/// </summary>
|
||
public ICommand ConfirmCommand { get; }
|
||
|
||
/// <summary>
|
||
/// 获取用于取消操作的命令。
|
||
/// </summary>
|
||
public ICommand CancelCommand { get; }
|
||
|
||
// 新增一行的命令
|
||
public ICommand AddNodeCommand { get; }
|
||
|
||
public ICommand DeleteNodeCommand { get; }
|
||
|
||
public ICommand CheckCommand { get; }
|
||
|
||
|
||
#endregion
|
||
|
||
#region --- 构造函数 ---
|
||
|
||
/// <summary>
|
||
/// 初始化 <see cref="WizardClientsViewModel"/> 类的新实例。
|
||
/// </summary>
|
||
public WizardClientsViewModel()
|
||
{
|
||
// 实现新增逻辑
|
||
AddNodeCommand = new RelayCommand<object>(_ =>
|
||
{
|
||
// 创建新行对象并添加到集合
|
||
var newNode = new ServiceNodeModel
|
||
{
|
||
ServiceNodeName = "新节点",
|
||
ServiceNodeIp = "0.0.0.0",
|
||
ServiceNodePort = "5000",
|
||
Status = "未检测"
|
||
};
|
||
ServiceNodes.Add(newNode);
|
||
});
|
||
|
||
// 删除逻辑实现
|
||
DeleteNodeCommand = new RelayCommand<ServiceNodeModel>(node =>
|
||
{
|
||
if (node != null && ServiceNodes.Contains(node))
|
||
{
|
||
ServiceNodes.Remove(node);
|
||
}
|
||
});
|
||
|
||
// 初始化确认命令
|
||
ConfirmCommand = new RelayCommand<object>(async _ =>
|
||
{
|
||
try
|
||
{
|
||
// 2. 【核心代码】调用通用存储服务
|
||
// 泛型 T 自动推断为 ObservableCollection<ServiceNodeModel>
|
||
await LocalStorageService.SaveAsync(
|
||
AppPaths.ServiceNodesConfig, // 路径:Configs/service_nodes.json
|
||
ServiceNodes // 数据:当前的列表对象
|
||
);
|
||
|
||
// 4. 关闭当前弹窗
|
||
RequestClose?.Invoke();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"保存失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
});
|
||
|
||
CheckCommand = new RelayCommand<object>(async _ => await ExecuteCheckAsync());
|
||
|
||
// 初始化取消命令
|
||
CancelCommand = new RelayCommand<object>(_ =>
|
||
{
|
||
// 直接触发关闭请求事件,取消并关闭向导
|
||
RequestClose?.Invoke();
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region --- IOverlayClosable 接口实现 ---
|
||
|
||
/// <summary>
|
||
/// 当需要关闭蒙板时发生。
|
||
/// </summary>
|
||
public event Action? RequestClose;
|
||
|
||
#endregion
|
||
|
||
#region --- INotifyPropertyChanged 接口实现 ---
|
||
|
||
/// <summary>
|
||
/// 当属性值更改时发生。
|
||
/// </summary>
|
||
public event PropertyChangedEventHandler? PropertyChanged;
|
||
|
||
/// <summary>
|
||
/// 引发 <see cref="PropertyChanged"/> 事件。
|
||
/// </summary>
|
||
/// <param name="name">更改的属性名称。</param>
|
||
protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = null)
|
||
{
|
||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||
}
|
||
|
||
#endregion
|
||
|
||
private async Task ExecuteCheckAsync()
|
||
{
|
||
foreach (var node in ServiceNodes)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(node.ServiceNodeIp) || string.IsNullOrWhiteSpace(node.ServiceNodePort))
|
||
continue;
|
||
|
||
node.Status = "正在获取信息...";
|
||
|
||
// 1. 调用 ApiClient 获取列表 (代码不需要变,因为 Repository 已经封装好了)
|
||
var cameras = await ApiClient.Instance.Cameras.GetListByAddressAsync(
|
||
node.ServiceNodeIp,
|
||
node.ServiceNodePort,
|
||
"向导页面"
|
||
);
|
||
|
||
// 2. 根据返回的详细数据,生成更智能的状态描述
|
||
if (cameras.Count > 0)
|
||
{
|
||
// 统计在线的摄像头数量
|
||
int onlineCount = 0;
|
||
// 统计主要品牌 (例如: HikVision)
|
||
string firstBrand = cameras[0].Brand;
|
||
|
||
foreach (var cam in cameras)
|
||
{
|
||
if (cam.IsOnline) onlineCount++;
|
||
}
|
||
|
||
// 状态显示示例:只能是在线,其它的影响界面上色
|
||
node.Status = $"在线";
|
||
}
|
||
else
|
||
{
|
||
// 列表为空,或者是网络不通导致 Repository 返回了空列表
|
||
// 为了区分是“无数据”还是“网络不通”,其实 Repository 可以优化返回 null 或抛异常,
|
||
// 但目前的架构返回空列表最安全。
|
||
node.Status = "离线或无设备";
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |