BDU/ATS/Views/ToolBar.xaml.cs

614 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using ATS.Logic;
using ATS.Models;
using ATS.Tools;
using ATS.Windows;
using ATS_DBContext;
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
using Newtonsoft.Json;
using PropertyChanged;
using System;
using System.Collections.Generic;
using System.IO;
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;
using TSMasterCAN;
using static ATS.Models.ParameterModel;
using Path = System.IO.Path;
namespace ATS.Views
{
/// <summary>
/// ToolBar.xaml 的交互逻辑
/// </summary>
[AddINotifyPropertyChangedInterface]
public partial class ToolBar : UserControl
{
public static ToolBar Instance { get; private set; }
public string CurSubProgramPath { get; set; }
public bool SingleStep = false;
public string RunState { get; set; } = "运行";
public PackIconKind RunIcon { get; set; } = PackIconKind.Play;
public bool? IsStop { get; set; } = null;
public bool IsTerminate { get; set; } = false;
public bool? CanReport => IsStop == false; // 是否可以导出报告
public bool IsAdmin => MainWindow.Instance.User.Role > 0;
public bool IsDebug => MainWindow.Instance.User.UserName == "开发者" && MainWindow.Instance.User.UserAccount == "Developer";
private Task? currentExecutionTask;
public ToolBar()
{
Instance = this;
InitializeComponent();
DataContext = this;
// 监听主窗口属性变化,特别是 Title 变化
if (MainWindow.Instance != null)
{
MainWindow.Instance.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(MainWindow.IsInSubProgramMode) ||
e.PropertyName == "Title") // 监听 Title 变化
{
OnPropertyChanged(nameof(IsInSubProgramMode));
OnPropertyChanged(nameof(CurrentPathDisplay));
}
};
}
this.Loaded += (s, e) => LoadDefaultProgramIfExists();
}
private void LoadDefaultProgramIfExists()
{
try
{
if (File.Exists(SystemConfig.Instance.DefaultSubProgramFilePath))
{
string json = File.ReadAllText(SystemConfig.Instance.DefaultSubProgramFilePath);
var tmp = JsonConvert.DeserializeObject<ProgramModel>(json);
if (tmp != null)
{
MainWindow.Instance.Program = tmp;
InitParameter(tmp);
InitDevice(tmp);
}
else
{
MainWindow.Instance.Program = new();
}
MainWindow.Instance.CurrentFilePath = SystemConfig.Instance.DefaultSubProgramFilePath;
Log.Success($"已打开文件: {SystemConfig.Instance.DefaultSubProgramFilePath}");
}
}
catch (Exception ex)
{
Log.Error($"默认程序:{SystemConfig.Instance.DefaultSubProgramFilePath} 文件打开失败:{ex.Message}");
}
}
#region
private void InitDevice(ProgramModel program)
{
if (program.Devices != null && program.Devices.Count > 0)
{
foreach (DeviceModel device in program.Devices)
{
_ = DeviceConnect.InitAndConnectDevice(program, device);
}
}
foreach (var step in program.StepCollection)
{
if (step.SubProgram != null)
{
InitDevice(step.SubProgram);
}
}
}
private void InitParameter(ProgramModel program)
{
if (program.Parameters != null && program.Parameters.Count > 0)
{
foreach (var parameter in program.Parameters)
{
if (parameter.Type!.BaseType == typeof(Enum))
{
parameter.Value = Enum.Parse(parameter.Type, parameter.Value!.ToString()!);
}
}
}
foreach (var step in program.StepCollection)
{
if (step.SubProgram != null)
{
InitDevice(step.SubProgram);
}
}
}
private void SaveProgramToFile(string filePath)
{
try
{
var tmp = ClearDeviceParameterValue(MainWindow.Instance.Program);
string json = JsonConvert.SerializeObject(tmp, Formatting.Indented);
File.WriteAllText(filePath, json);
Log.Success($"程序已保存: {filePath}");
}
catch (Exception ex)
{
Log.Error($"保存文件失败: {ex.Message}");
}
}
private ProgramModel ClearUnnecessaryParameterValue(ProgramModel program)
{
var tmp = new ProgramModel(program);
foreach (var step in tmp.StepCollection)
{
if (step.Method != null)
{
foreach (var para in step.Method.Parameters)
{
if (para.VariableID != null && para.Category == ParameterCategory.Output)
{
para.Value = null;
tmp.Parameters.First(x => x.ID == para.VariableID)!.Value = null;
}
}
}
else if (step.SubProgram != null)
{
var subTmp = ClearUnnecessaryParameterValue(step.SubProgram);
step.SubProgram = subTmp;
}
}
return tmp;
}
private ProgramModel ClearDeviceParameterValue(ProgramModel program)
{
var tmp = new ProgramModel(program);
foreach (var device in tmp.Devices)
{
tmp.Parameters.Remove(tmp.Parameters.First(x => x.ID == device.ParameterID));
}
foreach (var step in tmp.StepCollection)
{
if (step.SubProgram != null)
{
step.SubProgram = ClearDeviceParameterValue(step.SubProgram);
}
}
return tmp;
}
#endregion
private void File_New_Click(object sender, RoutedEventArgs e)
{
MainWindow.Instance.Program = new();
MainWindow.Instance.CurrentFilePath = "";
}
private void Set_DefaultProgram_Click(object sender, RoutedEventArgs e)
{
SystemConfig.Instance.DefaultSubProgramFilePath = CurSubProgramPath;
SystemConfig.Instance.SaveToFile();
}
private void File_Open_Click(object sender, RoutedEventArgs e)
{
var openFileDialog = new OpenFileDialog
{
Filter = "ATS程序文件|*.ats|所有文件|*.*",
Title = "打开程序文件"
};
if (openFileDialog.ShowDialog() == true)
{
try
{
CurSubProgramPath = openFileDialog.FileName;
string json = File.ReadAllText(openFileDialog.FileName);
var tmp = JsonConvert.DeserializeObject<ProgramModel>(json);
if (tmp != null)
{
MainWindow.Instance.Program = tmp;
MainWindow.Instance.Title = Path.GetFileName(openFileDialog.FileName).Split(".ats")[0];
InitParameter(tmp);
InitDevice(tmp);
}
else
{
MainWindow.Instance.Program = new();
}
MainWindow.Instance.SelectedStep = null;
MainWindow.Instance.CurrentFilePath = openFileDialog.FileName;
Log.Success($"已打开文件: {openFileDialog.FileName}");
}
catch (Exception ex)
{
Log.Error($"程序文件打开失败:{ex.Message}");
}
}
}
private void File_Save_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(MainWindow.Instance.CurrentFilePath))
{
File_SaveAsOther_Click(sender, e);
}
else
{
SaveProgramToFile(MainWindow.Instance.CurrentFilePath);
}
}
private void File_SaveAsOther_Click(object sender, RoutedEventArgs e)
{
var saveFileDialog = new SaveFileDialog
{
Filter = "ATS程序文件|*.ats|所有文件|*.*",
Title = "另存为",
FileName = "NewProgram.ats"
};
if (saveFileDialog.ShowDialog() == true)
{
MainWindow.Instance.CurrentFilePath = saveFileDialog.FileName;
SaveProgramToFile(MainWindow.Instance.CurrentFilePath);
}
}
private async void ProgramRun_Click(object sender, RoutedEventArgs e)
{
if (RunState == "运行")
{
SingleStep = false;
Log.Info($"用户 [ {MainWindow.Instance.User.UserName} ] 点击 [ 运行 ] ");
// 清空报告列表
ReportModelList.ReportList = new();
RunState = "暂停";
RunIcon = PackIconKind.Pause;
if (IsStop == null)
{
IsStop = false;
currentExecutionTask = StepRunning.ExecuteSteps(MainWindow.Instance.Program, cancellationToken: StepRunning.stepCTS.Token);
await currentExecutionTask;
RunState = "运行";
RunIcon = PackIconKind.Play;
IsStop = null;
}
else if (IsStop == true)
{
IsStop = false;
}
}
else
{
Log.Info($"用户 [ {MainWindow.Instance.User.UserName} ] 点击 [ 暂停 ] ");
IsStop = true;
RunState = "运行";
RunIcon = PackIconKind.Play;
}
}
private async void SingleStepExecution_Click(object sender, RoutedEventArgs e)
{
if (RunState == "运行")
{
SingleStep = true;
Log.Info($"用户 [ {MainWindow.Instance.User.UserName} ] 点击 [ 单步执行 ] ");
RunState = "暂停";
RunIcon = PackIconKind.Pause;
if (IsStop == null)
{
IsStop = false;
currentExecutionTask = StepRunning.ExecuteSteps(MainWindow.Instance.Program, cancellationToken: StepRunning.stepCTS.Token);
await currentExecutionTask;
RunState = "运行";
RunIcon = PackIconKind.Play;
IsStop = null;
}
else if (IsStop == true)
{
IsStop = false;
}
}
}
private void Terminate_Click(object sender, RoutedEventArgs e)
{
if (IsStop == false)
{
Log.Info($"用户 [ {MainWindow.Instance.User.UserName} ] 点击 [ 停止 ] ");
IsTerminate = true;
IsStop = null;
RunState = "运行";
RunIcon = PackIconKind.Play;
StepRunning.stepCTS.Cancel();
}
}
private void Reset_Click(object sender, RoutedEventArgs e)
{
Log.Info($"用户 [ {MainWindow.Instance.User.UserName} ] 点击 [ 复位 ] ");
IsTerminate = false;
currentExecutionTask = null;
StepRunning.stepCTS = new();
StepRunning.ResetAllStepStatus(MainWindow.Instance.Program);
}
//导出按钮
private void Report_Click(object sender, RoutedEventArgs e)
{
Log.Info($"用户 [ {MainWindow.Instance.User.UserName} ] 点击 [ 导出报告 ] ");
if (ReportModelList.ReportList != null && ReportModelList.ReportList.Count > 0)
{
//生成csv报告文件
GenerateCsvReport();
}
else
{
Log.Warning("当前无报告可导出");
MessageBox.Show("当前无报告可导出", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
private void ChannelMapping_Click(object sender, RoutedEventArgs e)
{
var re = CAN.ShowChannelMappingWindow(true);
if (re != 0)
{
var msg = CAN.GetErrorDescription(re);
Log.Error($"同星通道映射界面打开失败:{msg}");
}
}
private void TestDataInfo_Click(object sender, RoutedEventArgs e)
{
new TestDataInfomationWindow().Show();
}
private void SystemConfig_Click(object sender, RoutedEventArgs e)
{
new SystemConfigWindow().Show();
}
Task? DebugAutoRunTask;
CancellationTokenSource DebugAutoRunTaskCT;
private void Debug_AutoRun_Click(object sender, RoutedEventArgs e)
{
if (MainWindow.Instance.Program.StepCollection.Count == 0) return;
if (DebugAutoRunTask == null)
{
DebugAutoRunTaskCT = new();
try
{
DebugAutoRunTask = Task.Run(async () =>
{
while (true)
{
DebugAutoRunTaskCT.Token.ThrowIfCancellationRequested();
await StepRunning.ExecuteSteps(MainWindow.Instance.Program, cancellationToken: DebugAutoRunTaskCT.Token);
}
});
}
catch (OperationCanceledException)
{
}
}
else
{
DebugAutoRunTaskCT.Cancel();
DebugAutoRunTask = null;
}
}
private async void Debug_ClearDataBase_Click(object sender, RoutedEventArgs e)
{
MessageBoxResult result = MessageBox.Show($"确定执行删除操作?", "提示", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
using ATS_DB db = new();
db.TestData.RemoveRange(db.TestData);
await db.SaveChangesAsync();
}
}
private void CAN_DatabaseConnect_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Title = "请选择 DBC 文件",
Filter = "DBC 文件 (*.dbc)|*.dbc",
//InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
Multiselect = false
};
if (openFileDialog.ShowDialog() == true)
{
var re = CAN.LoadDBC(openFileDialog.FileName, [0, 1, 2, 3], out var DataBaseID);
if (re != 0)
{
Log.Error("CAN数据库加载失败" + CAN.GetErrorDescription(re));
}
else
{
Log.Success("CAN数据库加载成功");
}
}
}
private bool isConnect = true;
private void Connect_DisConnect_Click(object sender, RoutedEventArgs e)
{
if (isConnect)
{
var res = CAN.DisConnect();
if (res == 0)
{
Log.Success($"CAN卡断开连接成功,返回值:{res}");
isConnect = false;
}
else
{
Log.Error($"CAN卡断开连接失败,返回值:{res}");
}
}
else
{
var res = CAN.Connect();
if (res == 0)
{
Log.Success($"CAN卡连接成功,返回值:{res}");
isConnect = true;
}
else
{
Log.Error($"CAN卡连接失败,返回值:{res}");
}
}
}
private void GenerateCsvReport()
{
try
{
// 生成文件名(包含当前时间戳)
string fileName = $"Report_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Reports", fileName);
// 确保 Reports 目录存在
string directory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 写入 CSV 文件
using (var writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
// 写入 CSV 头部(新增"所属子程序"列)
writer.WriteLine("步骤序号,步骤名称,所属子程序,备注,执行人,执行时间,是否通过,结果");
var allPASS = true;
// 写入数据行
foreach (var report in ReportModelList.ReportList)
{
string stepIndex = report.stepModel?.Index.ToString() ?? "";
string stepName = EscapeCsvField(report.stepModel?.Name ?? "");
string subProgramPath = EscapeCsvField(report.SubProgramPath); // 新增列
string stepRemark = EscapeCsvField(report.stepModel?.Description ?? "");
string user = EscapeCsvField(report.User);
string executeTime = report.ExcuteTime?.ToString("yyyy-MM-dd HH:mm:ss");
string isPass = report.IsPass.ToString(); // 根据你的 IsPass 枚举定义,可能需要调整
if (isPass == "FAIL") allPASS = false;
string result = EscapeCsvField(report.Result ?? "");
writer.WriteLine($"{stepIndex},{stepName},{subProgramPath},{stepRemark},{user},{executeTime},{isPass},{result}");
}
// 写入报告总结果
writer.WriteLine("");
writer.WriteLine($"测试总结果,,,,,,{(allPASS ? "PASS" : "FAIL")},");
}
Log.Success($"报告导出成功,路径:{filePath}");
MessageBox.Show($"报告导出成功!\n文件路径{filePath}", "导出成功", MessageBoxButton.OK, MessageBoxImage.Information);
// 可选:打开文件所在目录
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{filePath}\"");
}
catch (Exception ex)
{
Log.Error($"导出报告失败:{ex.Message}");
MessageBox.Show($"导出报告失败:{ex.Message}", "导出失败", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 转义 CSV 字段中的特殊字符(逗号、双引号、换行符等)
/// </summary>
/// <param name="field">原始字段值</param>
/// <returns>转义后的字段值</returns>
private string EscapeCsvField(string field)
{
if (string.IsNullOrEmpty(field))
return "";
// 如果字段包含逗号、双引号或换行符,则用双引号包围,并将双引号转义为两个双引号
if (field.Contains(",") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
{
return "\"" + field.Replace("\"", "\"\"") + "\"";
}
return field;
}
private void CAN_CatchConfig_Click(object sender, RoutedEventArgs e)
{
new CANCatchSingalView().Show();
}
// 添加 IsInSubProgramMode 依赖属性或普通属性
// 如果 MainWindow.Instance.IsInSubProgramMode 是普通属性,可以用普通属性
public bool IsInSubProgramMode => MainWindow.Instance?.IsInSubProgramMode ?? false;
// 修改 CurrentPathDisplay 属性,直接从 MainWindow 获取 Title
public string CurrentPathDisplay
{
get
{
// 直接使用 MainWindow 的 Title它已经在 MainWindow 中被正确管理
return MainWindow.Instance?.Title ?? "ATS";
}
set
{
if (MainWindow.Instance != null)
{
value = MainWindow.Instance.Title;
}
}
}
private void NavigateBack_Click(object sender, RoutedEventArgs e)
{
MainWindow.Instance?.ExitSubProgramMode();
}
private void DeviceManage_Click(object sender, RoutedEventArgs e)
{
new DeviceManageWindow().Show();
}
}
}