Files
Ayay/SHH.CameraDashboard/ViewModels/CameraImageSubscriptionViewModels.cs
2026-01-01 22:40:32 +08:00

253 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
namespace SHH.CameraDashboard
{
public class CameraImageSubscriptionViewModels : INotifyPropertyChanged
{
private readonly WebApiCameraModel _camera;
public event Action RequestClose;
// 用于绑定 ComboBox 的类型列表
public Dictionary<int, string> SubscriptionTypes { get; } = new Dictionary<int, string>
{
{ 0, "本地窗口预览" },
{ 1, "本地录像" },
{ 2, "句柄渲染 (嵌入)" },
{ 3, "网络转发 (TCP/UDP)" },
{ 4, "Web 推流" }
};
// --- 数据源 ---
public ObservableCollection<SubscriptionDto> Subscriptions { get; set; } = new ObservableCollection<SubscriptionDto>();
// --- 编辑表单属性 ---
private string _editAppId;
public string EditAppId
{
get => _editAppId;
set { _editAppId = value; OnPropertyChanged(); }
}
private int _editType;
public int EditType
{
get => _editType;
set
{
_editType = value;
OnPropertyChanged();
// 切换类型时,控制 UI 上 IP/Port 输入框的显示
OnPropertyChanged(nameof(IsNetworkType));
OnPropertyChanged(nameof(IsRecordType));
}
}
private int _editFps = 25;
public int EditFps
{
get => _editFps;
set { _editFps = value; OnPropertyChanged(); }
}
private string _editMemo;
public string EditMemo
{
get => _editMemo;
set { _editMemo = value; OnPropertyChanged(); }
}
// 网络参数
private string _editTargetIp = "127.0.0.1";
public string EditTargetIp
{
get => _editTargetIp;
set { _editTargetIp = value; OnPropertyChanged(); }
}
private int _editTargetPort = 8080;
public int EditTargetPort
{
get => _editTargetPort;
set { _editTargetPort = value; OnPropertyChanged(); }
}
// --- 界面显隐控制 ---
// 只有类型是 3或4 时显示网络设置
public bool IsNetworkType => EditType == 3 || EditType == 4;
// 只有类型是 1 时显示录像设置 (这里简化,暂时只演示网络显隐)
public bool IsRecordType => EditType == 1;
// --- 命令 ---
public ICommand LoadCommand { get; }
public ICommand SaveCommand { get; }
public ICommand DeleteCommand { get; }
public ICommand ClearFormCommand { get; }
public CameraImageSubscriptionViewModels(WebApiCameraModel camera)
{
_camera = camera;
LoadCommand = new RelayCommand(ExecuteLoad);
SaveCommand = new RelayCommand(ExecuteSave);
DeleteCommand = new RelayCommand(ExecuteDelete);
ClearFormCommand = new RelayCommand(obj => ResetForm());
// 初始化加载
ExecuteLoad(null);
}
private async void ExecuteLoad(object obj)
{
var list = await ApiClient.Instance.Cameras.GetSubscriptionsAsync(_camera.Id);
Subscriptions.Clear();
foreach (var item in list)
{
Subscriptions.Add(item);
}
}
private async void ExecuteSave(object obj)
{
// 1. 基础校验
if (string.IsNullOrWhiteSpace(EditAppId))
{
MessageBox.Show("AppId 不能为空", "提示");
return;
}
// 2. 构建 DTO
// 注意:这里需要根据你 DTO 的定义进行类型转换和默认值处理
var dto = new SubscriptionDto
{
AppId = EditAppId,
// ★★★ 修改:直接赋值 int不需要强转枚举 ★★★
Type = EditType,
DisplayFps = EditFps,
Memo = EditMemo ?? string.Empty,
// ... 网络参数 ...
TargetIp = IsNetworkType ? (EditTargetIp ?? string.Empty) : string.Empty,
TargetPort = IsNetworkType ? EditTargetPort : 0,
// ★★★ 修改:直接赋值 int ★★★
Protocol = 0, // 0 代表 TCP
// ... 其他参数 ...
Handle = string.Empty,
SavePath = ((SubscriptionType)EditType == SubscriptionType.LocalRecord) ? @"C:\Temp\Video" : string.Empty,
RecordDuration = 0
};
// 3. 发送请求
bool success = await ApiClient.Instance.Cameras.UpdateSubscriptionAsync(_camera.Id, dto);
if (success)
{
MessageBox.Show("保存成功", "提示");
ExecuteLoad(null); // 刷新列表
// ResetForm(); // 可选:保存后清空表单
}
else
{
MessageBox.Show("保存失败,请检查网络或参数。", "错误");
}
}
private async void ExecuteDelete(object parameter)
{
// 支持两种方式删除:
// 1. 传入 parameter (点击列表中的删除按钮)
// 2. 根据当前表单的 AppId (如果在编辑模式)
string appIdToDelete = parameter as string;
if (string.IsNullOrEmpty(appIdToDelete)) return;
if (MessageBox.Show($"确定要停止并注销 [{appIdToDelete}] 吗?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
// 构造删除请求:关键是 DisplayFps = 0
var dto = new SubscriptionDto
{
AppId = appIdToDelete,
Type = 0,
DisplayFps = 0, // <--- 核心0 代表注销
Memo = "User Deleted"
};
bool success = await ApiClient.Instance.Cameras.UpdateSubscriptionAsync(_camera.Id, dto);
if (success)
{
ExecuteLoad(null);
}
}
private void ResetForm()
{
// 生成一个随机 AppId 方便测试
EditAppId = $"Client_{DateTime.Now:HHmmss}";
EditType = 0;
EditFps = 25;
EditMemo = "";
EditTargetIp = "127.0.0.1";
EditTargetPort = 8080;
}
// --- INotifyPropertyChanged 实现 (略,使用你的基类或标准实现) ---
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
// 1. 添加一个字段
private SubscriptionDto _selectedSubscription;
// 2. 添加 SelectedSubscription 属性
public SubscriptionDto SelectedSubscription
{
get => _selectedSubscription;
set
{
// 如果两次选中同一个,不做处理
if (_selectedSubscription == value) return;
_selectedSubscription = value;
OnPropertyChanged();
// ★★★ 核心逻辑:一旦选中项发生变化,就填充表单 ★★★
if (_selectedSubscription != null)
{
FillForm(_selectedSubscription);
}
}
}
// 3. 编写填充表单的辅助方法
private void FillForm(SubscriptionDto dto)
{
// 这里我们将 DTO 的值“复制”到编辑属性中
// 这样做的好处是:修改下方文本框时,不会立即改变列表里的显示,只有点击“保存”后才刷新
EditAppId = dto.AppId;
EditType = dto.Type; // 之前改成了 int直接赋值即可
EditFps = dto.DisplayFps; // 注意:后端返回可能是 targetFps前端 DTO 映射已修复
EditMemo = dto.Memo;
// 网络参数回显
EditTargetIp = dto.TargetIp;
EditTargetPort = dto.TargetPort;
// 触发一下 UI 状态刷新(比如网络参数的显隐)
OnPropertyChanged(nameof(IsNetworkType));
}
}
}