This commit is contained in:
2026-03-02 11:20:08 +08:00
parent 74338fdb3a
commit 5be18ded2e
21 changed files with 5984 additions and 224 deletions

View File

@@ -0,0 +1,402 @@
using AutoMapper;
using CapMachine.Core;
using CapMachine.Model;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.Services;
using ImTools;
using Prism.Commands;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace CapMachine.Wpf.ViewModels
{
/// <summary>
/// ZLG CAN 调度表配置
/// </summary>
public class DialogZlgCANSchConfigViewModel : DialogViewModel
{
/// <summary>
/// 构造函数
/// </summary>
public DialogZlgCANSchConfigViewModel(IFreeSql freeSql, IMapper mapper)
{
Title = "调度表 CAN 配置";
FreeSql = freeSql;
Mapper = mapper;
SendOrderCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){
Key="0",
Text="并行",
},
new CbxItems(){
Key="1",
Text="顺序",
},
};
//默认只能用1号调度器
SchTabIndexCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){
Key="0",
Text="0",
},
//new CbxItems(){
// Key="1",
// Text="1",
//},
//new CbxItems(){
// Key="2",
// Text="2",
//},
//new CbxItems(){
// Key="3",
// Text="3",
//},
//new CbxItems(){
// Key="4",
// Text="4",
//},
};
}
/// <summary>
/// FreeSql用于调度表项的删除/保存落库)。
/// </summary>
public IFreeSql FreeSql { get; }
/// <summary>
/// AutoMapperDTO 与实体映射)。
/// </summary>
public IMapper Mapper { get; }
private string name;
/// <summary>
/// 名称
/// </summary>
public string Name
{
get { return name; }
set { name = value; RaisePropertyChanged(); }
}
private ObservableCollection<CANScheduleConfigDto> _ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>();
/// <summary>
/// CAN 调度表数据集合
/// </summary>
public ObservableCollection<CANScheduleConfigDto> ListCANScheduleConfigDto
{
get { return _ListCANScheduleConfigDto; }
set { _ListCANScheduleConfigDto = 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 CANScheduleConfigDto _CurSelectedItem;
/// <summary>
/// 当前选中的调度表项(用于删除等操作)。
/// </summary>
public CANScheduleConfigDto CurSelectedItem
{
get { return _CurSelectedItem; }
set { _CurSelectedItem = value; RaisePropertyChanged(); }
}
private DelegateCommand<object> _GridSelectionChangedCmd;
/// <summary>
/// DataGrid 选中行变化。
/// </summary>
public DelegateCommand<object> GridSelectionChangedCmd
{
set
{
_GridSelectionChangedCmd = value;
}
get
{
if (_GridSelectionChangedCmd == null)
{
_GridSelectionChangedCmd = new DelegateCommand<object>((par) => GridSelectionChangedCmdMethod(par));
}
return _GridSelectionChangedCmd;
}
}
private void GridSelectionChangedCmdMethod(object par)
{
// 先判断是否是正确的集合数据,防止 DataGrid 的 ItemsSource 刷新导致的误触发。
var Selecteddata = par as CANScheduleConfigDto;
if (Selecteddata != null)
{
CurSelectedItem = Selecteddata;
}
}
private DelegateCommand<string> _OpCmd;
/// <summary>
/// 操作命令(删除)。
/// 说明:新增调度表项由“读写设置”弹窗内的“加入定时调度表”生成,此处仅允许删除与保存。
/// </summary>
public DelegateCommand<string> OpCmd
{
set
{
_OpCmd = value;
}
get
{
if (_OpCmd == null)
{
_OpCmd = new DelegateCommand<string>((Par) => OpCmdCall(Par));
}
return _OpCmd;
}
}
private void OpCmdCall(string Par)
{
switch (Par)
{
case "Add":
MessageBox.Show("调度表项由【读写设置】中的写入配置通过“加入定时调度表”生成,这里不支持新增。", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
break;
case "Delete":
if (CurSelectedItem != null)
{
// 直接落库删除(无论 UI 是否还有引用,都以数据库为准)。
FreeSql.Delete<CANScheduleConfig>(CurSelectedItem.Id).ExecuteAffrows();
ListCANScheduleConfigDto.Remove(CurSelectedItem);
CurSelectedItem = null;
}
else
{
MessageBox.Show("请选中后再进行【删除】操作?", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
}
break;
default:
break;
}
}
private DelegateCommand saveCmd;
/// <summary>
/// 保存命令
/// </summary>
public DelegateCommand SaveCmd
{
set
{
saveCmd = value;
}
get
{
if (saveCmd == null)
{
saveCmd = new DelegateCommand(() => SaveCmdMethod());
}
return saveCmd;
}
}
/// <summary>
/// 保存命令方法。
/// 说明:
/// - 先做必要校验MsgName/Cycle/发送方式等),避免写入无效配置;
/// - 使用 InsertOrUpdate 保证“新增/修改”统一处理;
/// - 保存完成后重新从数据库加载,作为最终权威数据,并通过 DialogResult 回传给调用方。
/// </summary>
private void SaveCmdMethod()
{
// 校验:确保每个调度项具备最小可用字段。
foreach (var item in ListCANScheduleConfigDto)
{
// 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;
}
}
//发送的控制帧都放到同一个调度表中,不需要检查了
////检查重复设置问题
//bool isRepeat = ListCANScheduleConfigDto.GroupBy(i => i.MsgName).Any(g => g.Count() > 1);
//if (isRepeat)
//{
// MessageBox.Show("请确认是否重复设置", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
// return;
//}
// Upsert逐项落库。
foreach (var item in ListCANScheduleConfigDto)
{
FreeSql.InsertOrUpdate<CANScheduleConfig>()
.SetSource(Mapper.Map<CANScheduleConfig>(item)).
ExecuteAffrows();
}
// 保存完成后重新加载:
// - 防止 UI 缓存与数据库实际数据不一致;
// - 同时也让新增项拿到真实 Id。
ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>(Mapper.Map<List<CANScheduleConfigDto>>(FreeSql.Select<CANScheduleConfig>().Where(a => a.CanLinConfigProId == SelectCanLinConfigProId).ToList()));
DialogParameters pars = new DialogParameters
{
{ "ReturnValue", ListCANScheduleConfigDto }
};
RaiseRequestClose(new DialogResult(ButtonResult.OK, pars));
}
private DelegateCommand cancelCmd;
/// <summary>
/// 取消命令。
/// </summary>
public DelegateCommand CancelCmd
{
set
{
cancelCmd = value;
}
get
{
if (cancelCmd == null)
{
cancelCmd = new DelegateCommand(() => CancelCmdMethod());
}
return cancelCmd;
}
}
/// <summary>
/// 取消命令方法。
/// </summary>
private void CancelCmdMethod()
{
RaiseRequestClose(new DialogResult(ButtonResult.Cancel));
}
/// <summary>
/// 弹窗打开时接收参数并初始化 UI。
/// 说明:
/// - ListMsg 用于构造消息名下拉框;
/// - ListCANScheduleConfigDto 用于回显现有调度表;
/// - 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集合都是文本内容
MsgCbxItems = new ObservableCollection<CbxItems>(
ListMsg.Select(value => new CbxItems
{
Key = value,
Text = value
}));
}
}
ListCANScheduleConfigDto = parameters.GetValue<ObservableCollection<CANScheduleConfigDto>>("ListCANScheduleConfigDto");
//防止返回的数据为空,就无法增加了
if (ListCANScheduleConfigDto == null) ListCANScheduleConfigDto = new ObservableCollection<CANScheduleConfigDto>();
//Name = parameters.GetValue<string>("Name");
if (ListCANScheduleConfigDto.Count > 0)
{
// 回显:默认取第一条的 OrderSend 作为当前下拉框选择。
CurSendOrder = ListCANScheduleConfigDto.FirstOrDefault()!.OrderSend.ToString();
}
else
{
// 默认:顺序发送。
CurSendOrder = "1";
}
SelectCanLinConfigProId = parameters.GetValue<long>("SelectCanLinConfigProId");
}
}
}