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 { /// /// 硬件调试插件(壳):装配并持有共享基础设施(会话管理器/设备服务/配置库路径), /// 以 TabControl 承载多个 ,支持同时调试多个设备, /// 每个 Tab 拥有独立会话与维护租约。设备下拉仅列出尚未打开的设备。 /// [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 _allDevices = new(); private readonly Dictionary _openTabs = new(StringComparer.OrdinalIgnoreCase); [ObservableProperty] private ObservableCollection _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("DeviceManager"); _deviceService = container.GetUtil("DeviceService"); _resourceManager = container.GetUtil("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}"); } } /// 下拉仅列出未打开的设备(一会一设备)。 private void RefreshAvailableList() { var avail = _allDevices .Where(d => !_openTabs.ContainsKey(ParseDeviceId(d))) .ToList(); DeviceList = new ObservableCollection(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}"); } } } }