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
{
///
/// ToolBar.xaml 的交互逻辑
///
[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(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(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);
}
}
///
/// 转义 CSV 字段中的特殊字符(逗号、双引号、换行符等)
///
/// 原始字段值
/// 转义后的字段值
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();
}
}
}