用户确认导入导出策略:1) 配置冲突按 ConfigName + CANLINInfo 判重,CAN/LIN/CANFD 可同名;2) 增量导入对同名配置自动重命名(_import_时间戳);3) JSON 字段尽量与数据库模型一致,可不加注释;4) LogicRule 也需随配置导入导出,规则同名冲突采用覆盖更新;5) 导入后需同步刷新 CAN/CANFD/LIN 以及 ZLG 对应界面;6) 入口按现有系统菜单弹窗(ComDialogEvent + DialogService)接入。

This commit is contained in:
2026-03-30 14:33:10 +08:00
parent aa6d930374
commit ea58e0335e
14 changed files with 1610 additions and 4 deletions

View File

@@ -7,6 +7,7 @@
<add key="connecting5" value="Data Source=@Address@; Attachs=ems.db; Pooling=true;Min Pool Size=1"/>
<add key="PLCScan" value="600"/>
<add key="PLCIP" value="127.0.0.1"/>
<add key="CompressorDisplacementCc" value="35CC"/>
<add key="FluidsPath" value="C:\Program Files (x86)\REFPROP\fluids"/>
<add key="Cryogen" value="R134a"/>
<add key="LocalDBPath" value="D:\MSDB\LocalDb\CapMachineDb"/>

View File

@@ -140,6 +140,7 @@ namespace CapMachine.Wpf
containerRegistry.RegisterSingleton<SysRunService>();
containerRegistry.RegisterSingleton<ComActionService>();
containerRegistry.RegisterSingleton<CanLinConfigImExportService>();
containerRegistry.RegisterSingleton<ProRuntimeService>();
@@ -204,6 +205,7 @@ namespace CapMachine.Wpf
containerRegistry.RegisterDialog<DialogLimitConfigView, DialogLimitConfigViewModel>();
containerRegistry.RegisterDialog<DialogSuperHeatCoolConfigView, DialogSuperHeatCoolConfigViewModel>();
containerRegistry.RegisterDialog<DialogLogicRuleView, DialogLogicRuleViewModel>();
containerRegistry.RegisterDialog<DialogCanLinConfigImExportView, DialogCanLinConfigImExportViewModel>();
containerRegistry.RegisterDialog<DialogCANFdSchConfigView, DialogCANFdSchConfigViewModel>();
containerRegistry.RegisterDialog<DialogCANSchConfigView, DialogCANSchConfigViewModel>();

View File

@@ -0,0 +1,11 @@
using Prism.Events;
namespace CapMachine.Wpf.PrismEvent
{
/// <summary>
/// CAN/CANFD/LIN 配置变更事件。
/// </summary>
public class CanLinConfigChangedEvent : PubSubEvent<string>
{
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -70,6 +70,9 @@ namespace CapMachine.Wpf.Services
}
ShowLogicRule(msg.Par);
break;
case "CAN/CANFD/LIN配置导入导出":
ShowCanLinConfigImExport(msg.Par);
break;
default:
break;
}
@@ -136,6 +139,20 @@ namespace CapMachine.Wpf.Services
});
}
/// <summary>
/// CAN/CANFD/LIN 配置导入导出弹窗。
/// </summary>
/// <param name="par">透传参数。</param>
private void ShowCanLinConfigImExport(object par)
{
DialogService.ShowDialog("DialogCanLinConfigImExportView", new DialogParameters() { { "Name", par } }, (dialogResult) =>
{
if (dialogResult.Result == ButtonResult.OK)
{
}
});
}

View File

@@ -44,10 +44,10 @@ namespace CapMachine.Wpf.Services
{
new NavigationItem("Rule","规则转换","DialogLogicRuleView"),
}),
//new NavigationItem("", "PID设置","",new ObservableCollection<NavigationItem>()
//{
// new NavigationItem("Circle","转速PID",""),
//}),
new NavigationItem("", "配置导出","",new ObservableCollection<NavigationItem>()
{
new NavigationItem("","CAN/CANFD/LIN配置导入导出","DialogCanLinConfigImExport"),
}),
//new NavigationItem("", "通信配置","",new ObservableCollection<NavigationItem>()
//{
// new NavigationItem("Circle","CAN配置","CANConfigView"),

View File

