Workflow.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. using Hotline.FlowEngine.Definitions;
  2. using Hotline.Orders;
  3. using Hotline.Settings;
  4. using Hotline.Share.Dtos;
  5. using Hotline.Share.Dtos.FlowEngine;
  6. using Hotline.Share.Enums.FlowEngine;
  7. using Hotline.Share.Enums.Order;
  8. using Hotline.Share.Enums.Settings;
  9. using SqlSugar;
  10. using System.ComponentModel;
  11. using XF.Domain.Entities;
  12. using XF.Domain.Exceptions;
  13. using XF.Domain.Extensions;
  14. using XF.Domain.Repository;
  15. namespace Hotline.FlowEngine.Workflows;
  16. public partial class Workflow : CreationEntity
  17. {
  18. public string DefinitionId { get; set; }
  19. /// <summary>
  20. /// 流程类型
  21. /// </summary>
  22. public EFlowType FlowType { get; set; }
  23. /// <summary>
  24. /// 审核结果
  25. /// </summary>
  26. public EReviewResult ReviewResult { get; set; }
  27. #region 业务模块(冗余)
  28. public string? ModuleId { get; set; }
  29. public string? ModuleName { get; set; }
  30. public string? ModuleCode { get; set; }
  31. #endregion
  32. /// <summary>
  33. /// 流程标题
  34. /// </summary>
  35. [SugarColumn(ColumnDataType = "varchar(2000)")]
  36. public string Title { get; set; }
  37. /// <summary>
  38. /// end节点办理完成时间
  39. /// </summary>
  40. public DateTime? EndTime { get; set; }
  41. /// <summary>
  42. /// 流程状态
  43. /// </summary>
  44. public EWorkflowStatus Status { get; set; }
  45. #region 实际办理信息(节点,部门,意见)
  46. /// <summary>
  47. /// 实际办理节点code(会签状态此字段保存最外层会签发起节点code)
  48. /// </summary>
  49. public string? ActualHandleStepCode { get; set; }
  50. /// <summary>
  51. /// 实际办理节点名称(会签状态此字段保存最外层会签发起节点名称)
  52. /// </summary>
  53. public string? ActualHandleStepName { get; set; }
  54. /// <summary>
  55. /// 实际办理节点id
  56. /// </summary>
  57. public string? ActualHandleStepId { get; set; }
  58. /// <summary>
  59. /// 到达实际办理节点时间(stepBox创建时间)
  60. /// </summary>
  61. public DateTime? ActualHandleStepCreateTime { get; set; }
  62. /// <summary>
  63. /// 实际办理节点签收时间
  64. /// </summary>
  65. public DateTime? ActualHandleStepAcceptTime { get; set; }
  66. /// <summary>
  67. /// 实际办理时间
  68. /// </summary>
  69. public DateTime? ActualHandleTime { get; set; }
  70. /// <summary>
  71. /// 实际办理人id
  72. /// </summary>
  73. public string? ActualHandlerId { get; set; }
  74. /// <summary>
  75. /// 实际办理人名称
  76. /// </summary>
  77. public string? ActualHandlerName { get; set; }
  78. /// <summary>
  79. /// 实际办理部门名称
  80. /// </summary>
  81. public string? ActualHandleOrgName { get; set; }
  82. /// <summary>
  83. /// 实际办理部门编码
  84. /// </summary>
  85. public string? ActualHandleOrgCode { get; set; }
  86. /// <summary>
  87. /// 实际办理部门等级
  88. /// </summary>
  89. public int? ActualHandleOrgLevel { get; set; }
  90. /// <summary>
  91. /// 实际办理部门行政区划编码
  92. /// </summary>
  93. public string? ActualHandleOrgAreaCode { get; set; }
  94. /// <summary>
  95. /// 实际办理部门行政区划名称
  96. /// </summary>
  97. public string? ActualHandleOrgAreaName { get; set; }
  98. /// <summary>
  99. /// 实际办理意见(办理中...or 最终办理意见)
  100. /// </summary>
  101. [SugarColumn(Length = 8000)]
  102. public string ActualOpinion { get; set; } = "办理中...";
  103. ///// <summary>
  104. ///// 真实办理人姓名(手动填写)
  105. ///// </summary>
  106. //public string? RealHandlerName { get; set; }
  107. ///// <summary>
  108. ///// 真实办理人电话(手动填写)
  109. ///// </summary>
  110. //public string? RealHandlerPhone { get; set; }
  111. ///// <summary>
  112. ///// 沟通方式(手动填写)
  113. ///// </summary>
  114. //public ERealCommunicationMode? RealCommunicationMode { get; set; }
  115. ///// <summary>
  116. ///// 沟通时间(手动填写)
  117. ///// </summary>
  118. //public DateTime? RealCommunicationTime { get; set; }
  119. ///// <summary>
  120. ///// 沟通地点(手动填写)
  121. ///// </summary>
  122. //public string? RealCommunicationAddress { get; set; }
  123. ///// <summary>
  124. ///// 已与市民沟通
  125. ///// </summary>
  126. //public bool? RealIsContacted { get; set; }
  127. ///// <summary>
  128. ///// 已与市民现场沟通
  129. ///// </summary>
  130. //public bool? RealContactLocale { get; set; }
  131. #endregion
  132. #region 当前办理节点信息(指派时赋值)
  133. public string? CurrentStepId { get; set; }
  134. /// <summary>
  135. /// 当前办理节点code(非会签:当前被指派节点,会签:会签发起节点)
  136. /// </summary>
  137. public string? CurrentStepCode { get; set; }
  138. /// <summary>
  139. /// 当前节点名称
  140. /// </summary>
  141. public string? CurrentStepName { get; set; }
  142. /// <summary>
  143. /// 到达当前节点时间
  144. /// </summary>
  145. public DateTime? CurrentStepCreateTime { get; set; }
  146. /// <summary>
  147. /// 当前办理节点签收时间
  148. /// </summary>
  149. public DateTime? CurrentStepAcceptTime { get; set; }
  150. /// <summary>
  151. /// 当前办理时间
  152. /// </summary>
  153. public DateTime? CurrentHandleTime { get; set; }
  154. /// <summary>
  155. /// 当前办理人id
  156. /// </summary>
  157. public string? CurrentHandlerId { get; set; }
  158. /// <summary>
  159. /// 当前办理人名称
  160. /// </summary>
  161. public string? CurrentHandlerName { get; set; }
  162. /// <summary>
  163. /// 当前办理部门名称
  164. /// </summary>
  165. public string? CurrentHandleOrgName { get; set; }
  166. /// <summary>
  167. /// 当前办理部门编码
  168. /// </summary>
  169. public string? CurrentHandleOrgId { get; set; }
  170. /// <summary>
  171. /// 当前办理部门等级
  172. /// </summary>
  173. public int? CurrentHandleOrgLevel { get; set; }
  174. /// <summary>
  175. /// 当前办理部门行政区划编码
  176. /// </summary>
  177. public string? CurrentHandleOrgAreaCode { get; set; }
  178. /// <summary>
  179. /// 当前办理部门行政区划名称
  180. /// </summary>
  181. public string? CurrentHandleOrgAreaName { get; set; }
  182. #endregion
  183. #region 会签
  184. /// <summary>
  185. /// 会签类型
  186. /// </summary>
  187. public ECounterSignType? CounterSignType { get; set; }
  188. /// <summary>
  189. /// 当前会签办理节点Id,嵌套会签为最外层会签办理节点Id
  190. /// </summary>
  191. public string? TopCountersignStepId { get; set; }
  192. /// <summary>
  193. /// 流程是否处于会签中(实时)
  194. /// </summary>
  195. public bool IsInCountersign { get; set; }
  196. #endregion
  197. // /// <summary>
  198. // /// 办结时长(分钟)
  199. // /// 办结时间-交办时间
  200. // /// </summary>
  201. // public double HandleDuration { get; set; }
  202. //
  203. // /// <summary>
  204. // /// 办结工作日时长
  205. // /// </summary>
  206. // public double HandleDurationWorkday { get; set; }
  207. /// <summary>
  208. /// 全流程时长(秒)
  209. /// 归档时间-创建时间
  210. /// </summary>
  211. public double AllDuration { get; set; }
  212. /// <summary>
  213. /// 外部业务唯一标识
  214. /// </summary>
  215. public string ExternalId { get; set; }
  216. #region 当前办理对象
  217. /// <summary>
  218. /// 办理人id
  219. /// </summary>
  220. [SugarColumn(ColumnDataType = "json", IsJson = true)]
  221. public List<HandlerGroupItem> HandlerUsers { get; set; } = new();
  222. /// <summary>
  223. /// 办理部门id
  224. /// </summary>
  225. [SugarColumn(ColumnDataType = "json", IsJson = true)]
  226. public List<HandlerGroupItem> HandlerOrgs { get; set; } = new();
  227. #endregion
  228. #region 流经对象
  229. /// <summary>
  230. /// 流经部门
  231. /// </summary>
  232. [SugarColumn(ColumnDataType = "json", IsJson = true)]
  233. public List<string> FlowedOrgIds { get; set; } = new();
  234. /// <summary>
  235. /// 流经办理人
  236. /// </summary>
  237. [SugarColumn(ColumnDataType = "json", IsJson = true)]
  238. public List<string> FlowedUserIds { get; set; } = new();
  239. #endregion
  240. #region 会签实际办理对象
  241. [SugarColumn(ColumnDataType = "json", IsJson = true)]
  242. public List<string>? CsActualHandleOrgIds { get; set; }
  243. [SugarColumn(ColumnDataType = "json", IsJson = true)]
  244. public List<string>? CsActualHandleUserIds { get; set; }
  245. #endregion
  246. #region 一级部门
  247. /// <summary>
  248. /// 一级部门code
  249. /// </summary>
  250. public string? OrgLevelOneCode { get; set; }
  251. /// <summary>
  252. /// 一级部门名称
  253. /// </summary>
  254. public string? OrgLevelOneName { get; set; }
  255. #endregion
  256. #region 受理人(开启流程的话务员)
  257. /// <summary>
  258. /// 受理人id
  259. /// </summary>
  260. public string? AcceptorId { get; set; }
  261. /// <summary>
  262. /// 受理人名称
  263. /// </summary>
  264. public string? AcceptorName { get; set; }
  265. /// <summary>
  266. /// 受理人工号
  267. /// </summary>
  268. public string? AcceptorStaffNo { get; set; }
  269. /// <summary>
  270. /// 受理人部门编码
  271. /// </summary>
  272. public string? AcceptorOrgId { get; set; }
  273. /// <summary>
  274. /// 受理人部门名称
  275. /// </summary>
  276. public string? AcceptorOrgName { get; set; }
  277. /// <summary>
  278. /// 受理人部门行政区划编码
  279. /// </summary>
  280. public string? AcceptorOrgAreaCode { get; set; }
  281. /// <summary>
  282. /// 受理人部门行政区划名称
  283. /// </summary>
  284. public string? AcceptorOrgAreaName { get; set; }
  285. #endregion
  286. }
  287. public partial class Workflow
  288. {
  289. [Navigate(NavigateType.OneToOne, nameof(DefinitionId))]
  290. public WorkflowDefinition WorkflowDefinition { get; set; }
  291. // /// <summary>
  292. // /// 补充信息
  293. // /// </summary>
  294. // [Navigate(NavigateType.OneToMany, nameof(WorkflowSupplement.WorkflowId))]
  295. // public List<WorkflowSupplement> Supplements { get; set; }
  296. /// <summary>
  297. /// 会签
  298. /// </summary>
  299. [Navigate(NavigateType.OneToMany, nameof(WorkflowCountersign.WorkflowId))]
  300. public List<WorkflowCountersign> Countersigns { get; set; }
  301. /// <summary>
  302. /// 主节点,依据流转进度动态生成或删除
  303. /// </summary>
  304. //[SugarColumn(IsIgnore = true)]
  305. [Navigate(NavigateType.OneToMany, nameof(WorkflowStep.WorkflowId))]
  306. public List<WorkflowStep> Steps { get; set; }
  307. /// <summary>
  308. /// 流转记录
  309. /// </summary>
  310. //[SugarColumn(IsIgnore = true)]
  311. [Navigate(NavigateType.OneToMany, nameof(WorkflowTrace.WorkflowId))]
  312. public List<WorkflowTrace> Traces { get; set; } = new();
  313. #region Method
  314. /// <summary>
  315. /// 流程结束
  316. /// </summary>
  317. public void Complete(WorkflowStep endStep, EReviewResult reviewResult = EReviewResult.Unknown)
  318. {
  319. //if (FlowType is EFlowType.Review && !reviewResult.HasValue)
  320. // throw new UserFriendlyException("无审核结果");
  321. Status = EWorkflowStatus.Completed;
  322. EndTime = DateTime.Now;
  323. if (FlowType is EFlowType.Review && ReviewResult is EReviewResult.Unknown)
  324. ReviewResult = reviewResult;
  325. //ClearHandlers();
  326. SetAllDuration();
  327. UpdateActualOption();
  328. }
  329. public void Terminate(string opinion)
  330. {
  331. Status = EWorkflowStatus.Terminated;
  332. EndTime = DateTime.Now;
  333. ActualOpinion = opinion;
  334. //ClearHandlers();
  335. }
  336. /// <summary>
  337. /// 归档时为最终办理意见赋值
  338. /// </summary>
  339. public void UpdateActualOption()
  340. {
  341. if (FlowType is EFlowType.Review) return;
  342. WorkflowStep? step;
  343. if (Steps.Count == 2
  344. && Steps.Exists(d => d.StepType == EStepType.Start)
  345. && Steps.Exists(d => d.StepType == EStepType.End))
  346. {
  347. step = Steps.FirstOrDefault(d => d.StepType == EStepType.Start);
  348. }
  349. else
  350. {
  351. step = Steps.FirstOrDefault(d => d.Id == ActualHandleStepId);
  352. }
  353. if (step is null)
  354. throw new UserFriendlyException($"未查询到对应实际办理子节点,workflowId: {Id}");
  355. ActualOpinion = step.Opinion;
  356. ActualHandleStepAcceptTime = step.AcceptTime;
  357. }
  358. ///// <summary>
  359. ///// 更新workflow中实际办理节点数据(节点,时间,部门)
  360. ///// </summary>
  361. //public void UpdateWorkflowActualHandleInfo(WorkflowStep currentStep,
  362. // string actualHandlerId, string? actualHandlerName,
  363. // string actualHandleOrgCode, string? actualHandleOrgName,
  364. // string? actualHandleOrgAreaCode, string? actualHandleOrgAreaName,
  365. // int currentHandlerOrgLevel)
  366. //{
  367. // /*
  368. // a.会签中:记录顶级会签发起节点, 会签结束前不更新。会签结束后再发起会签才会记录下一次会签的顶级发起节点
  369. // b.非会签中,记录当前节点
  370. // */
  371. // if (currentStep.IsInCountersign()) return;
  372. // if (currentStep.StepType is EStepType.Summary or EStepType.End) return;
  373. // ActualHandle(currentStep,
  374. // actualHandlerId, actualHandlerName,
  375. // actualHandleOrgCode, actualHandleOrgName,
  376. // actualHandleOrgAreaCode, actualHandleOrgAreaName);
  377. // //SetHandleDuration();
  378. // //实际办理部门为一级部门时记录
  379. // if (currentHandlerOrgLevel == 1)
  380. // UpdateLevelOneOrg(actualHandleOrgCode, actualHandleOrgName);
  381. //}
  382. /// <summary>
  383. /// 指派、未办理时调用
  384. /// </summary>
  385. public void UpdateActualStepWhenAssign(WorkflowStep nextStep, FlowStepHandler nextStepHandler)
  386. {
  387. ResetActualStep();
  388. ActualHandleStepId = nextStep.Id;
  389. ActualHandleStepCode = nextStep.Code;
  390. ActualHandleStepName = nextStep.Name;
  391. ActualHandleStepCreateTime = nextStep.CreationTime;
  392. ActualHandlerId = nextStepHandler.UserId;
  393. ActualHandlerName = nextStepHandler.Username;
  394. ActualHandleOrgCode = nextStepHandler.OrgId;
  395. ActualHandleOrgName = nextStepHandler.OrgName;
  396. if (!string.IsNullOrEmpty(ActualHandleOrgCode))
  397. ActualHandleOrgLevel = ActualHandleOrgCode.CalcOrgLevel();
  398. //实际办理部门为一级部门时记录
  399. if (ActualHandleOrgLevel.HasValue && ActualHandleOrgLevel == 1)
  400. UpdateLevelOneOrg(ActualHandleOrgCode, ActualHandleOrgName);
  401. }
  402. /// <summary>
  403. /// 办理时调用
  404. /// </summary>
  405. public void UpdateActualStepWhenHandle(
  406. WorkflowStep step,
  407. string? handleOrgAreaCode,
  408. string? handleOrgAreaName,
  409. int handlerOrgLevel)
  410. {
  411. //ActualHandleStepAcceptTime = null;
  412. ActualHandleTime = step.HandleTime;
  413. ActualHandleOrgAreaCode = handleOrgAreaCode;
  414. ActualHandleOrgAreaName = handleOrgAreaName;
  415. ActualHandleOrgLevel = handlerOrgLevel;
  416. //坐席->派单存在不选办理对象的场景,所以要补赋值
  417. ActualHandleStepId = step.Id;
  418. ActualHandleStepCode = step.Code;
  419. ActualHandleStepName = step.Name;
  420. ActualHandleStepCreateTime = step.CreationTime;
  421. ActualHandlerId = step.HandlerId;
  422. ActualHandlerName = step.HandlerName;
  423. ActualHandleOrgCode = step.HandlerOrgId;
  424. ActualHandleOrgName = step.HandlerOrgName;
  425. }
  426. /// <summary>
  427. /// 指派、未办理时调用
  428. /// </summary>
  429. public void UpdateCurrentStepWhenAssign(WorkflowStep nextStep, FlowStepHandler nextStepHandler)
  430. {
  431. ResetCurrentStep();
  432. CurrentStepId = nextStep.Id;
  433. CurrentStepCode = nextStep.Code;
  434. CurrentStepName = nextStep.Name;
  435. CurrentStepCreateTime = nextStep.CreationTime;
  436. CurrentHandlerId = nextStepHandler.UserId;
  437. CurrentHandlerName = nextStepHandler.Username;
  438. CurrentHandleOrgId = nextStepHandler.OrgId;
  439. CurrentHandleOrgName = nextStepHandler.OrgName;
  440. if (!string.IsNullOrEmpty(CurrentHandleOrgId))
  441. CurrentHandleOrgLevel = CurrentHandleOrgId.CalcOrgLevel();
  442. // //实际办理部门为一级部门时记录
  443. // if (CurrentHandleOrgLevel.HasValue && CurrentHandleOrgLevel == 1)
  444. // UpdateLevelOneOrg(CurrentHandleOrgId, CurrentHandleOrgName);
  445. }
  446. /// <summary>
  447. /// 办理时调用
  448. /// </summary>
  449. public void UpdateCurrentStepWhenHandle(
  450. WorkflowStep step,
  451. string? handleOrgAreaCode,
  452. string? handleOrgAreaName,
  453. int handlerOrgLevel)
  454. {
  455. //CurrentStepAcceptTime = step.AcceptTime;
  456. CurrentHandleTime = step.HandleTime;
  457. CurrentHandleOrgAreaCode = handleOrgAreaCode;
  458. CurrentHandleOrgAreaName = handleOrgAreaName;
  459. CurrentHandleOrgLevel ??= handlerOrgLevel;
  460. //坐席->派单存在不选办理对象的场景,所以要补赋值
  461. CurrentStepId = step.Id;
  462. CurrentStepCode = step.Code;
  463. CurrentStepName = step.Name;
  464. CurrentStepCreateTime = step.CreationTime;
  465. CurrentHandlerId = step.HandlerId;
  466. CurrentHandlerName = step.HandlerName;
  467. CurrentHandleOrgId = step.HandlerOrgId;
  468. CurrentHandleOrgName = step.HandlerOrgName;
  469. }
  470. private void ResetActualStep()
  471. {
  472. ActualHandleStepCode = null;
  473. ActualHandleStepName = null;
  474. ActualHandleStepId = null;
  475. ActualHandleStepCreateTime = null;
  476. ActualHandleStepAcceptTime = null;
  477. ActualHandleTime = null;
  478. ActualHandlerId = null;
  479. ActualHandlerName = null;
  480. ActualHandleOrgCode = null;
  481. ActualHandleOrgName = null;
  482. ActualHandleOrgAreaCode = null;
  483. ActualHandleOrgAreaName = null;
  484. }
  485. private void ResetCurrentStep()
  486. {
  487. CurrentStepId = null;
  488. CurrentStepCode = null;
  489. CurrentStepName = null;
  490. CurrentStepCreateTime = null;
  491. CurrentStepAcceptTime = null;
  492. CurrentHandleTime = null;
  493. CurrentHandlerId = null;
  494. CurrentHandlerName = null;
  495. CurrentHandleOrgId = null;
  496. CurrentHandleOrgName = null;
  497. CurrentHandleOrgLevel = null;
  498. CurrentHandleOrgAreaCode = null;
  499. CurrentHandleOrgAreaName = null;
  500. }
  501. /// <summary>
  502. /// 检查会签是否结束
  503. /// </summary>
  504. public bool CheckIfCountersignOver()
  505. {
  506. return Countersigns.All(d => d.IsCompleted());
  507. }
  508. /// <summary>
  509. /// 开始会签
  510. /// </summary>
  511. public void StartCountersign(string startCsStepId, ECounterSignType? counterSignType)
  512. {
  513. IsInCountersign = true;
  514. TopCountersignStepId = startCsStepId;
  515. CounterSignType = counterSignType;
  516. }
  517. /// <summary>
  518. /// 结束流程会签状态(保留topStepId创建节点时判断用,直到下次会签开启时更新)
  519. /// </summary>
  520. public void EndCountersign()
  521. {
  522. IsInCountersign = false;
  523. //TopCountersignStepId = null;
  524. }
  525. /// <summary>
  526. /// 重置最终办理意见
  527. /// </summary>
  528. public void ResetOption() => ActualOpinion = "办理中...";
  529. /// <summary>
  530. /// 状态设置为可流转
  531. /// </summary>
  532. public void SetStatusRunnable() => Status = EWorkflowStatus.Runnable;
  533. /// <summary>
  534. /// 重新设置办理人(删除当前待办人/部门),撤回/跳转场景,因当前办理人不是流程指定办理人
  535. /// </summary>
  536. /// <param name="assignType"></param>
  537. /// <param name="handlerObjects"></param>
  538. public void ResetHandlers(EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
  539. {
  540. //ClearHandlers();
  541. //SetHandlers(assignType, handlerObjects);
  542. }
  543. /// <summary>
  544. /// 清除办理对象
  545. /// </summary>
  546. public void ClearHandlers()
  547. {
  548. HandlerOrgs = new List<HandlerGroupItem>();
  549. HandlerUsers = new List<HandlerGroupItem>();
  550. }
  551. /// <summary>
  552. /// 更新当前办理人(待办人或部门),正常流转场景
  553. /// </summary>
  554. public void UpdateHandlers(string handlerId, string handlerOrg, EFlowAssignType assignType,
  555. List<HandlerGroupItem> handlerObjects, bool isCreateNewStep)
  556. {
  557. //RemoveCurrentHandleGroup(handlerId, handlerOrg);
  558. if (isCreateNewStep)
  559. SetHandlers(assignType, handlerObjects);
  560. }
  561. public void UpdateHandlers(List<string> handlers, EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
  562. {
  563. foreach (var handler in handlers)
  564. {
  565. var orgItem = HandlerOrgs.FirstOrDefault(d => d.Key == handler);
  566. if (orgItem != null)
  567. {
  568. HandlerOrgs.RemoveAll(d => d.GroupId == orgItem.GroupId);
  569. }
  570. var userItem = HandlerUsers.FirstOrDefault(d => d.Key == handler);
  571. if (userItem != null)
  572. {
  573. HandlerUsers.RemoveAll(d => d.GroupId == userItem.GroupId);
  574. }
  575. }
  576. SetHandlers(assignType, handlerObjects);
  577. }
  578. private void SetHandlers(EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
  579. {
  580. switch (assignType)
  581. {
  582. case EFlowAssignType.Org:
  583. HandlerOrgs.AddRange(handlerObjects);
  584. HandlerOrgs = HandlerOrgs.Distinct().ToList();
  585. break;
  586. case EFlowAssignType.User:
  587. case EFlowAssignType.Role:
  588. HandlerUsers.AddRange(handlerObjects);
  589. HandlerUsers = HandlerUsers.Distinct().ToList();
  590. break;
  591. default:
  592. throw new ArgumentOutOfRangeException(nameof(assignType), assignType, null);
  593. }
  594. }
  595. /// <summary>
  596. /// 更新当前办理人(逐级退回场景)
  597. /// </summary>
  598. /// <param name="handlerId"></param>
  599. /// <param name="handlerOrg"></param>
  600. /// <param name="prevStep"></param>
  601. public void UpdatePreviousHandlers(string handlerId, string handlerOrg, WorkflowStep prevStep)
  602. {
  603. //RemoveCurrentHandleGroup(handlerId, handlerOrg);
  604. var groupId = Guid.NewGuid().ToString();
  605. var handlerObjects = new HandlerGroupItem
  606. {
  607. GroupId = groupId,
  608. Key = prevStep.HandlerId,
  609. Value = prevStep.HandlerName
  610. };
  611. HandlerUsers.Add(handlerObjects);
  612. HandlerUsers = HandlerUsers.Distinct().ToList();
  613. //switch (prevStep.HandlerType)
  614. //{
  615. // case EHandlerType.OrgLevel:
  616. // case EHandlerType.OrgType:
  617. // case EHandlerType.AssignedOrg:
  618. // HandlerOrgs.AddRange(handlerObjects);
  619. // HandlerOrgs = HandlerOrgs.Distinct().ToList();
  620. // break;
  621. // case EHandlerType.Role:
  622. // case EHandlerType.AssignedUser:
  623. // HandlerUsers.AddRange(handlerObjects);
  624. // HandlerUsers = HandlerUsers.Distinct().ToList();
  625. // break;
  626. // default:
  627. // throw new ArgumentOutOfRangeException();
  628. //}
  629. }
  630. /// <summary>
  631. /// 当前用户是否可以办理该流程
  632. /// </summary>
  633. /// <returns></returns>
  634. public bool IsCanHandle(string userId, string orgId, string[] roleIds)
  635. {
  636. if (Steps is null || !Steps.Any())
  637. throw new UserFriendlyException("未查询节点信息");
  638. return Status is EWorkflowStatus.Runnable &&
  639. //(HandlerUsers.Any(d => d.Key == userId) || HandlerOrgs.Any(d => d.Key == orgCode));
  640. Steps.Any(d => d.IsCanHandle(userId, orgId, roleIds));
  641. }
  642. private void RemoveCurrentHandleGroup(string handlerId, string handlerOrg)
  643. {
  644. if (string.IsNullOrEmpty(handlerId) && string.IsNullOrEmpty(handlerOrg))
  645. throw new UserFriendlyException($"{nameof(RemoveCurrentHandleGroup)}, 办理对象参数为空");
  646. var orgItem = HandlerOrgs.FirstOrDefault(d => d.Key == handlerOrg);
  647. if (orgItem != null)
  648. {
  649. HandlerOrgs.RemoveAll(d => d.GroupId == orgItem.GroupId);
  650. }
  651. var userItem = HandlerUsers.FirstOrDefault(d => d.Key == handlerId);
  652. if (userItem != null)
  653. {
  654. HandlerUsers.RemoveAll(d => d.GroupId == userItem.GroupId);
  655. }
  656. }
  657. public void Assign(EFlowAssignType type, string handler)
  658. {
  659. handler = handler.ToLower();
  660. switch (type)
  661. {
  662. case EFlowAssignType.Org:
  663. var orgCodes = handler.GetHigherOrgIds(true).ToList();
  664. FlowedOrgIds.AddRange(orgCodes);
  665. FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
  666. break;
  667. case EFlowAssignType.User:
  668. case EFlowAssignType.Role:
  669. if (!FlowedUserIds.Exists(d => d == handler))
  670. FlowedUserIds.Add(handler);
  671. break;
  672. default:
  673. throw new ArgumentOutOfRangeException(nameof(type), type, null);
  674. }
  675. }
  676. public void Assign(EFlowAssignType type, IEnumerable<string> handlers)
  677. {
  678. if (!handlers.Any()) return;
  679. FlowedUserIds ??= new();
  680. FlowedOrgIds ??= new();
  681. handlers = handlers.Select(d => d.ToLower());
  682. switch (type)
  683. {
  684. case EFlowAssignType.Org:
  685. var orgCodes = handlers.SelectMany(d => d.GetHigherOrgIds(true)).ToList();
  686. FlowedOrgIds.AddRange(orgCodes);
  687. FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
  688. break;
  689. case EFlowAssignType.User:
  690. case EFlowAssignType.Role:
  691. FlowedUserIds.AddRange(handlers);
  692. FlowedUserIds = FlowedUserIds.Distinct().ToList();
  693. break;
  694. default:
  695. throw new ArgumentOutOfRangeException(nameof(type), type, null);
  696. }
  697. }
  698. /// <summary>
  699. /// 更新受理人信息
  700. /// </summary>
  701. public void UpdateAcceptor(string userId, string? userName, string? staffNo, string orgId, string? orgName)
  702. {
  703. AcceptorId = userId;
  704. AcceptorName = userName;
  705. AcceptorStaffNo = staffNo;
  706. AcceptorOrgId = orgId;
  707. AcceptorOrgName = orgName;
  708. }
  709. /// <summary>
  710. /// 更新一级部门信息(实际办理部门为一级部门时记录)
  711. /// </summary>
  712. public void UpdateLevelOneOrg(string orgId, string? orgName)
  713. {
  714. OrgLevelOneCode = orgId;
  715. OrgLevelOneName = orgName;
  716. }
  717. public void Redo()
  718. {
  719. ResetOption();
  720. Status = EWorkflowStatus.Runnable;
  721. }
  722. public void SetAllDuration()
  723. {
  724. if (!EndTime.HasValue)
  725. throw new ArgumentNullException($"{EndTime} is null");
  726. AllDuration = Math.Round((EndTime - CreationTime).Value.TotalSeconds);
  727. }
  728. public bool IsReviewPass() => FlowType == EFlowType.Review && ReviewResult == EReviewResult.Approval;
  729. public bool IsReviewType() => FlowType == EFlowType.Review;
  730. /// <summary>
  731. /// 查询实际办理节点
  732. /// </summary>
  733. /// <returns></returns>
  734. public WorkflowStep? GetActualStep() => Steps.FirstOrDefault(d => d.Id == ActualHandleStepId);
  735. public void AddCsActualHandler(string userId, string orgId)
  736. {
  737. CsActualHandleUserIds ??= new();
  738. if (CsActualHandleUserIds.All(d => d != userId))
  739. CsActualHandleUserIds.Add(userId);
  740. CsActualHandleOrgIds ??= new();
  741. if (CsActualHandleOrgIds.All(d => d != orgId))
  742. CsActualHandleOrgIds.Add(orgId);
  743. }
  744. public bool IsTopCountersignEndStep(StepBasicEntity step)
  745. {
  746. // if (string.IsNullOrEmpty(TopCountersignStepId))
  747. // throw new UserFriendlyException("该流程当前未开启会签");
  748. return step.IsCountersignEndStep
  749. && !string.IsNullOrEmpty(TopCountersignStepId)
  750. && step.CountersignStartStepId == TopCountersignStepId;
  751. }
  752. #endregion
  753. }
  754. /*
  755. 1. 弃用 workflow, order 上的 handlerUserIds, flowUserIds
  756. 2. 弃用 step, trace 上的handlers
  757. 3. 统一封装创建step, 复制step,指派类型及办理对象开放参数,依据3种策略进行创建
  758. 4. 重构recall,重构recallDto(domain层传入指派信息dto), 取消session传入
  759. */