通知更新任务接收人

usertest
嵇文龙 4 months ago
parent 7085fc9bbd
commit 0052c331c9

@ -225,6 +225,11 @@ namespace DS.Module.Core
[Description("待放单")]
WAIT_CHECKOUT_BILL = 208,
/// <summary>
/// 审单驳回
/// </summary>
[Description("审单驳回")]
ORDER_AUDIT_REJECTED = 401,
#endregion
#region 工作流--可选服务项目

@ -285,7 +285,7 @@ namespace DS.WMS.Core.Fee.Method
/// </summary>
/// <param name="auditTypes">审核类型</param>
/// <returns></returns>
protected ISugarQueryable<FlowInstance> GetCurrentFlowsQuery(AuditType[] auditTypes)
protected internal ISugarQueryable<FlowInstance> GetCurrentFlowsQuery(AuditType[] auditTypes)
{
return Db.Queryable<FlowInstance>().Where(x => x.FlowStatus == FlowStatusEnum.Running
&& SqlFunc.SplitIn(x.MakerList, User.UserId) && auditTypes.Contains(x.Type.Value))

@ -4,7 +4,7 @@ using DS.WMS.Core.Op.Entity;
namespace DS.WMS.Core.Flow.Dtos
{
/// <summary>
/// 工作流回调信息
/// 工作流完成回调信息
/// </summary>
public class FlowCallback
{

@ -0,0 +1,36 @@
using DS.Module.Core;
using DS.WMS.Core.Op.Entity;
namespace DS.WMS.Core.Flow.Dtos
{
/// <summary>
/// 执行人变更回调信息
/// </summary>
public class MakerChangedCallback
{
/// <summary>
/// 工作流实例ID
/// </summary>
public long InstanceId { get; set; }
/// <summary>
/// 业务ID
/// </summary>
public long BusinessId { get; set; }
/// <summary>
/// 业务类型
/// </summary>
public BusinessType? BusinessType { get; set; }
/// <summary>
/// 工作流类型
/// </summary>
public AuditType? Type { get; set; }
/// <summary>
/// 下一执行人的用户ID
/// </summary>
public long? NextUserId { get; set; }
}
}

@ -86,9 +86,15 @@ public class FlowInstance : BaseTenantModel<long>
public string Content { get; set; }
/// <summary>
/// 回调地址
/// 执行人变更回调地址
/// </summary>
[SugarColumn(ColumnDescription = "回调地址", IsNullable = true, Length = 255)]
[SugarColumn(ColumnDescription = "执行人变更回调地址", IsNullable = true, Length = 255)]
public string? MakerNotifyURL { get; set; }
/// <summary>
/// 审批完成回调地址
/// </summary>
[SugarColumn(ColumnDescription = "审批完成回调地址", IsNullable = true, Length = 255)]
public string? CallbackURL { get; set; }
/// <summary>

@ -45,11 +45,17 @@ public class FlowTemplate : BaseModel<long>
[SugarColumn(ColumnDescription = "状态")]
public StatusEnum? Status { get; set; } = StatusEnum.Enable;
/// <summary>
/// 执行人变更回调地址
/// </summary>
[SugarColumn(ColumnDescription = "执行人变更回调地址", IsNullable = true, Length = 255)]
public string? MakerNotifyURL { get; set; }
/// <summary>
/// 回调地址
/// </summary>
[SugarColumn(ColumnDescription = "回调地址", IsNullable = true, Length = 255)]
public string CallbackURL { get; set; }
public string? CallbackURL { get; set; }
/// <summary>
/// 审批类型

@ -45,11 +45,17 @@ public class FlowTemplateTenant : BaseTenantModel<long>
[SugarColumn(ColumnDescription = "状态")]
public StatusEnum? Status { get; set; } = StatusEnum.Enable;
/// <summary>
/// 执行人变更回调地址
/// </summary>
[SugarColumn(ColumnDescription = "执行人变更回调地址", IsNullable = true, Length = 255)]
public string? MakerNotifyURL { get; set; }
/// <summary>
/// 回调地址
/// </summary>
[SugarColumn(ColumnDescription = "回调地址", IsNullable = true, Length = 255)]
public string CallbackURL { get; set; }
public string? CallbackURL { get; set; }
/// <summary>
/// 审批类型

@ -39,6 +39,7 @@ public class ClientFlowInstanceService : FlowInstanceService, IClientFlowInstanc
PermissionId = template.PermissionId,
ColumnView = template.ColumnView,
Content = template.Content,
MakerNotifyURL = template.MakerNotifyURL,
CallbackURL = template.CallbackURL,
Type = template.AuditType
};

@ -93,6 +93,7 @@ public class FlowInstanceService : IFlowInstanceService
PermissionId = template.PermissionId,
ColumnView = template.ColumnView,
Content = template.Content,
MakerNotifyURL = template.MakerNotifyURL,
CallbackURL = template.CallbackURL,
Type = template.AuditType
};
@ -150,7 +151,6 @@ public class FlowInstanceService : IFlowInstanceService
if (wfruntime.GetNextNodeType() == 4 && !instance.CallbackURL.IsNullOrEmpty())
{
Task.Factory.StartNew(() => RunCallbackAsync(instance));
//RunCallbackAsync(instance);
}
var userInfo = db.Queryable<SysUser>().First(x => x.Id == long.Parse(user.UserId));
@ -202,8 +202,7 @@ public class FlowInstanceService : IFlowInstanceService
instance.ActivityId = startNodeId;
instance.ActivityType = wfruntime.GetNodeType(startNodeId);
instance.ActivityName = wfruntime.ChildNodes.First(x => x.Id == startNodeId).Name;
instance.MakerList =
(wfruntime.GetNextNodeType() != 4 ? GetCurrentMakers(wfruntime) : "1");
instance.MakerList = (wfruntime.GetNextNodeType() != 4 ? GetCurrentMakers(wfruntime) : "1");
instance.FlowStatus = FlowStatusEnum.Draft;
wfruntime.FlowInstanceId = instance.Id;
@ -321,9 +320,7 @@ public class FlowInstanceService : IFlowInstanceService
var runtime = CreateRuntimeService(instance);
if (runtime.CurrentNodeId != instance.ActivityId)
{
return DataResult.Failed("该工作流审批节点与当前节点不一致!", MultiLanguageConst.FlowInstanceNodeIdConflict);
}
#region 会签
@ -352,13 +349,18 @@ public class FlowInstanceService : IFlowInstanceService
instance.FlowStatus = runtime.NextNodeType == 4 ? FlowStatusEnum.Approve : FlowStatusEnum.Running;
instance.MakerList = runtime.NextNodeType == 4 ? "1" : GetNextMakers(runtime);
}
// AddTransHistory(wfruntime);
}
else
{
//会签过程中,需要更新用户
instance.MakerList = GetForkNodeMakers(runtime, runtime.CurrentNodeId);
// AddTransHistory(wfruntime);
}
string marker = GetNextMarker(instance);
//获取会签下一执行人,进行通知
if (!marker.IsNullOrEmpty() && marker != "-1" && !instance.MakerNotifyURL.IsNullOrEmpty())
{
Task.Factory.StartNew(() => NotifyMakerChangedAsync(instance, long.Parse(marker)));
}
}
@ -422,6 +424,47 @@ public class FlowInstanceService : IFlowInstanceService
return DataResult.Successed("审批成功!", MultiLanguageConst.FlowInstanceAuditSuccess);
}
/// <summary>
/// 获取会签下一执行人
/// </summary>
/// <param name="instance">运行实例</param>
/// <returns></returns>
public static string GetNextMarker(FlowInstance instance)
{
//if (instance.ActivityType != 0)
// return string.Empty;
if (instance.MakerList.IsNullOrEmpty() || instance.MakerList == "-1")
return instance.MakerList;
string[] markers = instance.MakerList.Split([','], StringSplitOptions.RemoveEmptyEntries);
if (markers.Length > 0 && long.TryParse(markers[0], out long nextUserId))
return nextUserId.ToString();
return instance.MakerList;
}
/// <summary>
/// 运行执行人变更回调
/// </summary>
/// <param name="instance">运行实例</param>
/// <param name="nextUserId">下一执行人ID</param>
/// <returns></returns>
protected virtual async Task NotifyMakerChangedAsync(FlowInstance instance, long nextUserId)
{
//请求参数设置
var callback = new MakerChangedCallback
{
InstanceId = instance.Id,
BusinessId = instance.BusinessId,
BusinessType = instance.BusinessType,
Type = instance.Type,
NextUserId = nextUserId
};
await api.PostAsync<DataResult>(instance.MakerNotifyURL, callback);
}
/// <summary>
/// 对指定的回调URL发起异步请求
/// </summary>
@ -516,7 +559,7 @@ public class FlowInstanceService : IFlowInstanceService
string makerList = "";
if (wfruntime.NextNodeId == "-1")
{
throw (new Exception("无法寻找到下一个节点"));
throw new Exception("无法寻找到下一个节点");
}
// if (wfruntime.NextNodeType == 0) //如果是会签节点
@ -539,7 +582,7 @@ public class FlowInstanceService : IFlowInstanceService
makerList = GetNodeMarkers(wfruntime.NextNode);
if (string.IsNullOrEmpty(makerList))
{
throw (new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!"));
throw new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!");
}
}

