From 559890c482f5973f06aafdfec9550fee5ba3c7f2 Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 09 十一月 2026 17:02:15 +0800
Subject: [PATCH] feat: CAN 模拟器 TCP 化 + 多设备并发调试 + 后台生命周期管理

---
 Plugin.DeviceConfig/DeviceEditModal.xaml.cs |  181 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 181 insertions(+), 0 deletions(-)

diff --git a/Plugin.DeviceConfig/DeviceEditModal.xaml.cs b/Plugin.DeviceConfig/DeviceEditModal.xaml.cs
index 9113dca..313bdec 100644
--- a/Plugin.DeviceConfig/DeviceEditModal.xaml.cs
+++ b/Plugin.DeviceConfig/DeviceEditModal.xaml.cs
@@ -3,6 +3,7 @@
 using Plugin.DeviceConfig.Entity;
 using Plugin.DeviceConfig.Model;
 using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Windows;
@@ -19,6 +20,7 @@
         private DeviceDefinition _device;
         private ObservableCollection<DeviceChannel> _channels = new();
         private bool _isNew;
+        private bool _execModeSyncing;
 
         public DeviceEditModal()
         {
@@ -40,6 +42,11 @@
             cbTransport.ItemsSource = Enum.GetValues(typeof(TransportType)).Cast<TransportType>().ToList();
             cbTransport.SelectionChanged += CbTransport_SelectionChanged;
 
+            // 鎵ц浣嶇疆锛氫徊瑁佸煙/BrokerId 鍊欓�夌敱閰嶇疆鏋氫妇
+            cbAuthority.ItemsSource = V3AuthorityCatalog.AuthorityIds;
+            cbBrokerId.ItemsSource = V3AuthorityCatalog.BrokerIds;
+            tbOwnerProcessId.Text = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
+
             // 濉厖鏁版嵁
             tbDeviceId.Text = device.DeviceId;
             tbDeviceId.IsReadOnly = !_isNew;
@@ -47,6 +54,29 @@
             tbDriverType.Text = device.DriverType;
             cbTransport.SelectedItem = device.Transport;
             tbEndpoint.Text = device.Endpoint;
+
+            // 鎵ц浣嶇疆鍥炴樉锛氭棫鏁版嵁 AuthorityId 涓虹┖鏃堕粯璁ゆ湰鏈� Local 鍩�
+            _execModeSyncing = true;
+            rbLocal.IsChecked = device.ExecutionMode == ExecutionModeKind.Local;
+            rbBroker.IsChecked = device.ExecutionMode == ExecutionModeKind.Broker;
+            cbAuthority.SelectedItem = string.IsNullOrWhiteSpace(device.AuthorityId)
+                ? V3AuthorityCatalog.LocalAuthorityId : device.AuthorityId;
+            if (cbAuthority.SelectedItem == null)
+            {
+                // 瀛橀噺鍊间笉鍦ㄥ綋鍓嶅�欓�夋灇涓句腑锛氫繚鐣欏睍绀哄苟杩藉姞
+                var list = V3AuthorityCatalog.AuthorityIds.ToList();
+                list.Add(device.AuthorityId);
+                cbAuthority.ItemsSource = list;
+                cbAuthority.SelectedItem = device.AuthorityId;
+            }
+            cbBrokerId.SelectedItem = device.BrokerId;
+            if (!string.IsNullOrWhiteSpace(device.OwnerProcessId))
+            {
+                tbOwnerProcessId.Text = device.OwnerProcessId;
+            }
+            _execModeSyncing = false;
+            RefreshExecModeUi();
+            RefreshSessionKeyCandidates();
 
             // 榛樿椹卞姩绫诲瀷寤鸿 & 绔偣鎻愮ず
             UpdateDriverHint();
@@ -63,6 +93,9 @@
                 _channels = new ObservableCollection<DeviceChannel>();
             }
             channelListView.ItemsSource = _channels;
+
+            // 閫氶亾 SessionKey 宸插姞杞斤紝閲嶆柊鐢熸垚浼氳瘽閿�欓�夛紙Broker 妯″紡锛�
+            RefreshSessionKeyCandidates();
 
             return ShowDialog();
         }
@@ -211,6 +244,120 @@
 
         #endregion
 
