OperatorController.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. package jnpf.flowable.controller;
  2. import cn.hutool.core.collection.CollectionUtil;
  3. import cn.hutool.core.util.ObjectUtil;
  4. import com.google.common.collect.ImmutableList;
  5. import io.swagger.v3.oas.annotations.Operation;
  6. import io.swagger.v3.oas.annotations.tags.Tag;
  7. import jnpf.base.ActionResult;
  8. import jnpf.base.Pagination;
  9. import jnpf.base.controller.SuperController;
  10. import jnpf.base.vo.ListVO;
  11. import jnpf.base.vo.PaginationVO;
  12. import jnpf.constant.MsgCode;
  13. import jnpf.exception.WorkFlowException;
  14. import jnpf.flowable.entity.OperatorEntity;
  15. import jnpf.flowable.entity.RecordEntity;
  16. import jnpf.flowable.entity.TaskEntity;
  17. import jnpf.flowable.enums.*;
  18. import jnpf.flowable.model.candidates.CandidateCheckFo;
  19. import jnpf.flowable.model.candidates.CandidateCheckVo;
  20. import jnpf.flowable.model.candidates.CandidateUserVo;
  21. import jnpf.flowable.model.operator.FlowBatchModel;
  22. import jnpf.flowable.model.operator.OperatorVo;
  23. import jnpf.flowable.model.task.AuditModel;
  24. import jnpf.flowable.model.task.FlowModel;
  25. import jnpf.flowable.model.task.TaskPagination;
  26. import jnpf.flowable.model.templatenode.BackNodeModel;
  27. import jnpf.flowable.model.util.FlowNature;
  28. import jnpf.flowable.service.CirculateService;
  29. import jnpf.flowable.service.OperatorService;
  30. import jnpf.flowable.service.RecordService;
  31. import jnpf.flowable.service.TaskService;
  32. import jnpf.flowable.util.*;
  33. import jnpf.permission.entity.UserEntity;
  34. import jnpf.util.JsonUtil;
  35. import jnpf.util.context.RequestContext;
  36. import jnpf.util.RedisUtil;
  37. import jnpf.util.UserProvider;
  38. import lombok.RequiredArgsConstructor;
  39. import org.springframework.beans.factory.annotation.Autowired;
  40. import org.springframework.web.bind.annotation.*;
  41. import java.util.*;
  42. import java.util.concurrent.TimeUnit;
  43. import java.util.stream.Collectors;
  44. /**
  45. * 类的描述
  46. *
  47. * @author JNPF@YinMai Info. Co., Ltd
  48. * @version 5.0.x
  49. * @since 2024/4/25 14:48
  50. */
  51. @Tag(name = "经办", description = "OperatorController")
  52. @RestController
  53. @RequestMapping("/api/workflow/operator")
  54. @RequiredArgsConstructor
  55. public class OperatorController extends SuperController<OperatorService, OperatorEntity> {
  56. private final OperatorService operatorService;
  57. private final TaskService taskService;
  58. @Autowired
  59. private ServiceUtil serviceUtil;
  60. @Autowired
  61. private RecordService recordService;
  62. @Autowired
  63. private CirculateService circulateService;
  64. @Autowired
  65. private OperatorUtil operatorUtil;
  66. @Autowired
  67. private TaskUtil taskUtil;
  68. @Autowired
  69. private RedisLock redisLock;
  70. /**
  71. * 判断候选人
  72. *
  73. * @param id 经办主键
  74. * @param fo 参数类
  75. */
  76. @Operation(summary = "判断候选人")
  77. @PostMapping("/CandidateNode/{id}")
  78. public ActionResult candidates(@PathVariable("id") String id, @RequestBody CandidateCheckFo fo) throws WorkFlowException {
  79. OperatorEntity info = !ObjectUtil.equals(id, "0") ? operatorService.getInfo(id) : null;
  80. if (info != null) {
  81. operatorUtil.checkOperatorPermission(id);
  82. }
  83. return ActionResult.success(taskService.checkCandidates(id, fo));
  84. }
  85. /**
  86. * 获取候选人
  87. *
  88. * @param fo 参数类
  89. */
  90. @Operation(summary = "获取候选人")
  91. @PostMapping("/CandidateUser/{id}")
  92. public ActionResult candidateUser(@PathVariable("id") String id, @RequestBody CandidateCheckFo fo) throws WorkFlowException {
  93. OperatorEntity info = !ObjectUtil.equals(id, "0") ? operatorService.getInfo(id) : null;
  94. if (info != null) {
  95. operatorUtil.checkOperatorPermission(id);
  96. }
  97. List<CandidateUserVo> candidates = taskService.getCandidateUser(id, fo);
  98. PaginationVO paginationVO = JsonUtil.getJsonToBean(fo, PaginationVO.class);
  99. return ActionResult.page(candidates, paginationVO);
  100. }
  101. /**
  102. * 列表
  103. *
  104. * @param category 列表标识
  105. * @param pagination 参数
  106. */
  107. @Operation(summary = "列表")
  108. @GetMapping("/List/{category}")
  109. public ActionResult list(@PathVariable("category") String category, TaskPagination pagination) {
  110. List<OperatorVo> list = new ArrayList<>();
  111. CategoryEnum categoryEnum = CategoryEnum.getType(category);
  112. pagination.setCategory(categoryEnum.getType());
  113. pagination.setDelegateType(true);
  114. pagination.setSystemId(serviceUtil.getSystemCodeById(RequestContext.getAppCode()));
  115. switch (categoryEnum) {
  116. case Sign: // 待签
  117. case Todo: // 待办
  118. case Doing: // 在办
  119. case BatchDoing: // 批量在办
  120. list = operatorService.getList(pagination);
  121. break;
  122. case Done: // 已办
  123. list = recordService.getList(pagination);
  124. break;
  125. case Circulate: // 抄送
  126. list = circulateService.getList(pagination);
  127. }
  128. List<OperatorVo> vos = new ArrayList<>();
  129. List<UserEntity> userList = serviceUtil.getUserName(list.stream().map(OperatorVo::getCreatorUserId).collect(Collectors.toList()));
  130. for (OperatorVo operatorVo : list) {
  131. OperatorVo vo = JsonUtil.getJsonToBean(operatorVo, OperatorVo.class);
  132. UserEntity userEntity = userList.stream().filter(t -> t.getId().equals(vo.getCreatorUserId())).findFirst().orElse(null);
  133. vo.setCreatorUser(userEntity != null ? userEntity.getRealName() + "/" + userEntity.getAccount() : "");
  134. if (ObjectUtil.equals(operatorVo.getIsProcessing(), 1) && ObjectUtil.equals(operatorVo.getStatus(), OperatorStateEnum.Transfer.getCode())) {
  135. vo.setStatus(OperatorStateEnum.TransferProcessing.getCode());
  136. }
  137. vos.add(vo);
  138. }
  139. PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
  140. return ActionResult.page(vos, paginationVO);
  141. }
  142. /**
  143. * 签收或退签
  144. *
  145. * @param flowModel 参数类,ids 主键集合、type 0 签收 1 退签
  146. */
  147. @Operation(summary = "签收或退签")
  148. @PostMapping("/Sign")
  149. public ActionResult<String> sign(@RequestBody FlowModel flowModel) throws WorkFlowException {
  150. operatorService.sign(flowModel);
  151. return ActionResult.success(MsgCode.SU005.get());
  152. }
  153. /**
  154. * 开始办理
  155. *
  156. * @param flowModel 参数类,ids 主键集合
  157. */
  158. @Operation(summary = "开始办理")
  159. @PostMapping("/Transact")
  160. public ActionResult<String> startHandle(@RequestBody FlowModel flowModel) throws WorkFlowException {
  161. operatorService.startHandle(flowModel);
  162. return ActionResult.success(MsgCode.SU005.get());
  163. }
  164. /**
  165. * 保存草稿
  166. *
  167. * @param id 经办主键
  168. * @param flowModel 参数
  169. */
  170. @Operation(summary = "保存草稿")
  171. @PostMapping("/SaveAudit/{id}")
  172. public ActionResult<String> saveAudit(@PathVariable("id") String id, @RequestBody FlowModel flowModel) throws WorkFlowException {
  173. operatorUtil.checkOperatorPermission(id);
  174. operatorService.saveAudit(id, flowModel);
  175. return ActionResult.success(MsgCode.SU002.get());
  176. }
  177. /**
  178. * 同意拒绝
  179. *
  180. * @param id 经办主键
  181. * @param flowModel 参数
  182. */
  183. @Operation(summary = "同意拒绝")
  184. @PostMapping("/Audit/{id}")
  185. public ActionResult audit(@PathVariable("id") String id, @RequestBody FlowModel flowModel) throws Exception {
  186. OperatorEntity operator = operatorUtil.checkOperator(id);
  187. TaskEntity taskEntity = taskService.getInfo(operator.getTaskId());
  188. if (null == taskEntity) {
  189. throw new WorkFlowException(MsgCode.FA001.get());
  190. }
  191. operatorUtil.checkOperatorPermission(id);
  192. boolean lock = redisLock.lock(taskEntity.getId() + operator.getNodeId(), operator.getId(), 5, TimeUnit.SECONDS);
  193. if (!lock) {
  194. throw new WorkFlowException("当前节点正在审批中,请稍后再试");
  195. }
  196. Integer handleStatus = flowModel.getHandleStatus();
  197. try {
  198. operatorService.auditWithCheck(id, flowModel);
  199. } catch (Exception e) {
  200. operatorUtil.compensate(taskEntity);
  201. throw e;
  202. } finally {
  203. redisLock.unlock(taskEntity.getId() + operator.getNodeId(), operator.getId());
  204. }
  205. operatorUtil.handleOperator();
  206. operatorUtil.handleEvent();
  207. taskEntity = flowModel.getTaskEntity();
  208. if (taskEntity.getRejectDataId() == null) {
  209. operatorUtil.autoAudit(flowModel);
  210. operatorUtil.handleOperator();
  211. operatorUtil.handleEvent();
  212. }
  213. operatorUtil.handleTaskStatus();
  214. TaskEntity task = taskService.getById(taskEntity.getId());
  215. taskEntity = task == null ? taskEntity : task;
  216. AuditModel model = taskUtil.getAuditModel(taskEntity.getId(), flowModel, operator);
  217. String msg = Objects.equals(handleStatus, FlowNature.RejectCompletion) ? MsgCode.WF065.get() : MsgCode.WF066.get();
  218. if (ObjectUtil.equals(operator.getIsProcessing(), FlowNature.Processing)) {
  219. msg = MsgCode.WF148.get();
  220. }
  221. return ActionResult.success(msg, model);
  222. }
  223. /**
  224. * 加签
  225. *
  226. * @param id 经办主键
  227. * @param flowModel 参数
  228. */
  229. @Operation(summary = "加签")
  230. @PostMapping("/AddSign/{id}")
  231. public ActionResult<String> freeApprover(@PathVariable("id") String id, @RequestBody FlowModel flowModel) throws Exception {
  232. operatorUtil.checkOperatorPermission(id);
  233. operatorService.addSign(id, flowModel);
  234. operatorUtil.autoAudit(flowModel);
  235. operatorUtil.handleOperator();
  236. operatorUtil.handleEvent();
  237. return ActionResult.success(MsgCode.WF004.get());
  238. }
  239. /**
  240. * 获取加签的人
  241. *
  242. * @param id 经办主键
  243. * @param pagination 参数
  244. */
  245. @Operation(summary = "获取加签的人")
  246. @PostMapping("/AddSignUserIdList/{id}")
  247. public ActionResult getAddSignUserIdList(@PathVariable("id") String id, @RequestBody Pagination pagination) throws WorkFlowException {
  248. List<CandidateUserVo> reduceList = operatorService.getReduceList(id, pagination);
  249. PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
  250. return ActionResult.page(reduceList, paginationVO);
  251. }
  252. /**
  253. * 减签
  254. *
  255. * @param flowModel 参数
  256. * @param id 记录主键
  257. */
  258. @Operation(summary = "减签")
  259. @PostMapping("/ReduceApprover/{id}")
  260. public ActionResult<String> reduceApprover(@RequestBody FlowModel flowModel, @PathVariable("id") String id) throws WorkFlowException {
  261. RecordEntity record = recordService.getInfo(id);
  262. if (null == record) {
  263. throw new WorkFlowException(MsgCode.FA001.get());
  264. }
  265. if (!Objects.equals(record.getHandleId(), UserProvider.getLoginUserId())) {
  266. throw new WorkFlowException(MsgCode.AD104.get());
  267. }
  268. operatorService.reduce(id, flowModel);
  269. return ActionResult.success(MsgCode.WF069.get());
  270. }
  271. /**
  272. * 获取退回的节点
  273. *
  274. * @param id 经办主键
  275. */
  276. @Operation(summary = "获取退回的节点")
  277. @GetMapping("/SendBackNodeList/{id}")
  278. public ActionResult getFallbacks(@PathVariable("id") String id) throws WorkFlowException {
  279. ListVO<BackNodeModel> vo = new ListVO<>();
  280. vo.setList(operatorService.getFallbacks(id));
  281. return ActionResult.success(vo);
  282. }
  283. /**
  284. * 退回
  285. *
  286. * @param id 经办主键
  287. * @param flowModel 参数
  288. */
  289. @Operation(summary = "退回")
  290. @PostMapping("/SendBack/{id}")
  291. public ActionResult<String> reject(@PathVariable("id") String id, @RequestBody FlowModel flowModel) throws Exception {
  292. OperatorEntity operator = operatorUtil.checkOperator(id);
  293. TaskEntity taskEntity = taskService.getInfo(operator.getTaskId());
  294. if (null == taskEntity) {
  295. throw new WorkFlowException(MsgCode.FA001.get());
  296. }
  297. operatorUtil.checkOperatorPermission(id);
  298. try {
  299. operatorService.back(id, flowModel);
  300. } catch (Exception e) {
  301. operatorUtil.compensate(taskEntity);
  302. throw e;
  303. }
  304. operatorUtil.handleOperator();
  305. operatorUtil.handleTaskStatus();
  306. operatorUtil.handleEvent();
  307. return ActionResult.success(MsgCode.WF002.get());
  308. }
  309. /**
  310. * 撤回
  311. *
  312. * @param id 记录主键
  313. * @param flowModel 参数
  314. */
  315. @Operation(summary = "撤回")
  316. @PostMapping("/Recall/{taskRecordId}")
  317. public ActionResult<String> recall(@PathVariable("taskRecordId") String id, @RequestBody FlowModel flowModel) throws Exception {
  318. RecordEntity record = recordService.getInfo(id);
  319. if (null == record) {
  320. throw new WorkFlowException(MsgCode.FA001.get());
  321. }
  322. if (record.getStatus().equals(FlowNature.Invalid)) {
  323. throw new WorkFlowException(MsgCode.WF005.get());
  324. }
  325. OperatorEntity operator = operatorService.getInfo(record.getOperatorId());
  326. if (null == operator) {
  327. throw new WorkFlowException(MsgCode.FA001.get());
  328. }
  329. TaskEntity taskEntity = taskService.getInfo(operator.getTaskId());
  330. if (null == taskEntity) {
  331. throw new WorkFlowException(MsgCode.FA001.get());
  332. }
  333. if (!Objects.equals(record.getHandleId(), UserProvider.getLoginUserId())) {
  334. return ActionResult.fail(MsgCode.AD104.get());
  335. }
  336. flowModel.setRecordEntity(record);
  337. flowModel.setOperatorEntity(operator);
  338. try {
  339. operatorService.recall(id, flowModel);
  340. } catch (Exception e) {
  341. operatorUtil.compensate(taskEntity);
  342. throw e;
  343. }
  344. operatorUtil.handleOperator();
  345. operatorUtil.handleTaskStatus();
  346. operatorUtil.event(flowModel, EventEnum.Recall.getStatus());
  347. return ActionResult.success(MsgCode.WF008.get());
  348. }
  349. /**
  350. * 转审
  351. *
  352. * @param id 经办主键
  353. * @param flowModel 参数
  354. */
  355. @Operation(summary = "转审")
  356. @PostMapping("/Transfer/{id}")
  357. public ActionResult<String> transfer(@PathVariable("id") String id, @RequestBody FlowModel flowModel) throws Exception {
  358. operatorUtil.checkOperatorPermission(id);
  359. operatorService.transfer(id, flowModel);
  360. operatorUtil.autoAudit(flowModel);
  361. operatorUtil.handleOperator();
  362. operatorUtil.handleEvent();
  363. OperatorEntity operator = operatorService.getById(id);
  364. return ActionResult.success(ObjectUtil.equals(operator.getIsProcessing(), FlowNature.Processing) ? MsgCode.WF003.get() : MsgCode.WF152.get());
  365. }
  366. /**
  367. * 协办
  368. *
  369. * @param id 主键
  370. * @param flowModel 参数
  371. */
  372. @Operation(summary = "协办")
  373. @PostMapping("/Assist/{id}")
  374. public ActionResult<String> assist(@PathVariable("id") String id, @RequestBody FlowModel flowModel) throws WorkFlowException {
  375. operatorUtil.checkOperatorPermission(id);
  376. operatorService.assist(id, flowModel);
  377. return ActionResult.success(MsgCode.WF067.get());
  378. }
  379. /**
  380. * 协办保存
  381. *
  382. * @param id 主键
  383. * @param flowModel 参数
  384. */
  385. @Operation(summary = "协办保存")
  386. @PostMapping("/AssistSave/{id}")
  387. public ActionResult<String> assistSave(@PathVariable("id") String id, @RequestBody FlowModel flowModel) throws WorkFlowException {
  388. operatorUtil.checkOperatorPermission(id);
  389. operatorService.assistSave(id, flowModel);
  390. return ActionResult.success(MsgCode.WF068.get());
  391. }
  392. /**
  393. * 批量审批流程分类列表
  394. */
  395. @Operation(summary = "批量审批流程分类列表")
  396. @GetMapping("/BatchFlowSelector")
  397. public ActionResult<List<FlowBatchModel>> batchFlowSelector() {
  398. List<FlowBatchModel> list = operatorService.batchFlowSelector();
  399. return ActionResult.success(list);
  400. }
  401. /**
  402. * 批量审批流程版本列表
  403. *
  404. * @param templateId 流程定义主键
  405. */
  406. @Operation(summary = "批量审批流程版本列表")
  407. @GetMapping("/BatchVersionSelector/{templateId}")
  408. public ActionResult<List<FlowBatchModel>> batchVersionSelector(@PathVariable("templateId") String templateId) {
  409. List<FlowBatchModel> list = operatorService.batchVersionSelector(templateId);
  410. return ActionResult.success(list);
  411. }
  412. /**
  413. * 批量审批节点列表
  414. *
  415. * @param flowId 定义版本主键
  416. */
  417. @Operation(summary = "批量审批节点列表")
  418. @GetMapping("/BatchNodeSelector/{flowId}")
  419. public ActionResult<List<FlowBatchModel>> batchNodeSelector(@PathVariable("flowId") String flowId) {
  420. List<FlowBatchModel> list = operatorService.batchNodeSelector(flowId);
  421. return ActionResult.success(list);
  422. }
  423. /**
  424. * 批量审批节点属性
  425. *
  426. * @param flowModel 参数
  427. */
  428. @Operation(summary = "批量审批节点属性")
  429. @GetMapping("/BatchNode")
  430. public ActionResult batchNode(FlowModel flowModel) throws WorkFlowException {
  431. Map<String, Object> nodeMap = operatorService.batchNode(flowModel);
  432. return ActionResult.success(nodeMap);
  433. }
  434. /**
  435. * 批量获取候选人
  436. *
  437. * @param flowId 版本主键
  438. * @param operatorId 经办主键
  439. * @param batchType 类型,0.同意 1.拒绝
  440. */
  441. @Operation(summary = "批量获取候选人")
  442. @GetMapping("/BatchCandidate")
  443. public ActionResult batchCandidate(String flowId, String operatorId, Integer batchType) throws WorkFlowException {
  444. CandidateCheckVo vo = operatorService.batchCandidates(flowId, operatorId, batchType);
  445. return ActionResult.success(vo);
  446. }
  447. /**
  448. * 批量审批
  449. *
  450. * @param flowModel 参数
  451. */
  452. @Operation(summary = "批量审批")
  453. @PostMapping("/BatchOperation")
  454. public ActionResult batchOperation(@RequestBody FlowModel flowModel) throws Exception {
  455. try {
  456. operatorService.batch(flowModel);
  457. } catch (Exception e) {
  458. List<TaskEntity> taskList = flowModel.getTaskList();
  459. if (CollectionUtil.isNotEmpty(taskList)) {
  460. for (TaskEntity taskEntity : taskList) {
  461. operatorUtil.compensate(taskEntity);
  462. }
  463. }
  464. throw e;
  465. }
  466. operatorUtil.handleOperator();
  467. operatorUtil.handleTaskStatus();
  468. operatorUtil.handleEvent();
  469. return ActionResult.success(MsgCode.WF011.get());
  470. }
  471. /**
  472. * 消息跳转工作流
  473. *
  474. * @param id 经办或抄送主键
  475. */
  476. @Operation(summary = "消息跳转工作流")
  477. @GetMapping("/{id}/Info")
  478. public ActionResult checkInfo(@PathVariable("id") String id, @RequestParam(value = "opType", required = false) String opType) throws WorkFlowException {
  479. Map<String, String> map = new HashMap<>();
  480. List<String> list = ImmutableList.of(OpTypeEnum.LaunchDetail.getType(), OpTypeEnum.LaunchCreate.getType());
  481. if (list.contains(opType)) {
  482. String type = OpTypeEnum.LaunchDetail.getType();
  483. TaskEntity task = taskService.getById(id);
  484. if (null != task) {
  485. taskUtil.checkTemplateHide(task.getTemplateId());
  486. if (ObjectUtil.equals(task.getStatus(), TaskStatusEnum.TO_BE_SUBMIT.getCode())) {
  487. type = OpTypeEnum.LaunchCreate.getType();
  488. }
  489. }
  490. map.put("opType", type);
  491. return ActionResult.success(map);
  492. }
  493. String type = taskService.checkInfo(id);
  494. map.put("opType", type);
  495. return ActionResult.success(map);
  496. }
  497. /**
  498. * 进度节点记录列表
  499. *
  500. * @param taskId 任务主键
  501. * @param nodeId 节点id
  502. */
  503. @Operation(summary = "进度节点记录列表")
  504. @GetMapping("/RecordList")
  505. public ActionResult getRecordList(@RequestParam("taskId") String taskId, @RequestParam("nodeId") String nodeId) {
  506. return ActionResult.success(recordService.getList(taskId, nodeId));
  507. }
  508. }