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.

872 lines
33 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.Module.Core.Extensions;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Entity;
using Mapster;
using Newtonsoft.Json;
using SqlSugar;
namespace DS.WMS.Core.Flow.Method;
/// <summary>
/// 工作流服务
/// </summary>
public class FlowInstanceService : ServiceBase, IFlowInstanceService
{
static readonly ApiFox api;
static FlowInstanceService()
{
api = new ApiFox();
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="serviceProvider"></param>
public FlowInstanceService(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
/// <summary>
/// 当工作流类型为会签时,返回首个执行人
/// </summary>
/// <param name="instance">运行实例</param>
/// <returns></returns>
public static string GetNextMarkers(FlowInstance instance)
{
string[] markers = GetMarkers(instance);
if (instance.ActivityType == 0 && markers.Length > 0)
return markers[0];
return string.Empty;
}
/// <summary>
/// 获取当前工作流的所有执行人
/// </summary>
/// <param name="instance">运行实例</param>
/// <returns></returns>
public static string[] GetMarkers(FlowInstance instance)
{
if (instance.IsCompleted)
return [];
return instance.MakerList.Split(',', StringSplitOptions.RemoveEmptyEntries);
}
public DataResult<List<FlowInstanceRes>> GetListByPage(PageRequest request)
{
//序列化查询条件
var whereList = request.GetConditionalModels(Db);
var data = Db.Queryable<FlowInstance>().Where(a => a.MakerList == "1" || a.MakerList.Contains(User.UserId))
.LeftJoin<SysPermission>((a, b) => a.PermissionId == b.Id)
.Select((a, b) => new FlowInstanceRes
{
CreateTime = a.CreateTime,
}, true)
.Where(whereList).ToQueryPage(request.PageCondition);
return data;
}
/// <summary>
/// 确定是否为最后审批人
/// </summary>
/// <param name="taskType">任务类型</param>
/// <param name="bsId">业务ID</param>
/// <param name="bsType">业务类型</param>
/// <returns></returns>
public DataResult<bool> IsLastMarker(TaskBaseTypeEnum taskType, long bsId, BusinessType? bsType)
{
var flow = Db.Queryable<FlowInstance>().Where(x => x.AuditType == taskType && x.BusinessId == bsId && x.BusinessType == bsType && x.FlowStatus == FlowStatusEnum.Running)
.Select(x => new { x.Id, x.MakerList }).First();
bool isLastMarker = default;
if (flow != null && flow.MakerList == User.UserId)
isLastMarker = true;
return DataResult<bool>.Success(isLastMarker);
}
public DataResult EditFlowInstance(FlowInstanceReq req)
{
if (req.Id == 0)
{
return DataResult.Failed("非法请求!", MultiLanguageConst.IllegalRequest);
}
else
{
var info = Db.Queryable<FlowInstance>().Where(x => x.Id == req.Id).First();
if (!(info.FlowStatus == FlowStatusEnum.Draft || info.FlowStatus == FlowStatusEnum.Ready))
{
return DataResult.Failed("只能修改【就绪】和【撤销】状态的流程", MultiLanguageConst.FlowEditOnlyReadyAndCancel);
}
info = req.Adapt(info);
Db.Updateable(info).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommand();
return DataResult.Successed("更新成功!", MultiLanguageConst.DataUpdateSuccess);
}
}
protected virtual FlowInstance? BuildInstance(CreateFlowInstanceReq req)
{
if (string.IsNullOrEmpty(req.TemplateId.ToString()))
return null;
FlowTemplate template = Db.Queryable<FlowTemplate>().First(x => x.Id == req.TemplateId);
return template == null ? null : new FlowInstance
{
CustomName = template.Name,
TemplateId = template.Id,
BusinessId = req.BusinessId,
BusinessType = req.BusinessType,
PermissionId = template.PermissionId,
ColumnView = template.ColumnView,
Content = template.Content,
MarkerNotifyURL = template.MakerNotifyURL,
CallbackURL = template.CallbackURL,
AuditType = template.AuditType
};
}
/// <summary>
/// 创建工作流实例
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public DataResult CreateFlowInstance(CreateFlowInstanceReq req)
{
var instance = BuildInstance(req);
if (instance == null)
return DataResult.Failed("该流程模板已不存在,请重新设计流程!", MultiLanguageConst.FlowTemplateNotExist);
var userName = Db.Queryable<SysUser>().Where(x => x.Id == long.Parse(User.UserId)).Select(x => x.UserName).First();
//创建运行实例
var runtime = CreateRuntimeService(instance);
if (runtime.ShouldSkip)
{
instance.FlowStatus = FlowStatusEnum.Approve;
instance.Note = "已设置为自动跳过工作流执行";
Db.Insertable(instance).ExecuteCommand();
var history1 = new FlowInstanceHistory
{
InstanceId = instance.Id,
Content = "【创建】"
+ userName
+ "创建了一个流程进程【"
+ instance.CustomName + "】",
UserName = userName
};
var history2 = new FlowInstanceHistory
{
InstanceId = instance.Id,
Content = "【审核】"
+ userName
+ "流程条件触发自动审核【"
+ instance.CustomName + "】",
UserName = userName
};
FlowInstanceHistory[] histories = [history1, history2];
Db.Insertable(histories).ExecuteCommand();
if (!string.IsNullOrEmpty(instance.CallbackURL))
Task.Factory.StartNew(() => RunCallbackAsync(instance));
var result = DataResult.Successed("创建工作流实例成功!", instance, MultiLanguageConst.FlowInstanceCreateSuccess);
return result;
}
if (runtime.CurrentNode is { AssigneeType: "user", Users.Count: > 0 })
{
if (!runtime.CurrentNode.Users.Contains(User.UserId))
{
return DataResult.Failed("该工作流指定用户非本人,没有发起审批的权限", MultiLanguageConst.FlowInstanceAssignUser);
}
}
if (runtime.CurrentNode is { AssigneeType: "role", Roles.Count: > 0 })
{
var userRoles = Db.Queryable<SysRoleUser>().Where(x => x.UserId == long.Parse(User.UserId))
.Select(n => n.RoleId.ToString()).ToList();
var intersectRoles = runtime.CurrentNode.Roles.Intersect(userRoles).ToList();
if (intersectRoles.Count == 0)
{
return DataResult.Failed("该工作流指定角色非本人,没有发起审批的权限", MultiLanguageConst.FlowInstanceAssignRole);
}
}
#region 根据运行实例改变当前节点状态
instance.ActivityId = runtime.CurrentNodeId;
instance.ActivityType = runtime.GetNodeType(runtime.StartNodeId);
instance.ActivityName = runtime.CurrentNode.Name;
instance.PreviousId = "";
instance.MakerList = GetCurrentMakers(runtime);
instance.FlowStatus = FlowStatusEnum.Ready;
#endregion 根据运行实例改变当前节点状态
Db.Insertable(instance).ExecuteCommand();
//流程==4为结束执行回调URL
if (runtime.GetNextNodeType() == 4 && !instance.CallbackURL.IsNullOrEmpty())
{
Task.Factory.StartNew(() => RunCallbackAsync(instance));
}
var history = new FlowInstanceHistory
{
InstanceId = instance.Id,
Content = "【创建】"
+ userName
+ "创建了一个流程进程【"
+ instance.CustomName + "】",
UserName = userName
};
Db.Insertable(history).ExecuteCommand();
return DataResult.Successed("创建工作流实例成功!", instance, MultiLanguageConst.FlowInstanceCreateSuccess);
}
/// <summary>
/// 撤销
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public DataResult WithdrawFlowInstance(CancelFlowInstanceReq req)
{
var instance = Db.Queryable<FlowInstance>().First(x => x.Id == req.Id);
if (instance == null)
{
return DataResult.Failed("该工作流不存在!", MultiLanguageConst.FlowInstanceNotExist);
}
if (instance.FlowStatus == FlowStatusEnum.Approve)
{
return DataResult.Failed("该工作流已完成!", MultiLanguageConst.FlowInstanceFinished);
}
instance.ActivityId = "";
//创建运行实例
var wfruntime = CreateRuntimeService(instance);
wfruntime.Cancel();
#region 根据运行实例改变当前节点状态
string startNodeId = wfruntime.StartNodeId; //起始节点
instance.PreviousId = instance.ActivityId;
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.FlowStatus = FlowStatusEnum.Draft;
#endregion 根据运行实例改变当前节点状态
var serializerSettings = new JsonSerializerSettings
{
// 设置为驼峰命名
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
};
instance.Content = JsonConvert.SerializeObject(wfruntime.ToFlowRoot(), Formatting.None, serializerSettings);
Db.Updateable(instance).ExecuteCommand();
var userInfo = Db.Queryable<SysUser>().First(x => x.Id == long.Parse(User.UserId));
var history = new FlowInstanceHistory
{
InstanceId = instance.Id,
Content = $"【撤销】由{userInfo.UserName}撤销,备注:{req.Note}",
Result = -1,
UserName = userInfo.UserName
};
Db.Insertable(history).ExecuteCommand();
return DataResult.Successed("撤销成功!", MultiLanguageConst.FlowInstanceCancelSuccess);
}
/// <summary>
/// 获取流程操作历史
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public DataResult<List<FlowInstanceHistoryRes>> GetFlowInstanceHistoryList(string id)
{
var data = Db.Queryable<FlowInstanceHistory>()
.Where(a => a.InstanceId == long.Parse(id))
.Select<FlowInstanceHistoryRes>()
.ToList();
return DataResult<List<FlowInstanceHistoryRes>>.Success(data);
}
/// <summary>
/// 获取流程操作历史
/// </summary>
/// <param name="bsId">业务ID</param>
/// <param name="bsType">bsType</param>
/// <returns></returns>
public DataResult<List<FlowInstanceHistoryRes>> GetFlowInstanceHistoryList(long bsId, BusinessType? bsType)
{
var data = Db.Queryable<FlowInstanceHistory>()
.Where(x => SqlFunc.Subqueryable<FlowInstance>().Where(y => x.InstanceId == y.Id && y.BusinessId == bsId)
.WhereIF(bsType.HasValue, y => y.BusinessType == bsType.Value)
.Any())
.Select<FlowInstanceHistoryRes>()
.ToList();
return DataResult<List<FlowInstanceHistoryRes>>.Success(data);
}
/// <summary>
/// 启动
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public DataResult StartFlowInstance(string id)
{
var instance = Db.Queryable<FlowInstance>().First(x => x.Id == long.Parse(id));
if (instance == null)
{
return DataResult.Failed("该工作流不存在!", MultiLanguageConst.FlowInstanceNotExist);
}
if (instance.FlowStatus == FlowStatusEnum.Approve)
{
return DataResult.Failed("该工作流已完成!", MultiLanguageConst.FlowInstanceFinished);
}
//创建运行实例
var wfruntime = CreateRuntimeService(instance);
#region 根据运行实例改变当前节点状态
instance.ActivityId = wfruntime.NextNodeId;
instance.ActivityType = wfruntime.GetNextNodeType();
instance.ActivityName = wfruntime.NextNode.Name;
instance.PreviousId = wfruntime.CurrentNodeId;
instance.MakerList = wfruntime.GetNextNodeType() != 4 ? GetNextMakers(wfruntime) : "1";
instance.FlowStatus = (wfruntime.GetNextNodeType() == 4 ? FlowStatusEnum.Approve : FlowStatusEnum.Running);
#endregion 根据运行实例改变当前节点状态
Db.Updateable(instance).ExecuteCommand();
//流程==4为结束执行回调URL
if (wfruntime.GetNextNodeType() == 4 && !instance.CallbackURL.IsNullOrEmpty())
{
Task.Factory.StartNew(() => RunCallbackAsync(instance));
}
var userInfo = Db.Queryable<SysUser>().First(x => x.Id == long.Parse(User.UserId));
var history = new FlowInstanceHistory
{
InstanceId = instance.Id,
Content = $"【启动】由{userInfo.UserName}启动该流程。",
UserName = userInfo.UserName
};
Db.Insertable(history).ExecuteCommand();
return DataResult.Successed("更新成功!", instance, MultiLanguageConst.FlowInstanceUpdateSuccess);
}
/// <summary>
/// 审核工作流实例
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public async Task<DataResult> AuditAsync(FlowInstanceAuditReq req)
{
var instance = GetFlowInstance(req.Id);
if (instance == null)
{
return DataResult.Failed("该工作流不存在!", MultiLanguageConst.FlowInstanceNotExist);
}
else if (instance.FlowStatus == FlowStatusEnum.Approve)
{
return DataResult.Failed("该工作流已完成!", MultiLanguageConst.FlowInstanceFinished);
}
return await AuditCoreAsync(req.Status, req.AuditNote, instance);
}
/// <summary>
/// 工作流实例审核实现
/// </summary>
/// <param name="status">1=通过2=驳回</param>
/// <param name="auditNote">审核备注</param>
/// <param name="instance"></param>
/// <returns></returns>
protected virtual async Task<DataResult> AuditCoreAsync(int status, string auditNote, FlowInstance instance)
{
ArgumentNullException.ThrowIfNull(instance, nameof(instance));
if (!instance.MakerList.Contains(User.UserId))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.AuditUnauthorization));
var tag = new FlowTag
{
UserName = User.UserName,
UserId = User.UserId,
Description = auditNote,
Taged = status
};
var runtime = CreateRuntimeService(instance);
if (runtime.CurrentNodeId != instance.ActivityId)
return DataResult.Failed("该工作流审批节点与当前节点不一致!", MultiLanguageConst.FlowInstanceNodeIdConflict);
#region 会签
if (instance.ActivityType == 0) //当前节点是会签节点
{
//会签时的【当前节点】一直是会签开始节点
runtime.MakeTagNode(runtime.CurrentNodeId, tag); //标记审核节点状态
var res = runtime.NodeConfluence(runtime.CurrentNodeId, tag);
if (res == ((int)TagState.No).ToString()) //驳回
{
instance.FlowStatus = FlowStatusEnum.Reject;
if (runtime.NextNodeType == 4)
{
instance.PreviousId = instance.ActivityId;
instance.ActivityId = runtime.NextNodeId;
instance.ActivityType = runtime.NextNodeType;
instance.ActivityName = runtime.NextNode.Name;
instance.MakerList = runtime.NextNodeType == 4 ? string.Empty : GetNextMakers(runtime);
}
}
else if (!string.IsNullOrEmpty(res)) //通过
{
if (runtime.NextNodeType == 5)
{
instance.MakerList = runtime.GetOtherUsers(tag);
}
else
{
instance.PreviousId = instance.ActivityId;
instance.ActivityId = runtime.NextNodeId;
instance.ActivityType = runtime.NextNodeType;
instance.ActivityName = runtime.NextNode.Name;
instance.FlowStatus = runtime.NextNodeType == 4 ? FlowStatusEnum.Approve : FlowStatusEnum.Running;
instance.MakerList = runtime.NextNodeType == 4 ? string.Empty : GetNextMakers(runtime);
}
}
else //继续审批
{
//会签过程中,需要更新用户
instance.MakerList = GetForkNodeMakers(runtime, runtime.CurrentNodeId);
}
var marker = GetNextMarkers(instance);
//获取会签下一执行人,进行通知
if (!string.IsNullOrEmpty(marker) && !instance.MarkerNotifyURL.IsNullOrEmpty())
{
Task.Factory.StartNew(() => NotifyMarkerChangedAsync(status, instance, long.Parse(marker)));
}
}
#endregion 会签
#region 或签
else
{
runtime.MakeTagNode(runtime.CurrentNodeId, tag);
if (tag.Taged == (int)TagState.Ok)
{
instance.PreviousId = instance.ActivityId;
instance.ActivityId = runtime.NextNodeId;
instance.ActivityType = runtime.NextNodeType;
instance.ActivityName = runtime.NextNode.Name;
instance.MakerList = runtime.NextNodeType == 4 ? "1" : GetNextMakers(runtime);
instance.FlowStatus = runtime.NextNodeType == 4 ? FlowStatusEnum.Approve : FlowStatusEnum.Running;
}
else
{
instance.FlowStatus = FlowStatusEnum.Reject; //表示该节点不同意
runtime.NextNodeId = string.Empty;
runtime.NextNodeType = 4;
}
}
#endregion 或签
int nextNodeType = runtime.GetNextNodeType();
await Db.Ado.BeginTranAsync();
try
{
//流程=4为结束执行回调URL
if (runtime.NextNodeType != 5 && (nextNodeType == 4 || nextNodeType == -1))
{
instance.FlowStatus = status == 1 ? FlowStatusEnum.Approve : FlowStatusEnum.Reject;
if (!string.IsNullOrEmpty(instance.CallbackURL))
await RunCallbackAsync(instance);
}
//var serializerSettings = new JsonSerializerSettings
//{
// // 设置为驼峰命名
// ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
//};
//instance.Content = JsonConvert.SerializeObject(runtime.ToFlowRoot(), Formatting.None, serializerSettings);
instance.Note = auditNote;
await Db.Updateable(instance).ExecuteCommandAsync();
var userId = long.Parse(User.UserId);
var userInfo = Db.Queryable<SysUser>().Where(x => x.Id == userId).Select(x => new { x.Id, x.UserName }).First();
var history = new FlowInstanceHistory
{
InstanceId = instance.Id,
Content = "【" + runtime.CurrentNode.Name
+ "】【" + DateTime.Now.ToString("yyyy-MM-dd HH:mm")
+ "】" + (tag.Taged == 1 ? "同意" : "不同意") + ",备注:"
+ tag.Description,
UserName = userInfo?.UserName,
Result = status,
Note = auditNote
};
await Db.Insertable(history).ExecuteCommandAsync();
await Db.Ado.CommitTranAsync();
return DataResult.Successed("审核成功!", MultiLanguageConst.FlowInstanceAuditSuccess);
}
catch (Exception ex)
{
await Db.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.Failed(ex.Message, nameof(MultiLanguageConst.Operation_Failed));
}
}
/// <summary>
/// 运行执行人变更回调
/// </summary>
/// <param name="status">审批结果</param>
/// <param name="instance">运行实例</param>
/// <param name="nextUserId">下一执行人ID</param>
/// <returns></returns>
protected virtual async Task NotifyMarkerChangedAsync(int status, FlowInstance instance, params long[] nextUserId)
{
ArgumentNullException.ThrowIfNull(instance, nameof(instance));
//请求参数设置
var callback = new MarkerChangedCallback
{
InstanceId = instance.Id,
BusinessId = instance.BusinessId,
BusinessType = instance.BusinessType,
AuditType = instance.AuditType,
Status = status == 1 ? FlowStatusEnum.Approve : FlowStatusEnum.Reject,
NextUserId = nextUserId
};
if (api.DefaultHeaders.Contains("Authorization"))
api.DefaultHeaders.Remove("Authorization");
api.DefaultHeaders.Add("Authorization", "Bearer " + User.GetToken());
await api.PostAsync<DataResult>(instance.MarkerNotifyURL, callback);
}
/// <summary>
/// 对指定的回调URL发起异步请求
/// </summary>
/// <param name="instance">运行实例</param>
protected virtual async Task RunCallbackAsync(FlowInstance instance)
{
ArgumentNullException.ThrowIfNull(instance, nameof(instance));
if (instance.CallbackURL.IsNullOrEmpty())
return;
//请求参数设置
var callback = new FlowCallback
{
InstanceId = instance.Id,
BusinessId = instance.BusinessId,
BusinessType = instance.BusinessType,
AuditType = instance.AuditType,
FlowStatus = instance.FlowStatus,
RejectReason = instance.Note
};
if (api.DefaultHeaders.Contains("Authorization"))
api.DefaultHeaders.Remove("Authorization");
api.DefaultHeaders.Add("Authorization", "Bearer " + User.GetToken());
try
{
var result = await api.PostAsync<DataResult>(instance.CallbackURL, callback);
if (result.Succeeded)
{
//更新回调执行标识
instance.IsCallbackExecuted = true;
await Db.Updateable(instance).UpdateColumns(x => x.IsCallbackExecuted).ExecuteCommandAsync();
}
else
{
await new ApplicationException($"访问回调URL{instance.CallbackURL} 时返回了错误:" + result.Message).LogAsync(Db);
}
}
catch (Exception ex)
{
await ex.LogAsync(Db);
}
}
/// <summary>
/// 运行回调更新
/// </summary>
/// <param name="taskType">审核类型</param>
/// <param name="bsId">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <param name="callbackURL">指定的回调URL</param>
/// <returns></returns>
public async Task<DataResult> RunCallbackAsync(TaskBaseTypeEnum taskType,
long bsId, BusinessType? businessType = null,
string? callbackURL = null)
{
var instance = await Db.Queryable<FlowInstance>().Where(x => x.AuditType == taskType && x.BusinessId == bsId)
.WhereIF(businessType.HasValue, x => x.BusinessType == businessType)
.InnerJoin<FlowTemplateTenant>((f, ft) => f.TemplateId == ft.Id).Select((f, ft) => new FlowInstance
{
BusinessId = f.BusinessId,
BusinessType = f.BusinessType,
CallbackURL = ft.CallbackURL,
MarkerNotifyURL = ft.MarkerNotifyURL,
FlowStatus = f.FlowStatus,
Id = f.Id,
AuditType = ft.AuditType
}).OrderByDescending(f => f.CreateTime).FirstAsync();
if (instance == null)
return DataResult.FailedWithDesc(MultiLanguageConst.EmptyData);
if (!string.IsNullOrEmpty(callbackURL))
instance.CallbackURL = callbackURL;
await RunCallbackAsync(instance);
return DataResult.Success;
}
/// <summary>
/// 获取运行实例信息
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public FlowInstance GetFlowInstance(long id)
{
return Db.Queryable<FlowInstance>().Where(x => x.Id == id)
.InnerJoin<FlowTemplateTenant>((f, ft) => f.TemplateId == ft.Id).Select((f, ft) => new FlowInstance
{
ActivityId = f.ActivityId,
ActivityName = f.ActivityName,
ActivityType = f.ActivityType,
BusinessId = f.BusinessId,
BusinessType = f.BusinessType,
CallbackURL = ft.CallbackURL,
MarkerNotifyURL = ft.MarkerNotifyURL,
ColumnView = f.ColumnView,
Content = f.Content,
FlowStatus = f.FlowStatus,
Id = f.Id,
MakerList = f.MakerList,
PreviousId = f.PreviousId,
PermissionId = f.PermissionId,
AuditType = ft.AuditType
}).First();
}
protected virtual FlowRuntime CreateRuntimeService(FlowInstance instance)
{
return new FlowRuntime(instance, Db, null);
}
public DataResult<FlowInstanceRes> GetFlowInstanceInfo(string id)
{
var data = Db.Queryable<FlowInstance>()
// .LeftJoin<SysPermission>((a, b) => a.PermissionId == b.Id)
.Where(a => a.Id == long.Parse(id))
.Select<FlowInstanceRes>()
.First();
return DataResult<FlowInstanceRes>.Success(data);
}
/// <summary>
/// 寻找下一步的执行人
/// 一般用于本节点审核完成后,修改流程实例的当前执行人,可以做到通知等功能
/// </summary>
/// <returns></returns>
protected string GetCurrentMakers(FlowRuntime wfruntime, CreateFlowInstanceReq request = null)
{
string makerList = "";
if (wfruntime.NextNodeId == "-1")
throw new ApplicationException("无法寻找到下一个节点");
if (wfruntime.CurrentNodeType == 0) //如果是会签节点
{
makerList = GetForkNodeMakers(wfruntime, wfruntime.NextNodeId);
}
else if (wfruntime.CurrentNode.AssigneeType == "role")
{
var users = Db.Queryable<SysRoleUser>().Where(x =>
wfruntime.CurrentNode.Roles.Contains(x.RoleId.ToString()))
.Select(x => x.UserId).Distinct().ToList();
makerList = string.Join(',', users);
}
else if (wfruntime.CurrentNode.AssigneeType == "user")
{
makerList = string.Join(",", wfruntime.CurrentNode.Users);
}
else if (wfruntime.CurrentNode.AssigneeType == FlowChild.Dynamic)
{
makerList = GetDynamicMarkers(wfruntime.CurrentNode, wfruntime);
}
else
{
makerList = GetNodeMarkers(wfruntime.CurrentNode);
if (string.IsNullOrEmpty(makerList))
{
throw (new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!"));
}
}
return makerList;
}
/// <summary>
/// 寻找下一步的执行人
/// 一般用于本节点审核完成后,修改流程实例的当前执行人,可以做到通知等功能
/// </summary>
/// <returns></returns>
protected string GetNextMakers(FlowRuntime wfruntime, CreateFlowInstanceReq request = null)
{
string makerList = "";
if (wfruntime.NextNodeId == "-1")
throw new ApplicationException("无法寻找到下一个节点");
if (wfruntime.NextNode.AssigneeType == "role")
{
var users = Db.Queryable<SysRoleUser>().Where(x =>
wfruntime.NextNode.Roles.Contains(x.RoleId.ToString()))
.Select(x => x.UserId).Distinct().ToList();
makerList = string.Join(",", users);
}
else if (wfruntime.NextNode.AssigneeType == "user")
{
makerList = string.Join(",", wfruntime.NextNode.Users);
}
else if (wfruntime.NextNode.AssigneeType == FlowChild.Dynamic)
{
makerList = GetDynamicMarkers(wfruntime.NextNode, wfruntime);
}
else
{
makerList = GetNodeMarkers(wfruntime.NextNode);
if (string.IsNullOrEmpty(makerList))
{
throw new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!");
}
}
return makerList;
}
/// <summary>
/// 获取会签开始节点的所有可执行者
/// </summary>
/// <param name="forkNodeId">会签开始节点</param>
/// <returns></returns>
protected virtual string GetForkNodeMakers(FlowRuntime wfruntime, string forkNodeId)
{
string makerList = "";
var nextNode = wfruntime.NextNode;
var nextConditionNodeId = wfruntime.GetNextConditionNodeId(nextNode);
var nextConditionNode = wfruntime.ChildNodes.First(x => x.Id == nextConditionNodeId);
if (nextConditionNode.AssigneeType == "role")
{
var users = Db.Queryable<SysRoleUser>().Where(x =>
nextConditionNode.Roles.Contains(x.RoleId.ToString()))
.Select(x => x.UserId).Distinct().ToList();
makerList = string.Join(",", users);
}
else if (nextConditionNode.AssigneeType == "user")
{
makerList = string.Join(",", nextConditionNode.Users);
}
else if (nextConditionNode.AssigneeType == FlowChild.Dynamic)
{
makerList = GetDynamicMarkers(nextConditionNode, wfruntime);
}
return makerList;
}
/// <summary>
/// 寻找该节点执行人
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected string GetNodeMarkers(FlowChild node, string flowinstanceCreateUserId = "")
{
string makerList = "";
if (node.Type == FlowChild.START && (!string.IsNullOrEmpty(flowinstanceCreateUserId))) //如果是开始节点,通常情况下是驳回到开始了
{
makerList = flowinstanceCreateUserId;
}
else if (node.AssigneeType != null)
{
if (node.AssigneeType == "role")
{
var users = Db.Queryable<SysRoleUser>().Where(x =>
node.Roles.Contains(x.RoleId.ToString()))
.Select(x => x.UserId).Distinct().ToList();
makerList = string.Join(",", users);
}
else if (node.AssigneeType == "user")
{
makerList = node.Users.ToString();
}
}
else //如果没有设置节点信息,默认所有人都可以审核
{
makerList = "1";
}
return makerList;
}
//获取动态节点的执行人
internal string GetDynamicMarkers(FlowChild flowNode, FlowRuntime runtime)
{
if (flowNode == null || string.IsNullOrEmpty(flowNode.MarkerSQLText) || runtime == null)
return string.Empty;
List<string> markers = [];
using (var reader = TenantDb.Ado.GetDataReader(flowNode.MarkerSQLText, new SugarParameter($"@{nameof(BaseModel<long>.Id)}", runtime.BusinessId)))
{
while (reader.Read())
markers.Add(reader.GetString(0));
}
string markerList = string.Join(",", markers);
if (string.IsNullOrEmpty(markerList))
throw new ApplicationException("未能根据动态节点设置的查询语句获取工作流执行人,请检查模板配置");
Db.Updateable<FlowInstance>()
.SetColumns(x => x.MakerList == markerList).Where(x => x.Id == runtime.InstanceId)
.ExecuteCommand();
return markerList;
}
}