You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
12 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using DS.Module.Core;
using DS.Module.Core.Data;
using DS.WMS.Core.TaskPlat.Dtos;
using DS.WMS.Core.TaskPlat.Entity;
using Newtonsoft.Json;
using SqlSugar;
using System.Diagnostics;
using System.Reflection;
namespace DS.WMS.Core.TaskPlat
{
/// <summary>
/// 任务编排执行器
/// </summary>
public class TaskFlowRuner
{
private readonly SqlSugarScopeProvider tenantDb = null!;
private readonly IServiceProvider serviceProvider = null!;
private TaskFlowRuner() { }
/// <summary>
///
/// </summary>
/// <param name="tenantDb"></param>
/// <param name="serviceProvider"></param>
public TaskFlowRuner(SqlSugarScopeProvider tenantDb, IServiceProvider serviceProvider)
{
this.tenantDb = tenantDb;
this.serviceProvider = serviceProvider;
}
public async Task Run(TaskBaseTypeEnum taskBaseType, TaskManageOrderMessageInfo messageInfo, TaskBaseInfo taskInfo, TaskFlowDataContext dataContext)
{
if (taskInfo == null)
{
throw new ArgumentNullException(nameof(taskInfo));
}
if (dataContext == null)
{
throw new ArgumentNullException(nameof(dataContext));
}
var allConfigList = await tenantDb.Queryable<TaskFlowConfig>()
.Where(t => t.IsMain && t.TaskType == taskBaseType.ToString())
.OrderBy(t => t.Id)
.ToListAsync();
if (allConfigList.Count == 0)
{
string msg = $"未找到任何用于【{taskBaseType}】业务的处理流程";
TaskFlowLog log = new()
{
IsMatch = false,
TaskId = taskInfo.Id,
TaskType = taskBaseType.ToString(),
ExecuteStatus = 2,
ExceptionMessage = msg
};
await tenantDb.Insertable(log).ExecuteCommandAsync();
throw new Exception(msg);
}
var allConfigIdList = allConfigList.Select(x => x.Id);
var allConditionList = await tenantDb.Queryable<TaskFlowCondition>()
.Where(x => allConfigIdList.Contains(x.ConfigId))
.ToListAsync();
Dictionary<long, int> configMatchCount = allConfigList.ToDictionary(x => x.Id, x => 0);
//dynamic taskInfoDynamic = taskInfo;
foreach (var configItem in allConfigList)
{
var conditionListGroup = allConditionList.Where(x => x.ConfigId == configItem.Id);
foreach (var conditionItem in conditionListGroup)
{
var (_, val, _) = GetPropertyValue(messageInfo, conditionItem.FieldName);
if (val == null) continue;
var valStr = val.ToString()!;
if (conditionItem.MatchType == 1)
{
if (valStr.Equals(conditionItem.MatchValue, StringComparison.CurrentCultureIgnoreCase))
{
configMatchCount[configItem.Id] = configMatchCount[configItem.Id] + 1;
}
}
else if (conditionItem.MatchType == 2)
{
if (valStr.Contains(conditionItem.MatchValue!, StringComparison.CurrentCultureIgnoreCase))
{
configMatchCount[configItem.Id] = configMatchCount[configItem.Id] + 1;
}
}
else if (conditionItem.MatchType == 3)
{
if (valStr.StartsWith(conditionItem.MatchValue!, StringComparison.CurrentCultureIgnoreCase))
{
configMatchCount[configItem.Id] = configMatchCount[configItem.Id] + 1;
}
}
else if (conditionItem.MatchType == 4)
{
if (valStr.EndsWith(conditionItem.MatchValue!, StringComparison.CurrentCultureIgnoreCase))
{
configMatchCount[configItem.Id] = configMatchCount[configItem.Id] + 1;
}
}
}
}
KeyValuePair<long, int>? bestMatched = null!;
foreach (var item in configMatchCount)
{
if (bestMatched == null)
{
bestMatched = new KeyValuePair<long, int>(item.Key, item.Value);
continue;
}
if (item.Value > bestMatched.Value.Value)
{
bestMatched = new KeyValuePair<long, int>(item.Key, item.Value);
continue;
}
if (item.Value == bestMatched.Value.Value)
{
if (item.Key < bestMatched.Value.Key)
{
bestMatched = new KeyValuePair<long, int>(item.Key, item.Value);
continue;
}
}
}
var targetConfig = allConfigList.First(x => x.Id == bestMatched.Value.Key);
var configList = await tenantDb.Queryable<TaskFlowConfig>().Where(x => x.MainConfigId == targetConfig.Id).ToListAsync();
var configIdList = configList.Select(x => x.Id).ToList();
var moduleIdList = configList.Select(x => x.ExecuteModuleId).ToList();
var paramList = await tenantDb.Queryable<TaskFlowParam>().Where(x => configIdList.Contains(x.ConfigId)).ToListAsync();
var moduleList = await tenantDb.Queryable<TaskFlowModule>().Where(x => moduleIdList.Contains(x.Id)).ToListAsync();
TaskFlowLog flowLog = new()
{
Id = SnowFlakeSingle.Instance.NextId(),
IsMatch = true,
TaskId = taskInfo.Id,
TaskType = taskBaseType.ToString(),
MatchMainConfigId = targetConfig.Id,
ConfigList = JsonConvert.SerializeObject(configList),
ModuleList = JsonConvert.SerializeObject(moduleList),
ExecuteStatus = 1
};
foreach (var configItem in configList)
{
TaskFlowLogDetail flowLogDetail = new()
{
ConfigId = configItem.Id,
PId = flowLog.Id,
};
try
{
var paramItemList = paramList.Where(x => x.ConfigId == configItem.Id).ToList();
foreach (var paramItem in paramItemList)
{
dataContext.Set(paramItem.FieldName!, paramItem.FieldValue!);
//if (dataContext.ContainsKey(paramItem.FieldName!))
//{
// dataContext[paramItem.FieldName!] = paramItem.FieldValue!;
//}
//else
//{
// dataContext.TryAdd(paramItem.FieldName!, paramItem.FieldValue!);
//}
}
var module = moduleList.FirstOrDefault(x => x.Id == configItem.ExecuteModuleId);
if (module == null)
{
throw new Exception($"未找到指定流程配置ExecuteModuleId{configItem.ExecuteModuleId}");
}
Assembly assembly;
if (module.NameSpace!.StartsWith("DS.WMS.Core"))
{
//assembly = Assembly.GetEntryAssembly()!;
assembly = Assembly.GetExecutingAssembly();
}
else
{
assembly = Assembly.Load(module.NameSpace!);
}
//var interfaceType2 = assembly.GetType(module.InterfaceName!);
var interfaceType = assembly.DefinedTypes.FirstOrDefault(x => x.Name == module.InterfaceName!);
if (interfaceType == null)
{
throw new Exception($"在命名空间【{module.NameSpace}】下未找到Interface【{module.InterfaceName}】");
}
object? imp = serviceProvider.GetService(interfaceType);
if (imp == null)
{
throw new Exception($"在依赖注入容器未找到Interface【{module.InterfaceName}】的实现类");
}
MethodInfo? method = imp.GetType().GetMethod(module.MethodName!);
if (method == null)
{
throw new Exception($"在Interface【{module.InterfaceName}】的实现类中未找到Method【{module.MethodName}】");
}
Stopwatch stopwatch = Stopwatch.StartNew();
var invokeResult = method.Invoke(imp, new object[] { dataContext });
// 这里需要取一下返回值
//var b = invokeResult as DataResult;
//var c = invokeResult as Task<DataResult>;
//var d = c.Result;
if (invokeResult is DataResult result)
{
}
else if (invokeResult is Task<DataResult> result2)
{
}
stopwatch.Stop();
flowLogDetail.ElapsedMillisecond = stopwatch.ElapsedMilliseconds;
flowLogDetail.ExecuteStatus = 1;
await tenantDb.Insertable(flowLogDetail).ExecuteCommandAsync();
}
catch (Exception ex)
{
flowLog.ExecuteStatus = 2;
flowLogDetail.ExceptionMessage = WriteLog("", ex);
flowLogDetail.ExecuteStatus = 2;
await tenantDb.Insertable(flowLogDetail).ExecuteCommandAsync();
if (configItem.IsExceptionContinue)
{
continue;
}
else
{
break;
}
}
}
await tenantDb.Insertable(flowLog).ExecuteCommandAsync();
}
/// <summary>
/// 深度获取对象属性值
/// </summary>
/// <param name="obj">对象</param>
/// <param name="propertyPath">属性路径</param>
static (bool isOk, object? val, string? otherPropertyPath) GetPropertyValue(object obj, string propertyPath)
{
var propertyName = propertyPath.Split('.').FirstOrDefault();
var type = obj.GetType();
var property = type.GetProperty(propertyName);
if (property == null)
{
return (true, null, null);
}
if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
{
var val = property.GetValue(obj);
if (val == null)
{
return (true, null, null);
}
var otherPropertyPath = propertyPath.Substring(propertyPath.IndexOf('.') + 1);
return GetPropertyValue(val, otherPropertyPath);
}
else
{
var val = property.GetValue(obj);
return (true, val, null);
}
}
static string WriteLog(string throwMsg, Exception ex)
{
return string.Format("【自定义错误】:{0} \r\n【异常类型】{1} \r\n【异常信息】{2} \r\n【堆栈调用】{3}", new object[]
{
throwMsg,
ex.GetType().Name,
ex.Message,
ex.StackTrace
});
}
}
}