@@ -57,6 +57,7 @@ namespace CapMachine.Wpf.ViewModels
DialogService = dialogService;
EventAggregator.GetEvent<LogicRuleChangeEvent>().Subscribe(LogicRuleChangeEventCall);
EventAggregator.GetEvent<CanLinConfigChangedEvent>().Subscribe(CanLinConfigChangedEventCall);
//数据波特率
DataBaudRateCbxItems = new ObservableCollection<CbxItems>()
@@ -150,6 +151,16 @@ namespace CapMachine.Wpf.ViewModels
//InitWriteRuleCbx();
}
/// <summary>
/// CAN/LIN 配置导入后刷新当前页面。
/// </summary>
/// <param name="msg">事件消息。</param>
private void CanLinConfigChangedEventCall(string msg)
{
InitLoadCanConfigPro();
InitWriteRuleCbx();
}
/// <summary>
/// 初始化写规则下拉框
/// </summary>

View File

@@ -55,6 +55,7 @@ namespace CapMachine.Wpf.ViewModels
DialogService = dialogService;
EventAggregator.GetEvent<LogicRuleChangeEvent>().Subscribe(LogicRuleChangeEventCall);
EventAggregator.GetEvent<CanLinConfigChangedEvent>().Subscribe(CanLinConfigChangedEventCall);
//仲裁波特率
ArbBaudRateCbxItems = new ObservableCollection<CbxItems>()
@@ -170,6 +171,16 @@ namespace CapMachine.Wpf.ViewModels
//InitWriteRuleCbx();
}
/// <summary>
/// CAN/LIN 配置导入后刷新当前页面。
/// </summary>
/// <param name="msg">事件消息。</param>
private void CanLinConfigChangedEventCall(string msg)
{
InitLoadCanConfigPro();
InitWriteRuleCbx();
}
/// <summary>
/// 初始化写规则下拉框
/// </summary>

View File

