2026-01-01 22:40:32 +08:00
|
|
|
|
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>
|
|
|
|
|
|
{
|
2026-01-09 12:30:36 +08:00
|
|
|
|
{ 0, "仅取流" },
|
|
|
|
|
|
{ 1, "本地窗口预览" },
|
|
|
|
|
|
{ 2, "本地录像" },
|
|
|
|
|
|
{ 3, "句柄渲染 (嵌入)" },
|
|
|
|
|
|
{ 4, "网络转发 (TCP/UDP)" },
|
|
|
|
|
|
{ 5, "Web 推流" }
|
2026-01-01 22:40:32 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// --- 数据源 ---
|
|
|
|
|
|
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));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|