using HMI.UI.Util;
using Panuon.WPF.UI;
using Plugin.DeviceConfig.Entity;
using Plugin.DeviceConfig.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
namespace Plugin.DeviceConfig
{
///
/// BatchGenerateModal.xaml 的交互逻辑
///
public partial class BatchGenerateModal : WindowX
{
private DeviceConfigModel _model;
private ObservableCollection _previewItems = new();
public BatchGenerateModal()
{
DataContext = this;
InitializeComponent();
}
///
/// 打开弹窗
///
public bool? Open(DeviceConfigModel model)
{
_model = model;
// 初始化枚举下拉
cbDeviceType.ItemsSource = Enum.GetValues(typeof(DeviceKind)).Cast().ToList();
cbTransport.ItemsSource = Enum.GetValues(typeof(TransportType)).Cast().ToList();
// 默认值
cbDeviceType.SelectedIndex = 0;
cbTransport.SelectedIndex = 0;
tbAddressRule.Text = "192.168.10.{0}";
tbSlotStart.Text = "Slot001";
tbDeviceIdPrefix.Text = "DEV";
previewListView.ItemsSource = _previewItems;
return ShowDialog();
}
#region 预览
private void PreviewBtn_Click(object sender, RoutedEventArgs e)
{
try
{
GeneratePreview();
}
catch (Exception ex)
{
tbConflictMsg.Text = $"生成预览失败: {ex.Message}";
tbConflictMsg.Visibility = Visibility.Visible;
}
}
private void GeneratePreview()
{
_previewItems.Clear();
tbConflictMsg.Visibility = Visibility.Collapsed;
if (cbDeviceType.SelectedItem is not DeviceKind kind)
{
ShowConflict("请选择设备类型");
return;
}
if (cbTransport.SelectedItem is not TransportType transport)
{
ShowConflict("请选择传输方式");
return;
}
int count = (int)(niDeviceCount.Value ?? 1);
int channelsPerDevice = (int)(niChannelsPerDevice.Value ?? 1);
int startPort = (int)(niStartPort.Value ?? 30000);
string addressRule = tbAddressRule.Text?.Trim() ?? string.Empty;
string slotStart = tbSlotStart.Text?.Trim() ?? string.Empty;
string prefix = tbDeviceIdPrefix.Text?.Trim() ?? "DEV";
string driverType = tbDriverType.Text?.Trim() ?? string.Empty;
// 检测已有设备ID
var existingDevices = _model.GetAllDevices();
var existingIds = new HashSet(existingDevices.Select(d => d.DeviceId));
var existingEndpoints = new HashSet(existingDevices.Select(d => d.Endpoint));
var conflicts = new List();
var generatedIds = new HashSet();
var generatedEndpoints = new HashSet();
for (int i = 1; i <= count; i++)
{
var deviceId = $"{prefix}{i:D3}";
var endpoint = string.Format(addressRule, i);
if (transport == TransportType.Tcp && !string.IsNullOrEmpty(addressRule))
{
endpoint = $"{endpoint}:{startPort + i - 1}";
}
else if (transport == TransportType.Serial)
{
endpoint = $"COM{i}";
}
// 解析 SlotStart 的序号部分并递增
var slotPrefix = new string(slotStart.TakeWhile(c => !char.IsDigit(c)).ToArray());
var slotNumStr = new string(slotStart.SkipWhile(c => !char.IsDigit(c)).ToArray());
int.TryParse(slotNumStr, out int startNum);
var slotId = $"{slotPrefix}{(startNum + i - 1):D3}";
// 检测冲突
if (existingIds.Contains(deviceId) || generatedIds.Contains(deviceId))
conflicts.Add($"设备ID冲突: {deviceId}");
if (existingEndpoints.Contains(endpoint) || generatedEndpoints.Contains(endpoint))
conflicts.Add($"Endpoint冲突: {endpoint}");
generatedIds.Add(deviceId);
generatedEndpoints.Add(endpoint);
_previewItems.Add(new BatchPreviewItem
{
DeviceId = deviceId,
Kind = kind,
DriverType = driverType,
Transport = transport,
Endpoint = endpoint,
ChannelCount = channelsPerDevice,
SlotStart = slotId,
});
}
if (conflicts.Count > 0)
{
ShowConflict(string.Join("\n", conflicts));
}
}
private void ShowConflict(string msg)
{
tbConflictMsg.Text = msg;
tbConflictMsg.Visibility = Visibility.Visible;
}
#endregion
#region 保存
private void SaveBtn_Click(object sender, RoutedEventArgs e)
{
try
{
if (_previewItems.Count == 0)
{
ToastHelper.Warning("请先生成预览");
return;
}
if (tbConflictMsg.Visibility == Visibility.Visible)
{
if (MsgBoxHelper.WarnMessage(this, "存在冲突项,是否仍要继续保存?") != MessageBoxResult.OK)
{
return;
}
}
int channelsPerDevice = (int)(niChannelsPerDevice.Value ?? 1);
string slotStart = tbSlotStart.Text?.Trim() ?? string.Empty;
foreach (var item in _previewItems)
{
// 保存设备
var device = new DeviceDefinition
{
DeviceId = item.DeviceId,
Kind = item.Kind,
DriverType = item.DriverType,
Transport = item.Transport,
Endpoint = item.Endpoint,
CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now,
};
_model.SaveDevice(device);
// 保存通道
for (int ch = 0; ch < channelsPerDevice; ch++)
{
var channel = new DeviceChannel
{
DeviceId = item.DeviceId,
ChannelId = ch,
Capability = $"CH{ch}",
MaxVoltage = 0,
MaxCurrent = 0,
};
_model.SaveChannel(channel);
}
// 保存 Slot 映射
if (!string.IsNullOrEmpty(item.SlotStart))
{
var mapping = new SlotDeviceMapping
{
SlotId = item.SlotStart,
Capability = "Default",
Version = "1.0",
DeviceId = item.DeviceId,
ChannelId = 0,
MappingVersion = "1.0",
};
_model.SaveSlotMapping(mapping);
}
}
ToastHelper.Success($"成功生成 {_previewItems.Count} 个设备");
DialogResult = true;
Close();
}
catch (Exception ex)
{
ToastHelper.Error($"保存失败: {ex.Message}");
}
}
private void CancelBtn_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
#endregion
}
///
/// 批量生成预览项
///
public class BatchPreviewItem
{
public string DeviceId { get; set; } = string.Empty;
public DeviceKind Kind { get; set; }
public string DriverType { get; set; } = string.Empty;
public TransportType Transport { get; set; }
public string Endpoint { get; set; } = string.Empty;
public int ChannelCount { get; set; }
public string SlotStart { get; set; } = string.Empty;
}
}