添加项目文件。

This commit is contained in:
“hsc”
2026-07-29 13:12:27 +08:00
parent d6da766e2d
commit 8cf45d36b9
297 changed files with 35814 additions and 0 deletions

View File

@@ -0,0 +1,846 @@
using UIShare.UIViewModel;
using UIShare.PubEvent;
using Common.Tools;
using Logger;
using MaterialDesignThemes.Wpf;
using Model.Entity;
using Service.Interface;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UIShare.GlobalVariable;
using static UIShare.UIViewModel.ParameterVM;
namespace UIShare
{
public class StepRunning:IDisposable
{
private ScopedContext _scopedContext;
private SystemConfig _systemConfig;
private DeviceManager _deviceManager;
//private Devices _devices;
private IContainerProvider containerProvider;
private IEventAggregator _eventAggregator;
private ITestReportService _testReportService;
private readonly Dictionary<Guid, ParameterVM> tmpParameters = [];
private readonly Stopwatch stepStopwatch = new();
private readonly Stack<Stopwatch> loopStopwatchStack = new();
private readonly Stack<LoopContext> loopStack = new();
public CancellationTokenSource stepCTS = new();
public CancellationTokenSource errorStepCTS = new();
private bool SubSingleStep = false;
/// <summary>标记是否已被注销,执行方法据此安全退出</summary>
private volatile bool _disposed = false;
public Guid TestRoundID;
public StepRunning(ScopedContext ScopedContext, SystemConfig systemConfig,IEventAggregator eventAggregator, DeviceManager deviceManager, ITestReportService testReportService)
{
_scopedContext = ScopedContext;
_systemConfig = systemConfig;
_eventAggregator = eventAggregator;
_deviceManager= deviceManager;
_testReportService = testReportService;
//_devices = containerProvider.Resolve<Devices>();
}
public async Task<bool> ExecuteErrorSteps(ProgramVM program, int depth = 0, CancellationToken cancellationToken = default)
{
if (_disposed) return false;
int index = 0;
bool stepSuccess = false;
if (depth == 0)
{
loopStack.Clear();
loopStopwatchStack.Clear();
ResetAllStepStatus(program.ErrorStepCollection);
tmpParameters.Clear();
TestRoundID = Guid.NewGuid();
}
foreach (var item in program.Parameters)
{
tmpParameters.TryAdd(item.ID, item);
}
while (index < program.ErrorStepCollection.Count)
{
if (_disposed || cancellationToken.IsCancellationRequested)
{
break;
}
var step = program.ErrorStepCollection[index];
if (!step.IsUsed)
{
index++;
continue;
}
step.Result = 0;
if (step.StepType == "循环开始")
{
var endStep = program.ErrorStepCollection.FirstOrDefault(x => x.LoopStartStepId == step.ID);
if (endStep != null)
{
endStep.Result = 0;
}
else
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, "程序循环指令未闭合,请检查后重试");
break;
}
}
// 处理循环开始
if (step.StepType == "循环开始")
{
Stopwatch loopStopwatch = new();
loopStopwatch.Start();
loopStopwatchStack.Push(loopStopwatch);
var context = new LoopContext
{
LoopCount = step.LoopCount ?? 1,
CurrentLoop = 0,
StartIndex = index,
LoopStartStep = step
};
loopStack.Push(context);
step.CurrentLoopCount = context.LoopCount;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环开始,共{context.LoopCount}次", depth);
index++;
await SaveStepRecordAsync(step, depth, true);
}
// 处理循环结束
else if (step.StepType == "循环结束")
{
if (loopStack.Count == 0)
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, "未匹配的循环结束指令", depth: depth);
step.Result = 2;
index++;
await SaveStepRecordAsync(step, depth, true);
continue;
}
var context = loopStack.Peek();
context.CurrentLoop++;
// 更新循环开始步骤的显示
context.LoopStartStep!.CurrentLoopCount = context.LoopCount - context.CurrentLoop;
if (context.CurrentLoop < context.LoopCount)
{
// 继续循环:跳转到循环开始后的第一条指令
index = context.StartIndex + 1;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
await SaveStepRecordAsync(step, depth, true);
}
else
{
// 循环结束
loopStack.Pop();
var loopStopwatch = loopStopwatchStack.Peek();
index++;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环结束,共执行{context.LoopCount}次", depth);
if (depth == 0 && loopStopwatch.IsRunning)
{
loopStopwatch.Stop();
step.RunTime = (int)loopStopwatch.ElapsedMilliseconds;
step.Result = 1;
program.ErrorStepCollection.First(x => x.ID == step.LoopStartStepId).Result = 1;
loopStopwatchStack.Pop();
}
await SaveStepRecordAsync(step, depth, true);
}
}
// 处理普通步骤
else
{
if (depth == 0)
{
stepStopwatch.Restart();
}
if (step.SubProgram != null)
{
if (_scopedContext.SingleStep)//子程序的单步执行将执行完保存下的所有Method
{
SubSingleStep = true;
_scopedContext.SingleStep = false;
}
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken);
UpdateCurrentStepResult(step, true, stepSuccess, depth);
if (SubSingleStep)
{
SubSingleStep = false;
_scopedContext.SingleStep = true;
}
}
else if (step.Method != null)
{
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken);
stepSuccess = step.Result == 1;
if (step.NGGotoStepID != null && !stepSuccess)
{
var tmp = program.ErrorStepCollection.FirstOrDefault(x => x.ID == step.NGGotoStepID);
if (tmp != null)
{
index = tmp.Index - 2;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
}
}
if (step.OKGotoStepID != null && stepSuccess)
{
var tmp = program.ErrorStepCollection.FirstOrDefault(x => x.ID == step.OKGotoStepID);
if (tmp != null)
{
index = tmp.Index - 2;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
}
}
}
index++;
if (depth == 0 && stepStopwatch.IsRunning)
{
stepStopwatch.Stop();
step.RunTime = (int)stepStopwatch.ElapsedMilliseconds;
}
await SaveStepRecordAsync(step, depth, true);
}
}
return loopStack.Count == 0 && stepSuccess;
}
public async Task<bool> ExecuteSteps(ProgramVM program, int depth = 0, CancellationToken cancellationToken = default)
{
if (_disposed) return false;
int index = 0;
bool stepSuccess = false;
if (depth == 0)
{
loopStack.Clear();
loopStopwatchStack.Clear();
ResetAllStepStatus(program.StepCollection);
tmpParameters.Clear();
TestRoundID = Guid.NewGuid();
}
foreach (var item in program.Parameters)
{
tmpParameters.TryAdd(item.ID, item);
}
while (index < program.StepCollection.Count)
{
while (!_disposed && _scopedContext.IsStop == true)
{
await Task.Delay(50, cancellationToken);
}
if (_disposed || cancellationToken.IsCancellationRequested)
{
break;
}
var step = program.StepCollection[index];
if (!step.IsUsed)
{
index++;
continue;
}
step.Result = 0;
if (step.StepType == "循环开始")
{
var endStep = program.StepCollection.FirstOrDefault(x => x.LoopStartStepId == step.ID);
if (endStep != null)
{
endStep.Result = 0;
}
else
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, "程序循环指令未闭合,请检查后重试");
break;
}
}
// 处理循环开始
if (step.StepType == "循环开始")
{
Stopwatch loopStopwatch = new();
loopStopwatch.Start();
loopStopwatchStack.Push(loopStopwatch);
var context = new LoopContext
{
LoopCount = step.LoopCount ?? 1,
CurrentLoop = 0,
StartIndex = index,
LoopStartStep = step
};
loopStack.Push(context);
step.CurrentLoopCount = context.LoopCount;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环开始({step.Name}),共{context.LoopCount}次", depth);
index++;
await SaveStepRecordAsync(step, depth, false);
}
// 处理循环结束
else if (step.StepType == "循环结束")
{
if (loopStack.Count == 0)
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, "未匹配的循环结束指令", depth:depth);
step.Result = 2;
index++;
await SaveStepRecordAsync(step, depth, false);
continue;
}
var context = loopStack.Peek();
context.CurrentLoop++;
// 更新循环开始步骤的显示
context.LoopStartStep!.CurrentLoopCount = context.LoopCount - context.CurrentLoop;
if (context.CurrentLoop < context.LoopCount)
{
// 继续循环:跳转到循环开始后的第一条指令
index = context.StartIndex + 1;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
await SaveStepRecordAsync(step, depth, false);
}
else
{
// 循环结束
loopStack.Pop();
var loopStopwatch = loopStopwatchStack.Peek();
index++;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"循环结束,共执行{context.LoopCount}次", depth);
if (depth == 0 && loopStopwatch.IsRunning)
{
loopStopwatch.Stop();
step.RunTime = (int)loopStopwatch.ElapsedMilliseconds;
step.Result = 1;
program.StepCollection.First(x => x.ID == step.LoopStartStepId).Result = 1;
loopStopwatchStack.Pop();
}
await SaveStepRecordAsync(step, depth, false);
}
}
// 处理普通步骤
else
{
if (depth == 0)
{
stepStopwatch.Restart();
}
if (step.SubProgram != null)
{
if (_scopedContext.SingleStep)//子程序的单步执行将执行完保存下的所有Method
{
SubSingleStep = true;
_scopedContext.SingleStep = false;
}
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
stepSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken);
UpdateCurrentStepResult(step, true, stepSuccess, depth);
if (SubSingleStep)
{
SubSingleStep = false;
_scopedContext.SingleStep = true;
}
}
else if (step.Method != null)
{
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken);
stepSuccess = step.Result == 1;
if (step.NGGotoStepID != null && !stepSuccess)
{
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.NGGotoStepID);
if (tmp != null)
{
index = tmp.Index - 2;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
}
}
if (step.OKGotoStepID != null && stepSuccess)
{
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.OKGotoStepID);
if (tmp != null)
{
index = tmp.Index - 2;
LoggerHelper.InfoWithNotify(_systemConfig.Title, $"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
}
}
}
index++;
if (depth == 0 && stepStopwatch.IsRunning)
{
stepStopwatch.Stop();
step.RunTime = (int)stepStopwatch.ElapsedMilliseconds;
}
if (_scopedContext.SingleStep)
{
_scopedContext.IsStop = true;
_scopedContext.RunState = "运行";
_scopedContext.SingleStep = false;
_eventAggregator.GetEvent<RunSingalCompletedEvent>().Publish("Play");
}
await SaveStepRecordAsync(step, depth, false);
}
}
return loopStack.Count == 0 && stepSuccess;
}
public async Task ExecuteMethodStep(StepVM step, Dictionary<Guid, ParameterVM> parameters, int depth, CancellationToken cancellationToken = default)
{
if (_disposed) return;
try
{
if(_scopedContext.Program.StepCollection.Count>1)
_scopedContext.SelectedStep = null;
await Task.Delay(_systemConfig.PerformanceLevel, cancellationToken);
// 1. 查找类型
Type? targetType = null;
foreach (var assembly in _scopedContext.Assemblies)
{
targetType = assembly.GetType(step.Method!.FullName!);
if (targetType != null) break;
}
if (targetType == null)
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: depth);
step.Result = 2;
}
// 2. 创建实例(仅当方法不是静态时才需要)
object? instance = null;
bool isMethod = false;
// 3. 准备参数
var inputParams = new List<object?>();
var paramTypes = new List<Type>();
ParameterVM? outputParam = null;
foreach (var param in step.Method!.Parameters)
{
if (param.Category == ParameterCategory.Input)
{
if (param.Type == typeof(CancellationToken))
{
inputParams.Add(stepCTS.Token);
paramTypes.Add(param.Type!);
continue;
}
var actualValue = param.GetActualValue(tmpParameters);
// 类型转换处理
if (actualValue != null)
{
if (string.IsNullOrEmpty(actualValue.ToString()))
{
actualValue = null;
}
if (actualValue != null && param.Type != null && actualValue.GetType() != param.Type)
{
try
{
if (param.Type.IsArray)
{
// 获取数组元素类型
Type elementType = param.Type.GetElementType()!;
// 解析字符串为字符串数组
string[] stringArray = actualValue.ToString()!
.Trim('[', ']')
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim())
.ToArray();
// 创建目标类型数组
Array array = Array.CreateInstance(elementType, stringArray.Length);
// 转换每个元素
for (int i = 0; i < stringArray.Length; i++)
{
try
{
// 特殊处理字符串类型
if (elementType == typeof(string))
{
array.SetValue(stringArray[i], i);
}
// 特殊处理枚举类型
else if (elementType.IsEnum)
{
array.SetValue(Enum.Parse(elementType, stringArray[i]), i);
}
// 常规类型转换
else
{
if (stringArray[i] is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
// 先转成整数
var intValue = Convert.ToInt64(s, 16);
// 再转成目标类型
array.SetValue(Convert.ChangeType(intValue, elementType), i);
}
else
{
array.SetValue(Convert.ChangeType(stringArray[i], elementType), i);
}
}
}
catch
{
throw new InvalidCastException($"指令 [ {step.Index} ] 执行错误:元素 '{stringArray[i]}' 无法转换为 {elementType.Name}[]");
}
}
actualValue = array;
}
else
{
if (param.Type.BaseType == typeof(Enum))
{
actualValue = Enum.Parse(param.Type, param.Value!.ToString()!);
}
else
{
if (actualValue is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
// 先转成整数
var intValue = Convert.ToInt64(s, 16);
// 再转成目标类型
actualValue = Convert.ChangeType(intValue, param.Type);
}
else
{
actualValue = Convert.ChangeType(actualValue, param.Type);
}
}
}
}
catch (Exception ex)
{
LoggerHelper.WarnWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: depth);
}
}
}
inputParams.Add(actualValue);
paramTypes.Add(param.Type!);
}
else if (param.Category == ParameterCategory.Output)
{
outputParam = param;
}
}
// 4. 获取方法
var method = targetType!.GetMethod(
step.Method.Name!,
BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance,
null,
paramTypes.ToArray(),
null
);
if (method == null)
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth: depth);
step.Result = 2;
}
// 检查是否是静态方法
bool isStaticMethod = method!.IsStatic;
// 如果是实例方法,需要创建实例
if (!isStaticMethod)
{
try
{
if(targetType.Name== "ZLGCANFD")
{
instance = _deviceManager.CANFD;
}
else if (targetType.Name == "IOBoardGroup")
{
instance = _deviceManager.IOGroup;
}
else instance = _deviceManager.DeviceMap[targetType.Name];
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: depth);
step.Result = 2;
}
}
// 5. 执行方法
object? returnValue = method.Invoke(instance, inputParams.ToArray());
try
{
// 处理异步方法
if (returnValue is Task task)
{
await task.ConfigureAwait(false);
// 获取结果如果是Task<T>
if (task.GetType().IsGenericType)
{
var returnValueProperty = task.GetType().GetProperty("Result");
returnValue = returnValueProperty?.GetValue(task);
}
else
{
returnValue = null;
}
}
// 处理VoidTaskreturnValue类型
if (returnValue != null && returnValue.GetType().FullName == "System.Threading.Tasks.VoidTaskreturnValue")
{
returnValue = null;
}
}
catch (OperationCanceledException)
{
return;
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth);
step.Result = 2;
return;
}
// 6. 处理输出
bool paraResult = true; //记录参数上下限是否NG
if (outputParam != null)
{
outputParam.Value = returnValue;
var currentPara = outputParam.GetCurrentParameter(tmpParameters);
if (currentPara != null)
{
currentPara.Value = returnValue;
var tmp = currentPara.GetResult();
currentPara.Result = tmp.Item1;
paraResult = tmp.Item1;
if (tmp.Item2 != null)
{
LoggerHelper.WarnWithNotify(_systemConfig.Title, tmp.Item2);
}
}
var returnType = returnValue?.GetType();
if (returnType != null)
{
if (!returnType.IsArray)
{
LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth);
}
else
{
if (returnValue is IEnumerable enumerable)
{
var elements = enumerable.Cast<object>().Select(item => item?.ToString() ?? "null");
LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth);
}
}
}
}
LoggerHelper.SuccessWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行成功", depth);
UpdateCurrentStepResult(step, paraResult: paraResult, depth: depth);
}
catch (OperationCanceledException)
{
return;
}
catch (Exception ex)
{
LoggerHelper.ErrorWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth);
step.Result = 2;
return;
}
}
/// <summary>
/// 将单个步骤的执行结果保存到数据库(测试报告)。
/// 同一次运行的所有步骤共享 TestRoundID导出时按此 Guid 查询。
/// </summary>
private async Task SaveStepRecordAsync(StepVM step, int depth, bool isErrorStep)
{
try
{
// 获取输出参数值
string? outputValue = null;
if (step.Method != null)
{
var outputParam = step.Method.Parameters.FirstOrDefault(p => p.Category == ParameterCategory.Output);
if (outputParam?.Value != null)
outputValue = outputParam.Value.ToString();
}
var entity = new TestReportEntity
{
TestRoundId = TestRoundID,
Scope = _systemConfig.Title,
FileName = _systemConfig.CurrentACPFile ?? "",
StepIndex = step.Index,
StepName = step.Name ?? "",
StepType = step.StepType ?? "普通步骤",
MethodName = step.Method?.Name,
MethodFullName = step.Method?.FullName,
Result = step.Result switch
{
-1 => "未执行",
0 => "执行中",
1 => "成功",
2 => "失败",
_ => "未知"
},
RunTimeMs = step.RunTime,
OutputValue = outputValue,
Depth = depth,
IsErrorStep = isErrorStep,
LoopRemaining = step.CurrentLoopCount,
CreateTime = DateTime.Now
};
var result = await _testReportService.InsertAsync(entity);
if (!result.IsSuccess)
{
LoggerHelper.Error($"保存步骤记录失败 [{step.Index}]: {result.Msg}");
}
}
catch (Exception ex)
{
LoggerHelper.Error($"保存步骤记录失败 [{step.Index}]: {ex.Message}");
}
}
public void ResetAllStepStatus(ObservableCollection<StepVM> StepCollection)
{
foreach (var step in StepCollection)
{
step.Result = -1;
step.RunTime = null;
}
}
private void UpdateCurrentStepResult(StepVM step, bool paraResult = true, bool stepResult = true, int depth = 0)
{
if (stepResult && paraResult)
{
if (string.IsNullOrEmpty(step.OKExpression))
{
step.Result = 1;
}
else
{
Dictionary<string, object> paraDic = [];
foreach (var item in tmpParameters)
{
paraDic.TryAdd(item.Value.Name, item.Value.Value!);
}
if (step.SubProgram != null)
{
foreach (var item in step.SubProgram.Parameters.Where(x => x.Category == ParameterCategory.Output))
{
paraDic.TryAdd(item.Name, item.Value!);
}
}
else if (step.Method != null)
{
foreach (var item in step.Method.Parameters.Where(x => x.Category == ParameterCategory.Output))
{
paraDic.TryAdd(item.Name, item.Value!);
}
}
bool re = ExpressionEvaluator.EvaluateExpression(step.OKExpression, paraDic);
step.Result = re ? 1 : 2;
if (step.Result == 2)
{
LoggerHelper.WarnWithNotify(_systemConfig.Title, $"指令 [ {step.Index} ] NG:条件表达式验证失败", depth: depth);
}
}
}
else
{
if (!paraResult)
{
LoggerHelper.WarnWithNotify(_systemConfig.Title, "参数限值校验失败", depth: depth);
}
step.Result = 2;
}
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
// 1. 唤醒暂停循环IsStop 可能卡住后台线程)
try
{
if (_scopedContext != null)
{
_scopedContext.IsStop = false;
_scopedContext.IsTerminate = true;
_scopedContext.RunState = "运行";
}
}
catch { }
try
{
if (stepCTS != null && !stepCTS.IsCancellationRequested) stepCTS.Cancel();
}
catch (ObjectDisposedException) { }
try
{
if (errorStepCTS != null && !errorStepCTS.IsCancellationRequested) errorStepCTS.Cancel();
}
catch (ObjectDisposedException) { }
tmpParameters.Clear();
loopStack.Clear();
loopStopwatchStack.Clear();
stepStopwatch.Stop();
}
#region
private class LoopContext
{
public int LoopCount { get; set; }
public int CurrentLoop { get; set; }
public int StartIndex { get; set; }
public StepVM? LoopStartStep { get; set; }
}
#endregion
}
}