From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点

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

diff --git a/Plugin.DeviceConfig/DeviceEditModal.xaml.cs b/Plugin.DeviceConfig/DeviceEditModal.xaml.cs
new file mode 100644
index 0000000..9113dca
--- /dev/null
+++ b/Plugin.DeviceConfig/DeviceEditModal.xaml.cs
@@ -0,0 +1,368 @@
+using HMI.UI.Util;
+using Panuon.WPF.UI;
+using Plugin.DeviceConfig.Entity;
+using Plugin.DeviceConfig.Model;
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Plugin.DeviceConfig
+{
+    /// <summary>
+    /// DeviceEditModal.xaml 鐨勪氦浜掗�昏緫
+    /// </summary>
+    public partial class DeviceEditModal : WindowX
+    {
+        private DeviceConfigModel _model;
+        private DeviceDefinition _device;
+        private ObservableCollection<DeviceChannel> _channels = new();
+        private bool _isNew;
+
+        public DeviceEditModal()
+        {
+            DataContext = this;
+            InitializeComponent();
+        }
+
+        /// <summary>
+        /// 鎵撳紑寮圭獥
+        /// </summary>
+        public bool? Open(DeviceDefinition device, DeviceConfigModel model)
+        {
+            _model = model;
+            _device = device;
+            _isNew = string.IsNullOrEmpty(device.DeviceId);
+
+            // 鍒濆鍖栨灇涓句笅鎷�
+            cbKind.ItemsSource = Enum.GetValues(typeof(DeviceKind)).Cast<DeviceKind>().ToList();
+            cbTransport.ItemsSource = Enum.GetValues(typeof(TransportType)).Cast<TransportType>().ToList();
+            cbTransport.SelectionChanged += CbTransport_SelectionChanged;
+
+            // 濉厖鏁版嵁
+            tbDeviceId.Text = device.DeviceId;
+            tbDeviceId.IsReadOnly = !_isNew;
+            cbKind.SelectedItem = device.Kind;
+            tbDriverType.Text = device.DriverType;
+            cbTransport.SelectedItem = device.Transport;
+            tbEndpoint.Text = device.Endpoint;
+
+            // 榛樿椹卞姩绫诲瀷寤鸿 & 绔偣鎻愮ず
+            UpdateDriverHint();
+            UpdateEndpointHint();
+
+            // 鍔犺浇閫氶亾
+            if (!_isNew && !string.IsNullOrEmpty(device.DeviceId))
+            {
+                var chList = _model.GetChannelsByDevice(device.DeviceId);
+                _channels = new ObservableCollection<DeviceChannel>(chList);
+            }
+            else
+            {
+                _channels = new ObservableCollection<DeviceChannel>();
+            }
+            channelListView.ItemsSource = _channels;
+
+            return ShowDialog();
+        }
+
+        #region 閫氶亾鎿嶄綔
+
+        private void AddChannel_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                if (!int.TryParse(tbChId.Text, out int chId) || chId < 0)
+                {
+                    ToastHelper.Warning("璇疯緭鍏ユ湁鏁堢殑閫氶亾缂栧彿锛堥潪璐熸暣鏁帮級");
+                    return;
+                }
+                if (_channels.Any(c => c.ChannelId == chId))
+                {
+                    ToastHelper.Warning($"閫氶亾 {chId} 宸插瓨鍦�");
+                    return;
+                }
+
+                double.TryParse(tbChVolt.Text, out double volt);
+                double.TryParse(tbChCurr.Text, out double curr);
+
+                var ch = new DeviceChannel
+                {
+                    DeviceId = _device.DeviceId ?? tbDeviceId.Text,
+                    ChannelId = chId,
+                    Capability = tbChCap.Text ?? string.Empty,
+                    MaxVoltage = volt,
+                    MaxCurrent = curr,
+                };
+                _channels.Add(ch);
+                ClearChannelInputs();
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Error($"鏂板閫氶亾澶辫触: {ex.Message}");
+            }
+        }
+
+        private void EditChannel_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                if (sender is Button btn && btn.Tag is DeviceChannel ch)
+                {
+                    tbChId.Text = ch.ChannelId.ToString();
+                    tbChCap.Text = ch.Capability;
+                    tbChVolt.Text = ch.MaxVoltage.ToString("F2");
+                    tbChCurr.Text = ch.MaxCurrent.ToString("F2");
+                }
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Error($"鍔犺浇閫氶亾鏁版嵁澶辫触: {ex.Message}");
+            }
+        }
+
+        private void DeleteChannel_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                if (sender is Button btn && btn.Tag is DeviceChannel ch)
+                {
+                    if (MsgBoxHelper.WarnMessage(this, $"纭畾瑕佸垹闄ら�氶亾 {ch.ChannelId} 鍚楋紵") == MessageBoxResult.OK)
+                    {
+                        _channels.Remove(ch);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Error($"鍒犻櫎閫氶亾澶辫触: {ex.Message}");
+            }
+        }
+
+        private void SaveChannel_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                if (!int.TryParse(tbChId.Text, out int chId) || chId < 0)
+                {
+                    ToastHelper.Warning("璇疯緭鍏ユ湁鏁堢殑閫氶亾缂栧彿");
+                    return;
+                }
+
+                double.TryParse(tbChVolt.Text, out double volt);
+                double.TryParse(tbChCurr.Text, out double curr);
+
+                var existing = _channels.FirstOrDefault(c => c.ChannelId == chId);
+                if (existing != null)
+                {
+                    existing.Capability = tbChCap.Text ?? string.Empty;
+                    existing.MaxVoltage = volt;
+                    existing.MaxCurrent = curr;
+                }
+                else
+                {
+                    _channels.Add(new DeviceChannel
+                    {
+                        DeviceId = _device.DeviceId ?? tbDeviceId.Text,
+                        ChannelId = chId,
+                        Capability = tbChCap.Text ?? string.Empty,
+                        MaxVoltage = volt,
+                        MaxCurrent = curr,
+                    });
+                }
+                ClearChannelInputs();
+                ToastHelper.Success("閫氶亾宸蹭繚瀛�");
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Error($"淇濆瓨閫氶亾澶辫触: {ex.Message}");
+            }
+        }
+
+        private void DelChannel_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                var selected = channelListView.SelectedItem as DeviceChannel;
+                if (selected == null)
+                {
+                    ToastHelper.Warning("璇峰厛閫変腑瑕佸垹闄ょ殑閫氶亾");
+                    return;
+                }
+                if (MsgBoxHelper.WarnMessage(this, $"纭畾瑕佸垹闄ら�氶亾 {selected.ChannelId} 鍚楋紵") == MessageBoxResult.OK)
+                {
+                    _channels.Remove(selected);
+                }
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Error($"鍒犻櫎閫氶亾澶辫触: {ex.Message}");
+            }
+        }
+
+        private void ClearChannelInputs()
+        {
+            tbChId.Text = string.Empty;
+            tbChCap.Text = string.Empty;
+            tbChVolt.Text = string.Empty;
+            tbChCurr.Text = string.Empty;
+        }
+
+        #endregion
+
+        #region 淇濆瓨/鍙栨秷
+
+        private void SaveBtn_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                // 楠岃瘉
+                var deviceId = tbDeviceId.Text?.Trim();
+                if (string.IsNullOrEmpty(deviceId))
+                {
+                    ToastHelper.Warning("璁惧ID涓嶈兘涓虹┖");
+                    return;
+                }
+
+                if (cbKind.SelectedItem is not DeviceKind kind)
+                {
+                    ToastHelper.Warning("璇烽�夋嫨璁惧绫诲瀷");
+                    return;
+                }
+
+                if (cbTransport.SelectedItem is not TransportType transport)
+                {
+                    ToastHelper.Warning("璇烽�夋嫨浼犺緭鏂瑰紡");
+                    return;
+                }
+
+                var endpoint = tbEndpoint.Text?.Trim();
+                if (string.IsNullOrEmpty(endpoint))
+                {
+                    ToastHelper.Warning("杩炴帴绔偣涓嶈兘涓虹┖");
+                    return;
+                }
+
+                // 楠岃瘉 Endpoint 鏍煎紡
+                if (transport == TransportType.Tcp)
+                {
+                    if (!endpoint.Contains(":") && !endpoint.Contains("."))
+                    {
+                        ToastHelper.Warning("TCP绔偣鏍煎紡涓嶆纭紝搴斾负 IP:Port 鏍煎紡");
+                        return;
+                    }
+                }
+                else if (transport == TransportType.Can)
+                {
+                    // CAN 绔偣鏍煎紡锛氭�荤嚎鍚嶇О:鑺傜偣缂栧彿 濡� "CAN_BUS_1:0"
+                    var parts = endpoint.Split(':');
+                    if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[0]) || !int.TryParse(parts[1], out int nodeIdx) || nodeIdx < 0)
+                    {
+                        ToastHelper.Warning("CAN绔偣鏍煎紡涓嶆纭紝搴斾负 鎬荤嚎鍚嶇О:鑺傜偣缂栧彿锛堝 CAN_BUS_1:0锛�");
+                        return;
+                    }
+                }
+
+                // 妫�鏌� DeviceId 鏄惁閲嶅锛堟柊澧炴椂锛�
+                if (_isNew)
+                {
+                    var existing = _model.GetDeviceById(deviceId);
+                    if (existing != null)
+                    {
+                        ToastHelper.Warning($"璁惧ID [{deviceId}] 宸插瓨鍦�");
+                        return;
+                    }
+                }
+
+                // 淇濆瓨璁惧
+                _device.DeviceId = deviceId;
+                _device.Kind = kind;
+                _device.DriverType = tbDriverType.Text?.Trim() ?? string.Empty;
+                _device.Transport = transport;
+                _device.Endpoint = endpoint;
+
+                _model.SaveDevice(_device);
+
+                // 淇濆瓨閫氶亾
+                foreach (var ch in _channels)
+                {
+                    ch.DeviceId = deviceId;
+                    _model.SaveChannel(ch);
+                }
+
+                DialogResult = true;
+                Close();
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Error($"淇濆瓨澶辫触: {ex.Message}");
+            }
+        }
+
+        private void CancelBtn_Click(object sender, RoutedEventArgs e)
+        {
+            DialogResult = false;
+            Close();
+        }
+
+        private void CbTransport_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            UpdateEndpointHint();
+        }
+
+        /// <summary>
+        /// 鏍规嵁浼犺緭鏂瑰紡鏇存柊绔偣杈撳叆妗嗘彁绀�
+        /// </summary>
+        private void UpdateEndpointHint()
+        {
+            if (cbTransport.SelectedItem is TransportType tt)
+            {
+                switch (tt)
+                {
+                    case TransportType.Can:
+                        Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "CAN鎬荤嚎绔偣锛屾牸寮�: 鎬荤嚎鍚嶇О:鑺傜偣缂栧彿锛堝 CAN_BUS_1:0锛�");
+                        break;
+                    case TransportType.Serial:
+                        Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "涓插彛鍙凤紝濡� COM3:115200:8:N:1");
+                        break;
+                    case TransportType.Visa:
+                        Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "VISG 鍦板潃锛屽 TCPIP0::192.168.1.100::inst0::INSTR");
+                        break;
+                    case TransportType.SDK:
+                        Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "SDK 璁惧鏍囪瘑锛屽 SDK://DeviceName/Instance");
+                        break;
+                    default:
+                        Panuon.WPF.UI.TextBoxHelper.SetWatermark(tbEndpoint, "渚�: 192.168.10.124:30000 鎴� COM3");
+                        break;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 鏍规嵁璁惧绫诲瀷寤鸿榛樿椹卞姩绫诲瀷
+        /// </summary>
+        private void UpdateDriverHint()
+        {
+            // 淇濈暀鐜版湁椹卞姩绫诲瀷锛屼笉鑷姩淇敼銆備粎褰撲负绌烘椂鎻愮ず榛樿鍊�
+            if (string.IsNullOrWhiteSpace(tbDriverType.Text) && cbKind.SelectedItem is DeviceKind kind)
+            {
+                string hint = kind switch
+                {
+                    DeviceKind.CanDevice => "CAN",
+                    DeviceKind.PowerSupply => "SCPI",
+                    DeviceKind.PlcDevice => "S7",
+                    DeviceKind.Chamber => "Tcp",
+                    DeviceKind.DAQ => "Tcp",
+                    _ => ""
+                };
+                if (!string.IsNullOrEmpty(hint))
+                {
+                    tbDriverType.Text = hint;
+                }
+            }
+        }
+
+        #endregion
+    }
+}

--
Gitblit v1.9.1