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#

4 months ago
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
});
}
}
}