@@ -0,0 +1,319 @@
using CapMachine.Core;
using CapMachine.Wpf.PrismEvent;
using CapMachine.Wpf.Services;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Events;
using Prism.Services.Dialogs;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
namespace CapMachine.Wpf.ViewModels
{
/// <summary>
/// CAN/CANFD/LIN 配置导入导出弹窗 ViewModel。
/// </summary>
public class DialogCanLinConfigImExportViewModel : DialogViewModel
{
/// <summary>
/// 初始化导入导出弹窗。
/// </summary>
/// <param name="canLinConfigImExportService">导入导出服务。</param>
/// <param name="eventAggregator">事件聚合器。</param>
public DialogCanLinConfigImExportViewModel(
CanLinConfigImExportService canLinConfigImExportService,
IEventAggregator eventAggregator)
{
CanLinConfigImExportService = canLinConfigImExportService;
EventAggregator = eventAggregator;
Title = "CAN/CANFD/LIN配置导入导出";
ImportModes = new ObservableCollection<ImportModeOption>
{
new ImportModeOption { Text = "覆盖导入(同名同类型先删除后导入)", Mode = CanLinImportMode.Overwrite },
new ImportModeOption { Text = "增量导入(同名同类型自动重命名)", Mode = CanLinImportMode.IncrementalRename },
};
SelectedImportMode = ImportModes.FirstOrDefault();
}
/// <summary>
/// 导入导出服务。
/// </summary>
public CanLinConfigImExportService CanLinConfigImExportService { get; }
/// <summary>
/// 事件聚合器。
/// </summary>
public IEventAggregator EventAggregator { get; }
private string _importFilePath = string.Empty;
/// <summary>
/// 导入文件路径。
/// </summary>
public string ImportFilePath
{
get { return _importFilePath; }
set { _importFilePath = value; RaisePropertyChanged(); }
}
private ObservableCollection<ImportModeOption> _importModes = new ObservableCollection<ImportModeOption>();
/// <summary>
/// 导入模式集合。
/// </summary>
public ObservableCollection<ImportModeOption> ImportModes
{
get { return _importModes; }
set { _importModes = value; RaisePropertyChanged(); }
}
private ImportModeOption? _selectedImportMode;
/// <summary>
/// 当前选中的导入模式。
/// </summary>
public ImportModeOption? SelectedImportMode
{
get { return _selectedImportMode; }
set { _selectedImportMode = value; RaisePropertyChanged(); }
}
private string _resultMessage = string.Empty;
/// <summary>
/// 操作结果消息。
/// </summary>
public string ResultMessage
{
get { return _resultMessage; }
set { _resultMessage = value; RaisePropertyChanged(); }
}
private DelegateCommand? _browseImportFileCmd;
/// <summary>
/// 选择导入文件命令。
/// </summary>
public DelegateCommand BrowseImportFileCmd
{
get
{
if (_browseImportFileCmd == null)
{
_browseImportFileCmd = new DelegateCommand(BrowseImportFile);
}
return _browseImportFileCmd;
}
}
private DelegateCommand? _importCmd;
/// <summary>
/// 导入命令。
/// </summary>
public DelegateCommand ImportCmd
{
get
{
if (_importCmd == null)
{
_importCmd = new DelegateCommand(ImportConfig);
}
return _importCmd;
}
}
private DelegateCommand? _exportCmd;
/// <summary>
/// 导出命令。
/// </summary>
public DelegateCommand ExportCmd
{
get
{
if (_exportCmd == null)
{
_exportCmd = new DelegateCommand(ExportConfig);
}
return _exportCmd;
}
}
private DelegateCommand? _closeCmd;
/// <summary>
/// 关闭命令。
/// </summary>
public DelegateCommand CloseCmd
{
get
{
if (_closeCmd == null)
{
_closeCmd = new DelegateCommand(CloseDialog);
}
return _closeCmd;
}
}
/// <summary>
/// 打开文件选择框并选择导入文件。
/// </summary>
private void BrowseImportFile()
{
try
{
var openFileDialog = new OpenFileDialog
{
Filter = "JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
CheckFileExists = true,
CheckPathExists = true,
};
var ok = openFileDialog.ShowDialog();
if (ok == true)
{
ImportFilePath = openFileDialog.FileName;
}
}
catch (Exception ex)
{
MessageBox.Show($"选择导入文件失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 执行配置导入。
/// </summary>
private void ImportConfig()
{
try
{
if (string.IsNullOrWhiteSpace(ImportFilePath))
{
MessageBox.Show("请先选择导入文件", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if (SelectedImportMode == null)
{
MessageBox.Show("请选择导入模式", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
var result = CanLinConfigImExportService.ImportFromFile(ImportFilePath, SelectedImportMode.Mode);
ResultMessage = BuildResultText(result);
if (!result.IsSuccess)
{
MessageBox.Show(ResultMessage, "导入失败", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
EventAggregator.GetEvent<CanLinConfigChangedEvent>().Publish("import");
EventAggregator.GetEvent<LogicRuleChangeEvent>().Publish("import");
MessageBox.Show(ResultMessage, "导入成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
ResultMessage = $"导入失败:{ex.Message}";
MessageBox.Show(ResultMessage, "导入失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 执行配置导出。
/// </summary>
private void ExportConfig()
{
try
{
var saveFileDialog = new SaveFileDialog
{
Filter = "JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
DefaultExt = "json",
FileName = $"CanLinConfigExport_{DateTime.Now:yyyyMMddHHmmss}.json",
};
var ok = saveFileDialog.ShowDialog();
if (ok != true)
{
return;
}
var result = CanLinConfigImExportService.ExportToFile(saveFileDialog.FileName);
ResultMessage = BuildResultText(result);
if (!result.IsSuccess)
{
MessageBox.Show(ResultMessage, "导出失败", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
MessageBox.Show(ResultMessage, "导出成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
ResultMessage = $"导出失败:{ex.Message}";
MessageBox.Show(ResultMessage, "导出失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 关闭弹窗。
/// </summary>
private void CloseDialog()
{
RaiseRequestClose(new DialogResult(ButtonResult.Cancel));
}
/// <summary>
/// 构建结果文本。
/// </summary>
/// <param name="result">执行结果。</param>
/// <returns>显示文本。</returns>
private static string BuildResultText(CanLinConfigImExportResult result)
{
var builder = new StringBuilder();
builder.AppendLine(result.Message);
if (result.RenamedConfigs != null && result.RenamedConfigs.Count > 0)
{
builder.AppendLine("重命名明细:");
foreach (var line in result.RenamedConfigs)
{
builder.AppendLine($"- {line}");
}
}
return builder.ToString();
}
/// <summary>
/// 弹窗打开回调。
/// </summary>
/// <param name="parameters">弹窗参数。</param>
public override void OnDialogOpened(IDialogParameters parameters)
{
ResultMessage = string.Empty;
}
/// <summary>
/// 导入模式选项。
/// </summary>
public class ImportModeOption
{
/// <summary>
/// 文本。
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// 模式值。
/// </summary>
public CanLinImportMode Mode { get; set; }
}
}
}

View File

@@ -4,6 +4,7 @@ using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.LinDrive;
using CapMachine.Wpf.PrismEvent;
using CapMachine.Wpf.Services;
using Prism.Commands;
using Prism.Events;
@@ -55,6 +56,7 @@ namespace CapMachine.Wpf.ViewModels
//MachineDataService = machineDataService;
DialogService = dialogService;
EventAggregator.GetEvent<CanLinConfigChangedEvent>().Subscribe(CanLinConfigChangedEventCall);
//数据波特率
DataBaudRateCbxItems = new ObservableCollection<CbxItems>()
@@ -144,6 +146,16 @@ namespace CapMachine.Wpf.ViewModels
//InitWriteRuleCbx();
}
/// <summary>
/// CAN/LIN 配置导入后刷新当前页面。
/// </summary>
/// <param name="msg">事件消息。</param>
private void CanLinConfigChangedEventCall(string msg)
{
InitLoadLinConfigPro();
InitWriteRuleCbx();
}
/// <summary>
/// 初始化写规则下拉框
/// </summary>

View File

@@ -3,6 +3,7 @@ using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.PrismEvent;
using CapMachine.Wpf.Services;
using CapMachine.Wpf.Views;
using ImTools;
@@ -79,6 +80,7 @@ namespace CapMachine.Wpf.ViewModels
ZlgCanDriveService = zlgCanDriveService;
ZlgLinDriveService = zlgLinDriveService;
Mapper = mapper;
EventAggregator.GetEvent<CanLinConfigChangedEvent>().Subscribe(CanLinConfigChangedEventCall);
SelectedMode = ZlgCanMode.Can;
@@ -129,6 +131,16 @@ namespace CapMachine.Wpf.ViewModels
InitLoadCanConfigPro();
}
/// <summary>
/// CAN/LIN 配置导入后刷新当前页面。
/// </summary>
/// <param name="msg">事件消息。</param>
private void CanLinConfigChangedEventCall(string msg)
{
InitWriteRuleCbx();
ReloadCurrentConfigPro();
}
/// <summary>
/// 初始化“写入规则”下拉框数据源。
/// </summary>

View File

@@ -3,6 +3,7 @@ using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.LinDrive;
using CapMachine.Wpf.PrismEvent;
using CapMachine.Wpf.Services;
using CapMachine.Wpf.Views;
using ImTools;
@@ -46,10 +47,20 @@ namespace CapMachine.Wpf.ViewModels
ComActionService = comActionService;
LogicRuleService = logicRuleService;
Mapper = mapper;
EventAggregator.GetEvent<CanLinConfigChangedEvent>().Subscribe(CanLinConfigChangedEventCall);
InitLoadLinConfigPro();
}
/// <summary>
/// CAN/LIN 配置导入后刷新当前页面。
/// </summary>
/// <param name="msg">事件消息。</param>
private void CanLinConfigChangedEventCall(string msg)
{
ReloadCurrentConfigPro();
}
/// <summary>
/// Prism 弹窗服务。
/// </summary>

View File

@@ -0,0 +1,83 @@
<UserControl
x:Class="CapMachine.Wpf.Views.DialogCanLinConfigImExportView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CapMachine.Wpf.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Width="800"
Height="450">
<Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
FontSize="18"
FontWeight="Bold"
Text="CAN/CANFD/LIN 配置导入导出" />
<Grid Grid.Row="1" Margin="0,12,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
Margin="0,0,8,0"
IsReadOnly="True"
Text="{Binding ImportFilePath, UpdateSourceTrigger=PropertyChanged}" />
<Button
Grid.Column="1"
Padding="16,4"
Command="{Binding BrowseImportFileCmd}"
Content="选择导入文件" />
</Grid>
<StackPanel
Grid.Row="2"
Margin="0,12,0,0"
Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Text="导入模式:" />
<ComboBox
Width="320"
Margin="8,0,0,0"
DisplayMemberPath="Text"
ItemsSource="{Binding ImportModes}"
SelectedItem="{Binding SelectedImportMode}" />
</StackPanel>
<TextBox
Grid.Row="3"
Margin="0,12,0,0"
HorizontalScrollBarVisibility="Auto"
IsReadOnly="True"
Text="{Binding ResultMessage}"
VerticalScrollBarVisibility="Auto" />
<StackPanel
Grid.Row="4"
Margin="0,12,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Margin="0,0,8,0"
Padding="16,4"
Command="{Binding ExportCmd}"
Content="导出" />
<Button
Margin="0,0,8,0"
Padding="16,4"
Command="{Binding ImportCmd}"
Content="导入" />
<Button
Padding="16,4"
Command="{Binding CloseCmd}"
Content="关闭" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CapMachine.Wpf.Views
{
/// <summary>
/// DialogCanLinConfigImExport.xaml 的交互逻辑
/// </summary>
public partial class DialogCanLinConfigImExportView : UserControl
{
public DialogCanLinConfigImExportView()
{
InitializeComponent();
}
}
}