CAN/LIN 导入和导出功能

This commit is contained in:
2026-04-09 21:56:22 +08:00
parent 48514b3162
commit 532374d1c4
46 changed files with 20232 additions and 109 deletions

View File

@@ -0,0 +1,358 @@
using AutoMapper;
using CapMachine.Core;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using Prism.Commands;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
namespace CapMachine.Wpf.ViewModels
{
/// <summary>
/// ZLG CAN FD 调度表配置弹窗 ViewModel。
/// 说明:
/// - 调度表项本身由“读写设置”弹窗中的“加入定时调度表”能力生成,这里主要负责:
/// 1) 设置发送方式(并行/顺序)
/// 2) 配置周期Cycle
/// 3) 删除与保存落库
/// - 保存时会使用 InsertOrUpdate 做 Upsert并在保存完成后从数据库重载作为权威数据再回传给调用方。
/// </summary>
public class DialogZlgCANFDSchConfigViewModel : DialogViewModel
{
/// <summary>
/// 构造函数。
/// </summary>
/// <param name="freeSql">FreeSql。</param>
/// <param name="mapper">AutoMapper。</param>
public DialogZlgCANFDSchConfigViewModel(IFreeSql freeSql, IMapper mapper)
{
Title = "调度表 CANFD 配置";
FreeSql = freeSql;
Mapper = mapper;
SendOrderCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){
Key="0",
Text="并行",
},
new CbxItems(){
Key="1",
Text="顺序",
},
};
SchTabIndexCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){
Key="0",
Text="0",
},
};
}
/// <summary>
/// FreeSql。
/// </summary>
public IFreeSql FreeSql { get; }
/// <summary>
/// AutoMapper。
/// </summary>
public IMapper Mapper { get; }
private ObservableCollection<CANFdScheduleConfigDto> _listCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>();
/// <summary>
/// CAN FD 调度表数据集合。
/// </summary>
public ObservableCollection<CANFdScheduleConfigDto> ListCANFdScheduleConfigDto
{
get { return _listCANFdScheduleConfigDto; }
set { _listCANFdScheduleConfigDto = value; RaisePropertyChanged(); }
}
/// <summary>
/// 消息名列表。
/// </summary>
public List<string>? ListMsg { get; set; }
private ObservableCollection<CbxItems> _msgCbxItems;
/// <summary>
/// 消息名称下拉框数据。
/// </summary>
public ObservableCollection<CbxItems> MsgCbxItems
{
get { return _msgCbxItems; }
set { _msgCbxItems = value; RaisePropertyChanged(); }
}
/// <summary>
/// 选中的程序 Id。
/// </summary>
public long SelectCanLinConfigProId { get; set; }
private ObservableCollection<CbxItems> _sendOrderCbxItems;
/// <summary>
/// 发送方式集合。
/// </summary>
public ObservableCollection<CbxItems> SendOrderCbxItems
{
get { return _sendOrderCbxItems; }
set { _sendOrderCbxItems = value; RaisePropertyChanged(); }
}
private string? _curSendOrder;
/// <summary>
/// 当前发送方式。
/// </summary>
public string? CurSendOrder
{
get { return _curSendOrder; }
set { _curSendOrder = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _schTabIndexCbxItems;
/// <summary>
/// 调度器序号集合。
/// </summary>
public ObservableCollection<CbxItems> SchTabIndexCbxItems
{
get { return _schTabIndexCbxItems; }
set { _schTabIndexCbxItems = value; RaisePropertyChanged(); }
}
private CANFdScheduleConfigDto _curSelectedItem;
/// <summary>
/// 当前选中项。
/// </summary>
public CANFdScheduleConfigDto CurSelectedItem
{
get { return _curSelectedItem; }
set { _curSelectedItem = value; RaisePropertyChanged(); }
}
private DelegateCommand<object> _gridSelectionChangedCmd;
/// <summary>
/// DataGrid 选中行变化。
/// </summary>
public DelegateCommand<object> GridSelectionChangedCmd
{
get
{
if (_gridSelectionChangedCmd == null)
{
_gridSelectionChangedCmd = new DelegateCommand<object>(GridSelectionChangedCmdMethod);
}
return _gridSelectionChangedCmd;
}
}
/// <summary>
/// 选中行变化处理。
/// </summary>
/// <param name="par">选中项。</param>
private void GridSelectionChangedCmdMethod(object par)
{
var selected = par as CANFdScheduleConfigDto;
if (selected != null)
{
CurSelectedItem = selected;
}
}
private DelegateCommand<string> _opCmd;
/// <summary>
/// 操作命令(删除)。
/// </summary>
public DelegateCommand<string> OpCmd
{
get
{
if (_opCmd == null)
{
_opCmd = new DelegateCommand<string>(OpCmdCall);
}
return _opCmd;
}
}
/// <summary>
/// 操作命令处理。
/// </summary>
/// <param name="par">参数。</param>
private void OpCmdCall(string par)
{
switch (par)
{
case "Add":
MessageBox.Show("调度表项由【读写设置】中的写入配置通过“加入定时调度表”生成,这里不支持新增。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
break;
case "Delete":
if (CurSelectedItem != null)
{
FreeSql.Delete<CANFdScheduleConfig>(CurSelectedItem.Id).ExecuteAffrows();
ListCANFdScheduleConfigDto.Remove(CurSelectedItem);
CurSelectedItem = null;
}
else
{
MessageBox.Show("请选中后再进行【删除】操作?", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
}
break;
default:
break;
}
}
private DelegateCommand _saveCmd;
/// <summary>
/// 保存命令。
/// </summary>
public DelegateCommand SaveCmd
{
get
{
if (_saveCmd == null)
{
_saveCmd = new DelegateCommand(SaveCmdMethod);
}
return _saveCmd;
}
}
/// <summary>
/// 保存命令处理。
/// </summary>
private void SaveCmdMethod()
{
// 校验:确保每个调度项具备最小可用字段,避免落库无效配置。
foreach (var item in ListCANFdScheduleConfigDto)
{
// UI 上的“发送方式”是全局下拉框,这里同步写回每个子项,确保落库数据一致。
item.OrderSend = CurSendOrder == "0" ? 0 : 1;
if (string.IsNullOrEmpty(item.MsgName))
{
MessageBox.Show("消息名为空:请在【读写设置】-> 写入配置中选择报文后点击“加入定时调度表”,再回到此处设置周期。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (item.Cycle <= 0)
{
MessageBox.Show("请确认周期是否正确", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
if (item.OrderSend >= 2)
{
MessageBox.Show("请确认发送方式是否正确", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
return;
}
}
foreach (var item in ListCANFdScheduleConfigDto)
{
// Upsert逐项落库。
FreeSql.InsertOrUpdate<CANFdScheduleConfig>()
.SetSource(Mapper.Map<CANFdScheduleConfig>(item))
.ExecuteAffrows();
}
// 保存完成后重载:
// - 避免 UI 集合与数据库实际数据不一致;
// - 同时让新增项获取真实 Id。
ListCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>(
Mapper.Map<List<CANFdScheduleConfigDto>>(
FreeSql.Select<CANFdScheduleConfig>()
.Where(a => a.CanLinConfigProId == SelectCanLinConfigProId)
.ToList()));
DialogParameters pars = new DialogParameters
{
{ "ReturnValue", ListCANFdScheduleConfigDto }
};
RaiseRequestClose(new DialogResult(ButtonResult.OK, pars));
}
private DelegateCommand _cancelCmd;
/// <summary>
/// 取消命令。
/// </summary>
public DelegateCommand CancelCmd
{
get
{
if (_cancelCmd == null)
{
_cancelCmd = new DelegateCommand(CancelCmdMethod);
}
return _cancelCmd;
}
}
/// <summary>
/// 取消命令处理。
/// </summary>
private void CancelCmdMethod()
{
RaiseRequestClose(new DialogResult(ButtonResult.Cancel));
}
/// <summary>
/// 弹窗打开时参数接收并初始化 UI。
/// 说明:
/// - ListMsg用于构造消息名下拉框候选
/// - ListCANFdScheduleConfigDto用于回显当前调度表
/// - SelectCanLinConfigProId用于 Save 后按配置程序 id 重载。
/// </summary>
/// <param name="parameters">参数。</param>
public override void OnDialogOpened(IDialogParameters parameters)
{
if (parameters.ContainsKey("ListMsg"))
{
ListMsg = parameters.GetValue<List<string>>("ListMsg");
if (ListMsg != null)
{
// 转换为 CbxItems 集合Key/Text 都使用消息名)。
MsgCbxItems = new ObservableCollection<CbxItems>(
ListMsg.Select(value => new CbxItems
{
Key = value,
Text = value
}));
}
}
ListCANFdScheduleConfigDto = parameters.GetValue<ObservableCollection<CANFdScheduleConfigDto>>("ListCANFdScheduleConfigDto");
if (ListCANFdScheduleConfigDto == null) ListCANFdScheduleConfigDto = new ObservableCollection<CANFdScheduleConfigDto>();
if (ListCANFdScheduleConfigDto.Count > 0)
{
// 回显:默认取第一条的 OrderSend。
CurSendOrder = ListCANFdScheduleConfigDto.FirstOrDefault()!.OrderSend.ToString();
}
else
{
// 默认:顺序发送。
CurSendOrder = "1";
}
SelectCanLinConfigProId = parameters.GetValue<long>("SelectCanLinConfigProId");
}
}
}