|
|
|
|
using DS.Module.Core;
|
|
|
|
|
using DS.Module.Core.Condition;
|
|
|
|
|
using DS.Module.Core.Data;
|
|
|
|
|
using DS.WMS.Core.Code.Entity;
|
|
|
|
|
using DS.WMS.Core.Op.Dtos;
|
|
|
|
|
using DS.WMS.Core.Op.Dtos.TaskInteraction;
|
|
|
|
|
using DS.WMS.Core.Op.Entity;
|
|
|
|
|
using DS.WMS.Core.Op.Entity.TaskInteraction;
|
|
|
|
|
using DS.WMS.Core.Op.Interface.TaskInteraction;
|
|
|
|
|
using DS.WMS.Core.Op.Method.TaskInteraction.ActionSelector;
|
|
|
|
|
using DS.WMS.Core.Sys.Entity;
|
|
|
|
|
using DS.WMS.Core.TaskPlat.Entity;
|
|
|
|
|
using Fasterflect;
|
|
|
|
|
using LanguageExt.Pipes;
|
|
|
|
|
using Masuit.Tools;
|
|
|
|
|
using Masuit.Tools.Systems;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using SqlSugar;
|
|
|
|
|
|
|
|
|
|
namespace DS.WMS.Core.Op.Method.TaskInteraction
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 动作执行管理
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class ActionManagerService : ServiceBase, IActionManagerService
|
|
|
|
|
{
|
|
|
|
|
ITaskLogService logService;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ActionManagerService(IServiceProvider serviceProvider) : base(serviceProvider)
|
|
|
|
|
{
|
|
|
|
|
logService = serviceProvider.GetRequiredService<ITaskLogService>();
|
|
|
|
|
TenantDb.QueryFilter.Clear<IOrgId>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据指定条件返回是否匹配的结果
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="source">要对比的数据源</param>
|
|
|
|
|
/// <param name="condition">匹配条件</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool IsMatch(object source, ConditionContent condition)
|
|
|
|
|
{
|
|
|
|
|
if (source == null || condition == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
TaskFlowDataContext dataContext = new((TaskFlowDataNameConst.Business, source));
|
|
|
|
|
if (condition.SourceName.IsNullOrEmpty())
|
|
|
|
|
condition.SourceName = TaskFlowDataNameConst.Business;
|
|
|
|
|
|
|
|
|
|
return ConditionHelper.IsPass(condition, dataContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据指定条件返回是否匹配的结果
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="bsId">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="conditions">匹配条件</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<bool> IsMatchAsync(long bsId, BusinessType businessType, IEnumerable<ConditionContent> conditions)
|
|
|
|
|
{
|
|
|
|
|
ArgumentNullException.ThrowIfNull(conditions, nameof(conditions));
|
|
|
|
|
|
|
|
|
|
var biz = await GetBusinessDataAsync(bsId, businessType, conditions);
|
|
|
|
|
if (biz != null)
|
|
|
|
|
{
|
|
|
|
|
TaskFlowDataContext dataContext = new((TaskFlowDataNameConst.Business, biz));
|
|
|
|
|
//循环匹配
|
|
|
|
|
foreach (var item in conditions)
|
|
|
|
|
{
|
|
|
|
|
if (ConditionHelper.IsPass(item, dataContext))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取所需业务数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="businessId">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="conditions">条件字段</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<dynamic?> GetBusinessDataAsync(long businessId, BusinessType businessType, IEnumerable<ConditionContent> conditions)
|
|
|
|
|
{
|
|
|
|
|
ArgumentNullException.ThrowIfNull(conditions, nameof(conditions));
|
|
|
|
|
|
|
|
|
|
HashSet<string> fields = [];
|
|
|
|
|
foreach (var item in conditions)
|
|
|
|
|
{
|
|
|
|
|
if (item.Conditions != null)
|
|
|
|
|
fields.AddRange(item.Conditions.Select(x => x.Field));
|
|
|
|
|
|
|
|
|
|
if (item.Groups != null)
|
|
|
|
|
fields.AddRange(item.Groups.SelectMany(x => x.Conditions.Select(x => x.Field)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await GetBusinessDataAsync(businessId, businessType, fields.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取所需业务数据
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="businessId">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="fields">返回字段列表</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<dynamic?> GetBusinessDataAsync(long businessId, BusinessType businessType, params string[] fields)
|
|
|
|
|
{
|
|
|
|
|
object? biz = null;
|
|
|
|
|
switch (businessType)
|
|
|
|
|
{
|
|
|
|
|
case BusinessType.OceanShippingExport:
|
|
|
|
|
//未设置查询字段
|
|
|
|
|
if (fields == null || fields.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
biz = await TenantDb.Queryable<SeaExport>().Where(a => a.Id == businessId)
|
|
|
|
|
.Select<SeaExportRes>().Mapper(it =>
|
|
|
|
|
{
|
|
|
|
|
it.DischargePortCountry = TenantDb.Queryable<CodePort>().Where(x => x.Id == it.DischargePortId).Select(x => x.CountryName).First();
|
|
|
|
|
}).FirstAsync();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var selectors = fields.Select(x => new SelectModel { FieldName = x }).ToList();
|
|
|
|
|
biz = await TenantDb.Queryable<object>().AS("op_sea_export")
|
|
|
|
|
.Where("Id=@Id", new { Id = businessId }).Select(selectors).FirstAsync();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BusinessType.OceanShippingImport:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return biz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 执行放舱任务(任务台使用)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async Task SpaceReleaseTask(TaskFlowDataContext dataContext)
|
|
|
|
|
{
|
|
|
|
|
dataContext.Set("TypeName", "DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.SpaceRelease.SpaceReleaseActionExecutor,DS.WMS.Core");
|
|
|
|
|
|
|
|
|
|
var businessId = dataContext.Get<long?>(TaskFlowDataNameConst.BusinessId);
|
|
|
|
|
ArgumentNullException.ThrowIfNull(businessId, TaskFlowDataNameConst.BusinessId);
|
|
|
|
|
|
|
|
|
|
//await TriggerActionAsync(businessId.Value, BusinessType.OceanShippingExport, TaskBaseTypeEnum.WAIT_SPACE_RELEASE);
|
|
|
|
|
|
|
|
|
|
var businessTask = await TenantDb.Queryable<BusinessTask>().Where(
|
|
|
|
|
x => x.BusinessId == businessId && x.BusinessType == BusinessType.OceanShippingExport && x.TaskType == TaskBaseTypeEnum.WAIT_SPACE_RELEASE).FirstAsync();
|
|
|
|
|
|
|
|
|
|
dataContext.Set(TaskFlowDataNameConst.BusinessTask, businessTask);
|
|
|
|
|
|
|
|
|
|
await ExecuteAsync(dataContext);
|
|
|
|
|
|
|
|
|
|
//var service = ServiceProvider.GetRequiredService<ISeaExportTaskService>();
|
|
|
|
|
//await service.CreateSubTaskAsync(businessTask);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 触发任务执行动作
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="businessTask">任务信息</param>
|
|
|
|
|
/// <param name="includeOrder">是否包含订单数据</param>
|
|
|
|
|
/// <param name="additionalData">附加参数</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> TriggerActionAsync(BusinessTask businessTask, bool includeOrder = false, IDictionary<string, object>? additionalData = null)
|
|
|
|
|
{
|
|
|
|
|
ArgumentNullException.ThrowIfNull(businessTask, nameof(businessTask));
|
|
|
|
|
|
|
|
|
|
if (businessTask.BusinessType == null)
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
|
|
|
|
|
TaskFlowDataContext dataContext = new(
|
|
|
|
|
(TaskFlowDataNameConst.BusinessTask, businessTask)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var paramList = await GetTaskParamsAsync(businessTask.TaskType);
|
|
|
|
|
var gpList = paramList.GroupBy(x => x.FieldName).Select(x => new
|
|
|
|
|
{
|
|
|
|
|
FieldName = x.Key,
|
|
|
|
|
Values = x.Select(y => y.FieldValue)
|
|
|
|
|
}).ToList();
|
|
|
|
|
foreach (var g in gpList)
|
|
|
|
|
{
|
|
|
|
|
if (g.FieldName == TaskFlowDataNameConst.TypeName)
|
|
|
|
|
{
|
|
|
|
|
dataContext[g.FieldName] = g.Values;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (g.Values.Count() == 1)
|
|
|
|
|
dataContext[g.FieldName] = g.Values.FirstOrDefault();
|
|
|
|
|
else
|
|
|
|
|
dataContext[g.FieldName] = g.Values;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (additionalData != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in additionalData)
|
|
|
|
|
dataContext[item.Key] = item.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!dataContext.TryGetValue(TaskFlowDataNameConst.TypeName, out object value))
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
|
|
|
|
|
if (includeOrder)
|
|
|
|
|
{
|
|
|
|
|
var biz = GetBusinessDataAsync(businessTask.BusinessId, businessTask.BusinessType.Value);
|
|
|
|
|
dataContext[TaskFlowDataNameConst.Business] = biz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
IEnumerable<string>? typeNames = value as IEnumerable<string>;
|
|
|
|
|
string typeStr = typeNames == null ? value.ToString() : string.Join(",", typeNames);
|
|
|
|
|
|
|
|
|
|
await logService.WriteLogAsync(businessTask, $"开始运行【{businessTask.TaskType.GetDescription()}】动作:{typeStr} ...");
|
|
|
|
|
|
|
|
|
|
await ExecuteAsync(dataContext);
|
|
|
|
|
|
|
|
|
|
await logService.WriteLogAsync(businessTask, $"【{businessTask.TaskType.GetDescription()}】动作:{typeStr} 运行结束");
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await logService.WriteLogAsync(businessTask, $"执行【{businessTask.TaskType.GetDescription()}】动作时出错:{ex.Message}"
|
|
|
|
|
+ Environment.NewLine + "调用堆栈:" + ex.StackTrace);
|
|
|
|
|
return DataResult.FailedWithDesc(MultiLanguageConst.Operation_Failed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 自动订舱
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="businessId">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> AutomaticBooking(long businessId, BusinessType businessType)
|
|
|
|
|
{
|
|
|
|
|
var businessTask = await TenantDb.Queryable<BusinessTask>().Where(
|
|
|
|
|
x => x.BusinessId == businessId && x.BusinessType == businessType && x.TaskType == TaskBaseTypeEnum.WAIT_BOOKING).FirstAsync();
|
|
|
|
|
if (businessTask == null)
|
|
|
|
|
return DataResult.FailedWithDesc(MultiLanguageConst.BookingTaskNotFound);
|
|
|
|
|
|
|
|
|
|
var dic = new Dictionary<string, object>
|
|
|
|
|
{
|
|
|
|
|
[TaskFlowDataNameConst.TypeName] = new string[1] { typeof(BookingSelector).AssemblyQualifiedName }
|
|
|
|
|
};
|
|
|
|
|
return await TriggerActionAsync(businessTask, false, dic);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取指定任务类型的参数
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="taskType">任务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
internal async Task<List<TaskFlowParam>> GetTaskParamsAsync(TaskBaseTypeEnum taskType)
|
|
|
|
|
{
|
|
|
|
|
return await TenantDb.Queryable<TaskFlowParam>()
|
|
|
|
|
.InnerJoin<TaskFlowConfig>((p, c) => p.ConfigId == c.Id)
|
|
|
|
|
.InnerJoin<TaskFlowModule>((p, c, m) => c.ExecuteModuleId == m.Id)
|
|
|
|
|
.Where((p, c, m) => m.TaskType == taskType.ToString() && m.ModuleType == 2).ToListAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 执行动作
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="dataContext"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task ExecuteAsync(TaskFlowDataContext dataContext)
|
|
|
|
|
{
|
|
|
|
|
ArgumentNullException.ThrowIfNull(dataContext, nameof(dataContext));
|
|
|
|
|
|
|
|
|
|
var context = new ActionExecutionContext
|
|
|
|
|
{
|
|
|
|
|
ActionManager = this,
|
|
|
|
|
TaskInfo = dataContext.GetOrDefault<BusinessTask>(TaskFlowDataNameConst.BusinessTask),
|
|
|
|
|
ServiceProvider = ServiceProvider
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
foreach (var key in dataContext.Keys)
|
|
|
|
|
context.AdditionalData[key] = dataContext[key];
|
|
|
|
|
|
|
|
|
|
if (!dataContext.TryGetValue(TaskFlowDataNameConst.TypeName, out object typeNameObj) || typeNameObj == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
IEnumerable<string> typeNames = typeNameObj as IEnumerable<string>;
|
|
|
|
|
typeNames ??= [typeNameObj.ToString()];
|
|
|
|
|
if (typeNames.IsNullOrEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
foreach (var typeName in typeNames)
|
|
|
|
|
{
|
|
|
|
|
Type? t = Type.GetType(typeName, true, false);
|
|
|
|
|
if (t == null)
|
|
|
|
|
{
|
|
|
|
|
await new ApplicationException($"未能获取类型【{typeName}】的信息,请检查配置").LogAsync(Db);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IActionExecutor? currentExecutor = null;
|
|
|
|
|
object instance = ConstructorExtensions.CreateInstance(t);
|
|
|
|
|
if (instance is IActionSelector selector)
|
|
|
|
|
{
|
|
|
|
|
currentExecutor = await selector.GetActionExecutor(context);
|
|
|
|
|
}
|
|
|
|
|
else if (instance is IActionExecutor executor)
|
|
|
|
|
{
|
|
|
|
|
currentExecutor = executor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentExecutor == null)
|
|
|
|
|
{
|
|
|
|
|
await new ApplicationException($"未能创建类型【{t.AssemblyQualifiedName}】的实例").LogAsync(Db);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await currentExecutor.ExecuteAsync(context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ISugarQueryable<SysUser> GetUserQueryable(params long[] ids)
|
|
|
|
|
{
|
|
|
|
|
return Db.Queryable<SysUser>().Where(x => ids.Contains(x.Id));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|