+        #region 鎵ц浣嶇疆锛圴3.0 搂05锛�
+
+        /// <summary>褰撳墠鏄惁 Broker 妯″紡</summary>
+        private bool IsBrokerMode => rbBroker.IsChecked == true;
+
+        private void ExecMode_Changed(object sender, RoutedEventArgs e)
+        {
+            // XAML 鍒濆鍖栭樁娈� rbLocal.IsChecked=True 浼氭彁鍓嶈Е鍙戯紝姝ゆ椂鍏朵綑鎺т欢瀛楁灏氭湭鍒涘缓
+            if (_execModeSyncing || rbBroker == null || cbAuthority == null) return;
+            _execModeSyncing = true;
+            // Broker 璁惧鐨� AuthorityId 鍗冲叾 Broker 鍩燂紱鍒囧洖 Local 鏃朵娇鐢ㄦ湰鏈洪粯璁ゅ煙
+            if (IsBrokerMode)
+            {
+                // 褰撳墠浠嶄负 local 鍩燂紙鎴栨湭閫夛級鈫� 鍒囧埌棣栦釜 Broker 鍩�
+                if (V3AuthorityCatalog.IsLocalAuthority(cbAuthority.SelectedItem as string) || cbAuthority.SelectedItem == null)
+                {
+                    cbAuthority.SelectedItem = V3AuthorityCatalog.BrokerIds.FirstOrDefault()
+                        ?? V3AuthorityCatalog.AuthorityIds.LastOrDefault(a => !V3AuthorityCatalog.IsLocalAuthority(a));
+                }
+            }
+            else
+            {
+                cbAuthority.SelectedItem = V3AuthorityCatalog.LocalAuthorityId;
+            }
+            _execModeSyncing = false;
+            RefreshExecModeUi();
+        }
+
+        private void CbAuthority_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if (_execModeSyncing || rbLocal == null || rbBroker == null || cbBrokerId == null) return;
+            var auth = cbAuthority.SelectedItem as string;
+            if (string.IsNullOrEmpty(auth)) return;
+            _execModeSyncing = true;
+            // 閫変腑 local- 鍩熲啋Local锛涢�変腑 Broker 鍩熲啋Broker 骞跺悓姝� BrokerId
+            if (V3AuthorityCatalog.IsLocalAuthority(auth))
+            {
+                rbLocal.IsChecked = true;
+            }
+            else
+            {
+                rbBroker.IsChecked = true;
+                cbBrokerId.SelectedItem = V3AuthorityCatalog.BrokerIds.Contains(auth) ? auth : cbBrokerId.SelectedItem;
+            }
+            _execModeSyncing = false;
+            RefreshExecModeUi();
+        }
+
+        /// <summary>鏍规嵁妯″紡鍒囨崲 Broker 瀛楁鍙鎬т笌鍙娲剧敓鐨勮闂瓥鐣�</summary>
+        private void RefreshExecModeUi()
+        {
+            spBroker.Visibility = IsBrokerMode ? Visibility.Visible : Visibility.Collapsed;
+            tbAccessPolicy.Text = (IsBrokerMode ? ExecutionModeKind.Broker : ExecutionModeKind.Local)
+                switch
+                {
+                    ExecutionModeKind.Broker => "鍏变韩浠茶 路 Broker SessionGate 浠g悊",
+                    _ => "鐙崰鐩磋繛 路 鏈繘绋嬫寔鏈夌墿鐞嗕細璇�"
+                };
+            if (IsBrokerMode)
+            {
+                RefreshSessionKeyCandidates();
+            }
+        }
+
+        /// <summary>
+        /// PhysicalSessionKey 鍊欓�夛細鐢辩鐐硅鑼冨寲鐨勫啓姝诲瓧绗︿覆锛圴3.0 搂04锛氬湴鍧�鍒悕蹇呴』褰掍竴涓哄悓涓�鐗╃悊韬唤锛�
+        /// </summary>
+        private void RefreshSessionKeyCandidates()
+        {
+            var deviceId = tbDeviceId.Text?.Trim() ?? string.Empty;
+            var transport = cbTransport.SelectedItem is TransportType tt ? tt : TransportType.Tcp;
+            var endpoint = tbEndpoint.Text?.Trim() ?? string.Empty;
+
+            var candidates = new List<string>();
+            if (transport == TransportType.Can)
+            {
+                var bus = endpoint.Split(':')[0].Trim();
+                if (!string.IsNullOrEmpty(bus)) candidates.Add($"can/{bus}/main");
+            }
+            else if (transport == TransportType.Tcp && endpoint.Contains(":"))
+            {
+                candidates.Add($"tcp/{endpoint}/main");
+            }
+            else if (transport == TransportType.Serial)
+            {
+                var com = endpoint.Split(':')[0].Trim();
+                if (!string.IsNullOrEmpty(com)) candidates.Add($"serial/{com}/main");
+            }
+            else if (transport == TransportType.Visa)
+            {
+                candidates.Add($"visa/{deviceId}/main");
+            }
+            else if (transport == TransportType.SDK)
+            {
+                candidates.Add($"sdk/{deviceId}/main");
+            }
+            if (!string.IsNullOrEmpty(deviceId)) candidates.Add($"{deviceId}/main");
+
+            // 宸插瓨閫氶亾 SessionKey 涔熷垪鍏ュ�欓�夛紙鍘婚噸锛�
+            foreach (var key in _channels.Select(c => c.SessionKey)
+                         .Where(k => !string.IsNullOrWhiteSpace(k)).Distinct())
+            {
+                candidates.Add(key);
+            }
+            candidates = candidates.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
+
+            string? current = _device?.PhysicalSessionKey;
+            cbSessionKey.ItemsSource = candidates;
+            cbSessionKey.Text = !string.IsNullOrWhiteSpace(current) ? current
+                : (candidates.Count > 0 ? candidates[0] : string.Empty);
+        }
+
+        #endregion
+
         #region 淇濆瓨/鍙栨秷
 
         private void SaveBtn_Click(object sender, RoutedEventArgs e)
