using Aging.Infrastructure.Contracts;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
using HMI.Base;
|
using HMI.Core.Util;
|
using HMI.UI.Util;
|
using log4net;
|
using Plugin.DeviceDebug.Model;
|
using System;
|
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
using System.IO;
|
using System.Linq;
|
using System.Windows;
|
using System.Windows.Controls;
|
|
namespace Plugin.DeviceDebug
|
{
|
/// <summary>
|
/// 硬件调试插件(壳):装配并持有共享基础设施(会话管理器/设备服务/配置库路径),
|
/// 以 TabControl 承载多个 <see cref="DeviceDebugTab"/>,支持同时调试多个设备,
|
/// 每个 Tab 拥有独立会话与维护租约。设备下拉仅列出尚未打开的设备。
|
/// </summary>
|
[ObservableObject]
|
public partial class DeviceDebug : SimpleMaskControl
|
{
|
private static readonly ILog log = LogManager.GetLogger(typeof(DeviceDebug));
|
private DeviceDebugModel _debugModel;
|
private DebugSessionManager _sessionManager;
|
|
private IDeviceManager _deviceManager;
|
private IDeviceService _deviceService;
|
private IResourceManager _resourceManager;
|
|
private string _deviceConfigDbPath;
|
|
// 全量设备("id [kind]")与已打开标签映射(deviceId → TabItem)
|
private readonly List<string> _allDevices = new();
|
private readonly Dictionary<string, TabItem> _openTabs = new(StringComparer.OrdinalIgnoreCase);
|
|
[ObservableProperty] private ObservableCollection<string> _deviceList = new();
|
[ObservableProperty] private string _selectedDevice;
|
|
public DeviceDebug()
|
{
|
DataContext = this;
|
InitializeComponent();
|
}
|
|
public void ForceRefreshForTest()
|
{
|
try { LoadDeviceList(); }
|
catch (Exception ex) { log.Error("ForceRefreshForTest Error.", ex); }
|
}
|
|
public override void InitFinish()
|
{
|
base.InitFinish();
|
try
|
{
|
_debugModel = new DeviceDebugModel();
|
string dbPath = Path.Combine(BaseFolder, "debug.db");
|
_debugModel.InitDatabase(dbPath);
|
|
var container = new UtilContainer();
|
_deviceManager = container.GetUtil<IDeviceManager>("DeviceManager");
|
_deviceService = container.GetUtil<IDeviceService>("DeviceService");
|
_resourceManager = container.GetUtil<IResourceManager>("ResourceManager");
|
|
_sessionManager = new DebugSessionManager(_debugModel, _resourceManager);
|
_deviceConfigDbPath = Path.Combine(BaseFolder, "data.db");
|
|
log.Info("硬件调试模块初始化完成");
|
}
|
catch (Exception ex)
|
{
|
log.Error("硬件调试模块初始化失败", ex);
|
ToastHelper.Error($"硬件调试初始化失败: {ex.Message}");
|
}
|
}
|
|
private void SimpleMaskControl_Loaded(object sender, RoutedEventArgs e)
|
{
|
LoadDeviceList();
|
Loaded -= SimpleMaskControl_Loaded;
|
}
|
|
private void RfhBtn_Click(object sender, RoutedEventArgs e) => LoadDeviceList();
|
|
private void LoadDeviceList()
|
{
|
try
|
{
|
if (!File.Exists(_deviceConfigDbPath))
|
{
|
log.Warn($"设备配置数据库不存在: {_deviceConfigDbPath}");
|
ToastHelper.Warning("设备配置数据库不存在,请先在设备配置模块中添加设备");
|
return;
|
}
|
|
var sqliteHelper = new SqliteHelper(_deviceConfigDbPath);
|
var dt = sqliteHelper.GetDataTable("SELECT DeviceId, Kind FROM DeviceDefinition ORDER BY DeviceId");
|
|
_allDevices.Clear();
|
foreach (System.Data.DataRow row in dt.Rows)
|
_allDevices.Add($"{row["DeviceId"]} [{row["Kind"]}]");
|
|
RefreshAvailableList();
|
log.Info($"加载设备列表完成,共 {_allDevices.Count} 个设备");
|
}
|
catch (Exception ex)
|
{
|
log.Error("加载设备列表失败", ex);
|
ToastHelper.Error($"加载设备列表失败: {ex.Message}");
|
}
|
}
|
|
/// <summary>下拉仅列出未打开的设备(一会一设备)。</summary>
|
private void RefreshAvailableList()
|
{
|
var avail = _allDevices
|
.Where(d => !_openTabs.ContainsKey(ParseDeviceId(d)))
|
.ToList();
|
DeviceList = new ObservableCollection<string>(avail);
|
}
|
|
private static string ParseDeviceId(string selection)
|
{
|
if (string.IsNullOrEmpty(selection)) return string.Empty;
|
int idx = selection.IndexOf(" [");
|
return idx > 0 ? selection.Substring(0, idx) : selection;
|
}
|
|
private static string ParseDeviceKind(string selection)
|
{
|
if (string.IsNullOrEmpty(selection)) return string.Empty;
|
int start = selection.IndexOf(" [");
|
int end = selection.IndexOf("]");
|
if (start >= 0 && end > start)
|
return selection.Substring(start + 2, end - start - 2);
|
return string.Empty;
|
}
|
|
private void AddDeviceBtn_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
if (string.IsNullOrEmpty(SelectedDevice))
|
{
|
ToastHelper.Warning("请先在设备下拉中选择设备");
|
return;
|
}
|
string deviceId = ParseDeviceId(SelectedDevice);
|
string kind = ParseDeviceKind(SelectedDevice);
|
|
// 已打开则聚焦其 Tab(防御性:下拉本已过滤)
|
if (_openTabs.TryGetValue(deviceId, out var existing))
|
{
|
debugTabs.SelectedItem = existing;
|
SelectedDevice = null;
|
return;
|
}
|
|
var tabContent = new DeviceDebugTab();
|
tabContent.Initialize(_debugModel, _sessionManager, _deviceManager, _deviceService,
|
_deviceConfigDbPath, deviceId, kind);
|
|
var tab = new TabItem { Header = deviceId, Content = tabContent, Tag = deviceId };
|
debugTabs.Items.Add(tab);
|
debugTabs.SelectedItem = tab;
|
_openTabs[deviceId] = tab;
|
|
RefreshAvailableList();
|
SelectedDevice = null;
|
log.Info($"已加入调试设备: {deviceId}(当前 {debugTabs.Items.Count} 个标签)");
|
}
|
catch (Exception ex)
|
{
|
log.Error("加入调试设备失败", ex);
|
ToastHelper.Error($"加入调试失败: {ex.Message}");
|
}
|
}
|
|
private void CloseTabBtn_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
if (debugTabs.SelectedItem is not TabItem tab) return;
|
string deviceId = tab.Tag as string ?? "";
|
if (tab.Content is DeviceDebugTab content)
|
content.CloseSessionSilently(); // 关闭即释放维护租约,杜绝泄漏
|
debugTabs.Items.Remove(tab);
|
if (!string.IsNullOrEmpty(deviceId)) _openTabs.Remove(deviceId);
|
RefreshAvailableList();
|
log.Info($"已关闭调试标签并释放会话: {deviceId}");
|
}
|
catch (Exception ex)
|
{
|
log.Error("关闭调试标签失败", ex);
|
ToastHelper.Error($"关闭失败: {ex.Message}");
|
}
|
}
|
}
|
}
|