@ -108,7 +108,7 @@ public class FlowRuntime
/// <summary>
/// 下一个节点对象
/// </summary>
public FlowChild NextNode => NextNodeId != "-1" ? ChildNodes.First(x => x.Id == NextNodeId) : null;
public FlowChild? NextNode => NextNodeId != "-1" ? ChildNodes.First(x => x.Id == NextNodeId) : null;
/// <summary>
/// 上一个节点

@ -32,5 +32,10 @@ namespace DS.WMS.Core.Op.Dtos.TaskInteraction
/// 任务描述
/// </summary>
public string? TaskDescription { get; set; }
/// <summary>
/// 任务接收用户ID此值为空时则默认为任务发起者
/// </summary>
public long[]? RecvUserIdList { get; set; }
}
}

@ -1,4 +1,5 @@
using DS.Module.Core;
using DS.Module.Core.Extensions;
using SqlSugar;
namespace DS.WMS.Core.Op.Entity.TaskInteraction
@ -51,6 +52,19 @@ namespace DS.WMS.Core.Op.Entity.TaskInteraction
[SugarColumn(ColumnDescription = "工作流ID", IsNullable = true)]
public long? FlowId { get; set; }
/// <summary>
/// 接收人列表
/// </summary>
[SugarColumn(ColumnDescription = "接收人列表", IsNullable = false, ColumnDataType = "text")]
public string RecvUsers { get; set; } = string.Empty;
/// <summary>
/// 获取接收人用户ID列表
/// </summary>
[SugarColumn(IsIgnore = true)]
public long[] RecvUserIdArray => RecvUsers.IsNullOrEmpty() ? [] :
RecvUsers.Split([','], StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToArray();
/// <summary>
/// 创建人
/// </summary>

@ -2,8 +2,6 @@
using DS.Module.Core.Extensions;
using DS.Module.DjyServiceStatus;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.TaskInteraction;
@ -22,7 +20,6 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
public class SeaExportTaskService : TaskService, ISeaExportTaskService
{
readonly Lazy<IDjyServiceStatusService> djyService;
readonly Lazy<IClientFlowInstanceService> flowService;
/// <summary>
/// 初始化
@ -31,39 +28,6 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
public SeaExportTaskService(IServiceProvider provider) : base(provider)
{
djyService = new Lazy<IDjyServiceStatusService>(provider.GetRequiredService<IDjyServiceStatusService>());
flowService = new Lazy<IClientFlowInstanceService>(provider.GetRequiredService<IClientFlowInstanceService>());
}
/// <summary>
/// 当任务创建时调用
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
protected override async Task<DataResult> OnTaskCreated(BusinessTask task)
{
if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
{
//待审核,需创建工作流
var template = await FindTemplateAsync(AuditType.SeaExport);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
var result = flowService.Value.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = task.BusinessId,
BusinessType = BusinessType.OceanShippingExport,
TemplateId = template.Id
});
if (result.Succeeded)
{
var instance = result.Data as FlowInstance;
task.FlowId = instance.Id;
await TenantDb.Updateable(task).UpdateColumns(x => x.FlowId).ExecuteCommandAsync();
}
}
return DataResult.Success;
}
/// <summary>
@ -88,7 +52,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
x.Voyno,
x.ETD,
}).FirstAsync(x => x.Id == first.BusinessId);
var userList = await GetRecvUsers(first.RecvUserIdList);
foreach (var item in request)
{
var info = new TaskManageOrderMessageInfo
@ -112,7 +76,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
TaskSource = TaskSourceEnum.WORK_FLOW,
TaskUserId = User.UserId,
TaskUserName = User.UserName,
RecvUserInfoList = [new RecvUserInfo { RecvUserId = long.Parse(User.UserId), RecvUserName = User.UserName }],
RecvUserInfoList = userList,
TaskTenatId = tenatId,
TaskTenatName = tenatName
}
@ -149,18 +113,19 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
//放舱结束,根据业务所选服务,生成子任务
if (request.TaskType == TaskBaseTypeEnum.WAIT_SPACE_RELEASE && request.TaskStatus == TaskStatusEnum.Complete)
{
var list = await GetSubRequestAsync(request.BusinessId, request.BusinessType);
var task = await GetTaskAsync(request.BusinessId, request.BusinessType, request.TaskType);
var list = await GetSubRequestAsync(request.BusinessId, request.BusinessType, task?.RecvUserIdArray);
await CreateSubTaskAsync(list);
}
}
internal async Task<TaskCreationRequest[]> GetSubRequestAsync(long id, BusinessType businessType)
internal async Task<TaskCreationRequest[]> GetSubRequestAsync(long id, BusinessType businessType, params long[]? recvUsers)
{
var svcList = await GetServicesAsync(id);
var list = new TaskCreationRequest[svcList.Length];
for (int i = 0; i < svcList.Length; i++)
{
var dto = new TaskCreationRequest { BusinessId = id, BusinessType = businessType };
var dto = new TaskCreationRequest { BusinessId = id, BusinessType = businessType, RecvUserIdList = recvUsers };
var svcName = svcList[i];
if (svcName == "报关")
@ -214,8 +179,6 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
await base.UpdateBusinessAsync(callback);
//todo:海运出口主表信息
}
}