@@ -275,12 +422,42 @@
                     }
                 }
 
+                // 鎵ц浣嶇疆锛圴3.0 搂05锛夋牎楠�
+                var authorityId = cbAuthority.SelectedItem as string ?? string.Empty;
+                if (string.IsNullOrWhiteSpace(authorityId))
+                {
+                    ToastHelper.Warning("浠茶鍩熶笉鑳戒负绌猴紝璇蜂粠鍊欓�変腑閫夋嫨");
+                    return;
+                }
+                string brokerId = string.Empty, sessionKey = string.Empty, ownerPid = string.Empty;
+                if (IsBrokerMode)
+                {
+                    brokerId = cbBrokerId.SelectedItem as string ?? string.Empty;
+                    if (string.IsNullOrWhiteSpace(brokerId))
+                    {
+                        ToastHelper.Warning("鍏变韩浠櫒锛圔roker锛夊繀椤绘寚瀹� BrokerId");
+                        return;
+                    }
+                    sessionKey = cbSessionKey.Text?.Trim() ?? string.Empty;
+                    if (string.IsNullOrWhiteSpace(sessionKey))
+                    {
+                        ToastHelper.Warning("鍏变韩浠櫒锛圔roker锛夊繀椤绘寚瀹氱墿鐞嗕細璇濋敭");
+                        return;
+                    }
+                    ownerPid = tbOwnerProcessId.Text?.Trim() ?? string.Empty;
+                }
+
                 // 淇濆瓨璁惧
                 _device.DeviceId = deviceId;
                 _device.Kind = kind;
                 _device.DriverType = tbDriverType.Text?.Trim() ?? string.Empty;
                 _device.Transport = transport;
                 _device.Endpoint = endpoint;
+                _device.ExecutionMode = IsBrokerMode ? ExecutionModeKind.Broker : ExecutionModeKind.Local;
+                _device.AuthorityId = authorityId;
+                _device.BrokerId = brokerId;
+                _device.PhysicalSessionKey = sessionKey;
+                _device.OwnerProcessId = ownerPid;
 
                 _model.SaveDevice(_device);
 
@@ -309,6 +486,10 @@
         private void CbTransport_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
             UpdateEndpointHint();
+            if (IsBrokerMode)
+            {
+                RefreshSessionKeyCandidates();
+            }
         }
 
         /// <summary>

--
Gitblit v1.9.1