Workflow.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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 = step.AcceptTime;
  412. ActualHandleTime = step.HandleTime;
  413. ActualHandleOrgAreaCode = handleOrgAreaCode;
  414. ActualHandleOrgAreaName = handleOrgAreaName;
  415. ActualHandleOrgLevel = handlerOrgLevel;
  416. //坐席->派单存在不选办理对象的场景,所以要补赋值
  417. ActualHandlerId = 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. public void UpdateCurrentStepAcceptTime(DateTime acceptTime) => CurrentStepAcceptTime = acceptTime;
  447. public void UpdateActualStepAcceptTime(DateTime acceptTime) => ActualHandleStepAcceptTime = acceptTime;
  448. /// <summary>
  449. /// 办理时调用
  450. /// </summary>
  451. public void UpdateCurrentStepWhenHandle(
  452. WorkflowStep step,
  453. string? handleOrgAreaCode,
  454. string? handleOrgAreaName,
  455. int handlerOrgLevel)
  456. {
  457. //CurrentStepAcceptTime = step.AcceptTime;
  458. CurrentHandleTime = step.HandleTime;
  459. CurrentHandleOrgAreaCode = handleOrgAreaCode;
  460. CurrentHandleOrgAreaName = handleOrgAreaName;
  461. CurrentHandleOrgLevel ??= handlerOrgLevel;
  462. //坐席->派单存在不选办理对象的场景,所以要补赋值
  463. CurrentStepId = step.Id;
  464. CurrentStepCode = step.Code;
  465. CurrentStepName = step.Name;
  466. CurrentStepCreateTime = step.CreationTime;
  467. CurrentHandlerId = step.HandlerId;
  468. CurrentHandlerName = step.HandlerName;
  469. CurrentHandleOrgId = step.HandlerOrgId;
  470. CurrentHandleOrgName = step.HandlerOrgName;
  471. }
  472. private void ResetActualStep()
  473. {
  474. ActualHandleStepCode = null;
  475. ActualHandleStepName = null;
  476. ActualHandleStepId = null;
  477. ActualHandleStepCreateTime = null;
  478. ActualHandleStepAcceptTime = null;
  479. ActualHandleTime = null;
  480. ActualHandlerId = null;
  481. ActualHandlerName = null;
  482. ActualHandleOrgCode = null;
  483. ActualHandleOrgName = null;
  484. ActualHandleOrgAreaCode = null;
  485. ActualHandleOrgAreaName = null;
  486. }
  487. private void ResetCurrentStep()
  488. {
  489. CurrentStepId = null;
  490. CurrentStepCode = null;
  491. CurrentStepName = null;
  492. CurrentStepCreateTime = null;
  493. CurrentStepAcceptTime = null;
  494. CurrentHandleTime = null;
  495. CurrentHandlerId = null;
  496. CurrentHandlerName = null;
  497. CurrentHandleOrgId = null;
  498. CurrentHandleOrgName = null;
  499. CurrentHandleOrgLevel = null;
  500. CurrentHandleOrgAreaCode = null;
  501. CurrentHandleOrgAreaName = null;
  502. }
  503. /// <summary>
  504. /// 检查会签是否结束
  505. /// </summary>
  506. public bool CheckIfCountersignOver()
  507. {
  508. return Countersigns.All(d => d.IsCompleted());
  509. }
  510. /// <summary>
  511. /// 开始会签
  512. /// </summary>
  513. public void StartCountersign(string startCsStepId, ECounterSignType? counterSignType)
  514. {
  515. IsInCountersign = true;
  516. TopCountersignStepId = startCsStepId;
  517. CounterSignType = counterSignType;
  518. }
  519. /// <summary>
  520. /// 结束流程会签状态(保留topStepId创建节点时判断用,直到下次会签开启时更新)
  521. /// </summary>
  522. public void EndCountersign() => IsInCountersign = false;
  523. /// <summary>
  524. /// 重置最终办理意见
  525. /// </summary>
  526. public void ResetOption() => ActualOpinion = "办理中...";
  527. /// <summary>
  528. /// 状态设置为可流转
  529. /// </summary>
  530. public void SetStatusRunnable() => Status = EWorkflowStatus.Runnable;
  531. /// <summary>
  532. /// 重新设置办理人(删除当前待办人/部门),撤回/跳转场景,因当前办理人不是流程指定办理人
  533. /// </summary>
  534. /// <param name="assignType"></param>
  535. /// <param name="handlerObjects"></param>
  536. public void ResetHandlers(EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
  537. {
  538. ClearHandlers();
  539. SetHandlers(assignType, handlerObjects);
  540. }
  541. /// <summary>
  542. /// 清除办理对象
  543. /// </summary>
  544. public void ClearHandlers()
  545. {
  546. HandlerOrgs = new List<HandlerGroupItem>();
  547. HandlerUsers = new List<HandlerGroupItem>();
  548. }
  549. /// <summary>
  550. /// 更新当前办理人(待办人或部门),正常流转场景
  551. /// </summary>
  552. public void UpdateHandlers(string handlerId, string handlerOrg, EFlowAssignType assignType,
  553. List<HandlerGroupItem> handlerObjects, bool isCreateNewStep)
  554. {
  555. RemoveCurrentHandleGroup(handlerId, handlerOrg);
  556. if (isCreateNewStep)
  557. SetHandlers(assignType, handlerObjects);
  558. }
  559. public void UpdateHandlers(List<string> handlers, EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
  560. {
  561. foreach (var handler in handlers)
  562. {
  563. var orgItem = HandlerOrgs.FirstOrDefault(d => d.Key == handler);
  564. if (orgItem != null)
  565. {
  566. HandlerOrgs.RemoveAll(d => d.GroupId == orgItem.GroupId);
  567. }
  568. var userItem = HandlerUsers.FirstOrDefault(d => d.Key == handler);
  569. if (userItem != null)
  570. {
  571. HandlerUsers.RemoveAll(d => d.GroupId == userItem.GroupId);
  572. }
  573. }
  574. SetHandlers(assignType, handlerObjects);
  575. }
  576. private void SetHandlers(EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
  577. {
  578. switch (assignType)
  579. {
  580. case EFlowAssignType.Org:
  581. HandlerOrgs.AddRange(handlerObjects);
  582. HandlerOrgs = HandlerOrgs.Distinct().ToList();
  583. break;
  584. case EFlowAssignType.User:
  585. case EFlowAssignType.Role:
  586. HandlerUsers.AddRange(handlerObjects);
  587. HandlerUsers = HandlerUsers.Distinct().ToList();
  588. break;
  589. default:
  590. throw new ArgumentOutOfRangeException(nameof(assignType), assignType, null);
  591. }
  592. }
  593. /// <summary>
  594. /// 更新当前办理人(逐级退回场景)
  595. /// </summary>
  596. /// <param name="handlerId"></param>
  597. /// <param name="handlerOrg"></param>
  598. /// <param name="prevStep"></param>
  599. public void UpdatePreviousHandlers(string handlerId, string handlerOrg, WorkflowStep prevStep)
  600. {
  601. RemoveCurrentHandleGroup(handlerId, handlerOrg);
  602. var groupId = Guid.NewGuid().ToString();
  603. var handlerObjects = new HandlerGroupItem
  604. {
  605. GroupId = groupId,
  606. Key = prevStep.HandlerId,
  607. Value = prevStep.HandlerName
  608. };
  609. HandlerUsers.Add(handlerObjects);
  610. HandlerUsers = HandlerUsers.Distinct().ToList();
  611. //switch (prevStep.HandlerType)
  612. //{
  613. // case EHandlerType.OrgLevel:
  614. // case EHandlerType.OrgType:
  615. // case EHandlerType.AssignedOrg:
  616. // HandlerOrgs.AddRange(handlerObjects);
  617. // HandlerOrgs = HandlerOrgs.Distinct().ToList();
  618. // break;
  619. // case EHandlerType.Role:
  620. // case EHandlerType.AssignedUser:
  621. // HandlerUsers.AddRange(handlerObjects);
  622. // HandlerUsers = HandlerUsers.Distinct().ToList();
  623. // break;
  624. // default:
  625. // throw new ArgumentOutOfRangeException();
  626. //}
  627. }
  628. /// <summary>
  629. /// 当前用户是否可以办理该流程
  630. /// </summary>
  631. /// <returns></returns>
  632. public bool IsCanHandle(string userId, string orgId, string[] roleIds)
  633. {
  634. if (Steps is null || !Steps.Any())
  635. throw new UserFriendlyException("未查询节点信息");
  636. return Status is EWorkflowStatus.Runnable &&
  637. //(HandlerUsers.Any(d => d.Key == userId) || HandlerOrgs.Any(d => d.Key == orgCode));
  638. Steps.Any(d => d.IsCanHandle(userId, orgId, roleIds));
  639. }
  640. private void RemoveCurrentHandleGroup(string handlerId, string handlerOrg)
  641. {
  642. if (string.IsNullOrEmpty(handlerId) && string.IsNullOrEmpty(handlerOrg))
  643. throw new UserFriendlyException($"{nameof(RemoveCurrentHandleGroup)}, 办理对象参数为空");
  644. var orgItem = HandlerOrgs.FirstOrDefault(d => d.Key == handlerOrg);
  645. if (orgItem != null)
  646. {
  647. HandlerOrgs.RemoveAll(d => d.GroupId == orgItem.GroupId);
  648. }
  649. var userItem = HandlerUsers.FirstOrDefault(d => d.Key == handlerId);
  650. if (userItem != null)
  651. {
  652. HandlerUsers.RemoveAll(d => d.GroupId == userItem.GroupId);
  653. }
  654. }
  655. public void Assign(EFlowAssignType type, string handler)
  656. {
  657. handler = handler.ToLower();
  658. switch (type)
  659. {
  660. case EFlowAssignType.Org:
  661. var orgCodes = handler.GetHigherOrgCodes(true).ToList();
  662. FlowedOrgIds.AddRange(orgCodes);
  663. FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
  664. break;
  665. case EFlowAssignType.User:
  666. case EFlowAssignType.Role:
  667. if (!FlowedUserIds.Exists(d => d == handler))
  668. FlowedUserIds.Add(handler);
  669. break;
  670. default:
  671. throw new ArgumentOutOfRangeException(nameof(type), type, null);
  672. }
  673. }
  674. public void Assign(EFlowAssignType type, IEnumerable<string> handlers)
  675. {
  676. handlers = handlers.Select(d => d.ToLower());
  677. switch (type)
  678. {
  679. case EFlowAssignType.Org:
  680. var orgCodes = handlers.SelectMany(d => d.GetHigherOrgCodes(true)).ToList();
  681. FlowedOrgIds.AddRange(orgCodes);
  682. FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
  683. break;
  684. case EFlowAssignType.User:
  685. case EFlowAssignType.Role:
  686. FlowedUserIds.AddRange(handlers);
  687. FlowedUserIds = FlowedUserIds.Distinct().ToList();
  688. break;
  689. default:
  690. throw new ArgumentOutOfRangeException(nameof(type), type, null);
  691. }
  692. }
  693. /// <summary>
  694. /// 更新受理人信息
  695. /// </summary>
  696. public void UpdateAcceptor(string userId, string? userName, string? staffNo, string orgId, string? orgName)
  697. {
  698. AcceptorId = userId;
  699. AcceptorName = userName;
  700. AcceptorStaffNo = staffNo;
  701. AcceptorOrgId = orgId;
  702. AcceptorOrgName = orgName;
  703. }
  704. /// <summary>
  705. /// 更新一级部门信息(实际办理部门为一级部门时记录)
  706. /// </summary>
  707. public void UpdateLevelOneOrg(string orgId, string? orgName)
  708. {
  709. OrgLevelOneCode = orgId;
  710. OrgLevelOneName = orgName;
  711. }
  712. // public void CenterToOrg(DateTime expiredTime)
  713. // {
  714. // ProcessType = EProcessType.Jiaoban;
  715. // ExpiredTime = expiredTime;
  716. // CenterToOrgTime = DateTime.Now;
  717. // }
  718. //
  719. // public void OrgToCenter(DateTime expiredTime)
  720. // {
  721. // ProcessType = EProcessType.Zhiban;
  722. // ExpiredTime = expiredTime;
  723. // CenterToOrgTime = null;
  724. // }
  725. public void Redo()
  726. {
  727. ResetOption();
  728. Status = EWorkflowStatus.Runnable;
  729. }
  730. public void SetAllDuration()
  731. {
  732. if (!EndTime.HasValue)
  733. throw new ArgumentNullException($"{EndTime} is null");
  734. AllDuration = Math.Round((EndTime - CreationTime).Value.TotalSeconds);
  735. }
  736. public bool IsReviewPass() => FlowType == EFlowType.Review && ReviewResult == EReviewResult.Approval;
  737. public bool IsReviewType() => FlowType == EFlowType.Review;
  738. /// <summary>
  739. /// 查询实际办理节点
  740. /// </summary>
  741. /// <returns></returns>
  742. public WorkflowStep? GetActualStep() => Steps.FirstOrDefault(d => d.Id == ActualHandleStepId);
  743. public void AddCsActualHandler(string userId, string orgId)
  744. {
  745. CsActualHandleUserIds ??= new();
  746. if (CsActualHandleUserIds.All(d => d != userId))
  747. CsActualHandleUserIds.Add(userId);
  748. CsActualHandleOrgIds ??= new();
  749. if (CsActualHandleOrgIds.All(d => d != orgId))
  750. CsActualHandleOrgIds.Add(orgId);
  751. }
  752. public bool IsTopCountersignEndStep(WorkflowStep step)
  753. {
  754. if (string.IsNullOrEmpty(TopCountersignStepId))
  755. throw new UserFriendlyException("该流程当前未开启会签");
  756. return step.IsCountersignEndStep && step.CountersignStartStepId == TopCountersignStepId;
  757. }
  758. #endregion
  759. }