@ -3,6 +3,9 @@ using DS.Module.Core.Extensions;
using DS.Module.Core.Helpers;
using DS.WMS.Core.Fee.Method;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Flow.Method;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.TaskInteraction;
@ -28,6 +31,11 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
/// </summary>
protected ITaskManageService ManagerService { get; private set; }
/// <summary>
/// 工作流服务
/// </summary>
protected Lazy<IClientFlowInstanceService> FlowService { get; private set; }
/// <summary>
/// 初始化
/// </summary>
@ -35,6 +43,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
protected TaskService(IServiceProvider provider) : base(provider)
{
ManagerService = provider.GetRequiredService<ITaskManageService>();
FlowService = new Lazy<IClientFlowInstanceService>(provider.GetRequiredService<IClientFlowInstanceService>());
}
/// <summary>
@ -97,13 +106,20 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
TaskDesp = request.TaskDescription,
TaskUserId = User.UserId,
TaskUserName = User.UserName,
RecvUserId = User.UserId,
RecvUserName = User.UserName,
TaskTenatId = tenatId,
TaskTenatName = tenatName
}
};
if (request.RecvUserIdList == null || request.RecvUserIdList.Length == 0)
{
info.Main.RecvUserInfoList = [new RecvUserInfo { RecvUserId = long.Parse(User.UserId), RecvUserName = User.UserName }];
}
else
{
info.Main.RecvUserInfoList = await GetRecvUsers(request.RecvUserIdList);
}
if (info.Main.TaskTitle.IsNullOrEmpty())
{
var biz = await TenantDb.Queryable<SeaExport>().Select(x => new
@ -133,12 +149,50 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
BusinessType = request.BusinessType,
TaskType = request.TaskType,
TaskStatus = TaskStatusEnum.Create,
RecvUsers = string.Join(',', info.Main.RecvUserInfoList.Select(x => x.RecvUserId)),
CreateBy = long.Parse(User.UserId),
CreateTime = DateTime.Now
};
task.NextType = GetNextType(task);
await TenantDb.Insertable(task).ExecuteCommandAsync();
//待审核,需创建工作流
if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
{
var template = await FindTemplateAsync(AuditType.SeaExport);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
result = FlowService.Value.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = task.BusinessId,
BusinessType = BusinessType.OceanShippingExport,
TemplateId = template.Id
});
//创建并启动实例
if (result.Succeeded)
{
var instance = result.Data as FlowInstance;
task.FlowId = instance.Id;
await TenantDb.Updateable(task).UpdateColumns(x => x.FlowId).ExecuteCommandAsync();
result = FlowService.Value.StartFlowInstance(instance.Id.ToString());
//工作流为会签,需要更新任务接收人
if (result.Succeeded && instance.ActivityType == 0)
{
var marker = FlowInstanceService.GetNextMarker(instance);
await UpdateReceiverAsync(new MakerChangedCallback
{
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
InstanceId = instance.Id,
Type = instance.Type,
NextUserId = long.Parse(marker)
});
}
}
}
result = await OnTaskCreated(task);
if (!result.Succeeded)
return result;
@ -197,7 +251,10 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
await OnTaskStatusChanged(request);
task.TaskStatus = request.TaskStatus;
await TenantDb.Updateable(task).UpdateColumns(x => x.TaskStatus).ExecuteCommandAsync();
if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
task.FlowId = null;
await TenantDb.Updateable(task).UpdateColumns(x => new { x.TaskStatus, x.FlowId }).ExecuteCommandAsync();
if (task.TaskStatus == TaskStatusEnum.Complete)
{
@ -208,7 +265,8 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
{
BusinessId = request.BusinessId,
BusinessType = request.BusinessType,
TaskType = task.NextType.Value
TaskType = task.NextType.Value,
RecvUserIdList = task.RecvUserIdArray,
};
await CreateTaskAsync(req, false);
}
@ -239,6 +297,19 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
return Task.CompletedTask;
}
/// <summary>
/// 通知更新任务接收人
/// </summary>
/// <param name="callback">回调信息</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"><paramref name="callback"/>为null时引发</exception>
public virtual async Task UpdateReceiverAsync(MakerChangedCallback callback)
{
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
}
/// <summary>
/// 审批完成回调更新
/// </summary>
@ -257,6 +328,19 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
TaskType = TaskBaseTypeEnum.WAIT_ORDER_AUDIT,
TaskStatus = TaskStatusEnum.Complete
});
if (callback.FlowStatus == FlowStatusEnum.Reject)
{
//创建审单驳回任务以进行通知
var task = await GetTaskAsync(callback.BusinessId, callback.BusinessType.GetValueOrDefault(), TaskBaseTypeEnum.WAIT_ORDER_AUDIT);
await CreateTaskAsync(new TaskCreationRequest
{
BusinessId = callback.BusinessId,
BusinessType = callback.BusinessType.GetValueOrDefault(),
TaskType = TaskBaseTypeEnum.ORDER_AUDIT_REJECTED,
RecvUserIdList = task.RecvUserIdArray
});
}
}
/// <summary>
@ -288,5 +372,16 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction
return (TaskBaseTypeEnum)currentTypeVal++;
}
/// <summary>
/// 获取任务接收用户列表
/// </summary>
/// <param name="ids">用户ID</param>
/// <returns></returns>
protected internal async Task<List<RecvUserInfo>> GetRecvUsers(params long[] ids)
{
return await Db.Queryable<SysUser>().Where(x => ids.Contains(x.Id)).Select(
x => new RecvUserInfo { RecvUserId = x.Id, RecvUserName = x.UserName }).ToListAsync();
}
}
}

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<NameOfLastUsedPublishProfile>E:\MyCode\Dongsheng8\ds-wms-service\DS.WMS.OpApi\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
<NameOfLastUsedPublishProfile>D:\Source\Repos\DS8\ds-wms-service\DS.WMS.OpApi\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
<Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath>
</PropertyGroup>

Loading…
Cancel
Save