CostProjectTaskManagerImpl.java 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. package com.hotent.project.manager.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.baomidou.mybatisplus.core.metadata.IPage;
  4. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  5. import com.hotent.base.manager.impl.BaseManagerImpl;
  6. import com.hotent.base.util.AuthenticationUtil;
  7. import com.hotent.base.util.StringUtil;
  8. import com.hotent.baseInfo.req.CostTaskSearchReq;
  9. import com.hotent.constant.NodeConstant;
  10. import com.hotent.constant.TaskStatusConstant;
  11. import com.hotent.enterpriseDeclare.req.CostTaskPageReq;
  12. import com.hotent.enterpriseDeclare.req.CostTaskReviewPageReq;
  13. import com.hotent.project.dao.CostProjectTaskDao;
  14. import com.hotent.project.manager.*;
  15. import com.hotent.project.model.CostProjectApproval;
  16. import com.hotent.project.model.CostProjectTask;
  17. import com.hotent.project.model.CostProjectTaskMaterial;
  18. import com.hotent.project.model.CostProjectTaskPreliminaryOpinion;
  19. import com.hotent.project.resp.CostProjectApprovalDetailResp;
  20. import com.hotent.surveyinfo.manager.CostSurveyTemplateUploadManager;
  21. import com.hotent.surveyinfo.model.CostSurveyTemplateUpload;
  22. import com.hotent.uc.api.model.IUser;
  23. import com.hotent.uc.manager.UserManager;
  24. import com.hotent.uc.model.User;
  25. import com.hotent.uc.util.ContextUtil;
  26. import org.springframework.beans.factory.annotation.Autowired;
  27. import org.springframework.stereotype.Service;
  28. import org.springframework.transaction.annotation.Transactional;
  29. import java.util.List;
  30. /**
  31. * 项目任务表 服务实现类
  32. *
  33. * @author 超级管理员
  34. * @company 山西清众科技股份有限公司
  35. * @since 2025-10-03
  36. */
  37. @Service
  38. public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskDao, CostProjectTask> implements CostProjectTaskManager {
  39. @Autowired
  40. private CostProjectTaskProccessManager costProjectTaskProccessManager;
  41. @Autowired
  42. private CostProjectTaskManager costProjectTaskManager;
  43. @Autowired
  44. private CostNoticeManager costNoticeManager;
  45. @Autowired
  46. private CostProjectApprovalManager costProjectApprovalManager;
  47. @Autowired
  48. private CostProjectTaskPreliminaryOpinionManager preliminaryOpinionManager;
  49. @Autowired
  50. private UserManager userService;
  51. @Autowired
  52. private CostProjectTaskMaterialManager costProjectTaskMaterialManager;
  53. @Autowired
  54. private CostSurveyTemplateUploadManager costSurveyTemplateUploadManager;
  55. @Autowired
  56. private CostProjectTaskLogManager costProjectTaskLogManager;
  57. @Override
  58. public List<CostProjectTask> getTaskList(CostTaskSearchReq req) throws Exception {
  59. IUser iUser = ContextUtil.getCurrentUser();
  60. User user = userService.getByAccount(iUser.getAccount());
  61. req.setDataScope(user.getDataScope());
  62. req.setProvinceCode(user.getProvinceCode());
  63. req.setCityCode(user.getCityCode());
  64. req.setCountyCode(user.getCountyCode());
  65. List<CostProjectTask> list = baseMapper.getCostProjectTaskList(req.getDataScope()
  66. , req.getProvinceCode()
  67. , req.getCityCode()
  68. , req.getCountyCode()
  69. , req.getYear()
  70. , req.getProjectName());
  71. /*LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  72. if (ObjectUtil.isNotEmpty(req.getYear())) {
  73. queryWrapper.eq(CostProjectTask::getYear, req.getYear());
  74. }
  75. if (ObjectUtil.isNotEmpty(req.getProjectName())) {
  76. queryWrapper.like(CostProjectTask::getProjectName, req.getProjectName());
  77. }
  78. queryWrapper.eq(CostProjectTask::getIsDeleted, BaseConstant.NORMAL_STATUS);
  79. List<CostProjectTask> list = this.list(queryWrapper);*/
  80. return list;
  81. }
  82. @Override
  83. public IPage<CostProjectTask> pageListForReviewTask(CostTaskReviewPageReq req) {
  84. // 获取当前用户
  85. IUser currentUser = ContextUtil.getCurrentUser();
  86. String currentUserId = currentUser.getUserId();
  87. // 1. 先查询当前用户有权限的立项(负责人或项目组成员)
  88. LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
  89. approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
  90. approvalQueryWrapper.and(wrapper -> wrapper
  91. .eq(CostProjectApproval::getLeaderId, currentUserId)
  92. .or(projectMembersWrapper -> {
  93. projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
  94. })
  95. );
  96. List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);
  97. // 如果没有权限的立项,返回空结果
  98. if (accessibleApprovals.isEmpty()) {
  99. return new Page<>(req.getPageNum(), req.getPageSize());
  100. }
  101. // 提取有权限的立项ID列表
  102. List<String> accessibleProjectIds = accessibleApprovals.stream()
  103. .map(CostProjectApproval::getProjectId)
  104. .distinct()
  105. .collect(java.util.stream.Collectors.toList());
  106. // 2. 构建任务查询条件
  107. LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  108. // 查询未删除的记录
  109. queryWrapper.eq(CostProjectTask::getIsDeleted, "0");
  110. // 查询根任务(pid为0)
  111. queryWrapper.eq(CostProjectTask::getPid, "0");
  112. // 只查询当前用户有权限的立项对应的任务
  113. queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);
  114. // 根据请求参数添加查询条件
  115. if (StringUtil.isNotEmpty(req.getProjectName())) {
  116. queryWrapper.like(CostProjectTask::getProjectName, req.getProjectName());
  117. }
  118. if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
  119. queryWrapper.like(CostProjectTask::getAuditedUnitName, req.getAuditedUnitName());
  120. }
  121. if (StringUtil.isNotEmpty(req.getStatus())) {
  122. queryWrapper.eq(CostProjectTask::getStatus, req.getStatus());
  123. }
  124. if (StringUtil.isNotEmpty(req.getCurrentNode())) {
  125. // 如果指定了节点,按节点查询
  126. queryWrapper.eq(CostProjectTask::getCurrentNode, req.getCurrentNode());
  127. } else {
  128. // 如果没有指定节点,默认排除归档节点(待审核列表)
  129. queryWrapper.ne(CostProjectTask::getCurrentNode, NodeConstant.guidang.getNodeKey());
  130. }
  131. // 按创建时间倒序排列
  132. queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
  133. // 创建分页对象并执行查询
  134. Page<CostProjectTask> page = new Page<>(req.getPageNum(), req.getPageSize());
  135. IPage<CostProjectTask> result = costProjectTaskManager.page(page, queryWrapper);
  136. // 填充根任务的子任务列表和流程信息
  137. for (CostProjectTask rootTask : result.getRecords()) {
  138. // 查询子任务列表
  139. LambdaQueryWrapper<CostProjectTask> childQueryWrapper = new LambdaQueryWrapper<>();
  140. childQueryWrapper.eq(CostProjectTask::getPid, rootTask.getId())
  141. .eq(CostProjectTask::getIsDeleted, "0")
  142. .orderByAsc(CostProjectTask::getOrderNum);
  143. List<CostProjectTask> childTasks = costProjectTaskManager.list(childQueryWrapper);
  144. for (CostProjectTask childTask : childTasks) {
  145. childTask.setStatusName(TaskStatusConstant.getStatusNameByCode(childTask.getStatus()));
  146. CostProjectApprovalDetailResp detail = costProjectApprovalManager.getDetail(childTask.getProjectId());
  147. childTask.setCatalogId(detail.getCatalogId());
  148. }
  149. rootTask.setStatusName(TaskStatusConstant.getStatusNameByCode(rootTask.getStatus()));
  150. rootTask.setChildTasks(childTasks);
  151. rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
  152. CostProjectApprovalDetailResp detail = costProjectApprovalManager.getDetail(rootTask.getProjectId());
  153. rootTask.setCatalogId(detail.getCatalogId());
  154. }
  155. return result;
  156. }
  157. @Override
  158. public IPage<CostProjectTask> pageListForArchive(CostTaskReviewPageReq req) {
  159. // 获取当前用户
  160. IUser currentUser = ContextUtil.getCurrentUser();
  161. String currentUserId = currentUser.getUserId();
  162. // 1. 先查询当前用户有权限的立项(负责人或项目组成员)
  163. LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
  164. approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
  165. approvalQueryWrapper.and(wrapper -> wrapper
  166. .eq(CostProjectApproval::getLeaderId, currentUserId)
  167. .or(projectMembersWrapper -> {
  168. projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
  169. })
  170. );
  171. List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);
  172. // 如果没有权限的立项,返回空结果
  173. if (accessibleApprovals.isEmpty()) {
  174. return new Page<>(req.getPageNum(), req.getPageSize());
  175. }
  176. // 提取有权限的立项ID列表
  177. List<String> accessibleProjectIds = accessibleApprovals.stream()
  178. .map(CostProjectApproval::getProjectId)
  179. .distinct()
  180. .collect(java.util.stream.Collectors.toList());
  181. // 2. 构建任务查询条件
  182. LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  183. // 查询未删除的记录
  184. queryWrapper.eq(CostProjectTask::getIsDeleted, "0");
  185. // 查询主任务(pid为0)
  186. queryWrapper.eq(CostProjectTask::getPid, "0");
  187. // 只查询当前用户有权限的立项对应的任务
  188. queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);
  189. // 根据请求参数添加查询条件
  190. if (StringUtil.isNotEmpty(req.getProjectName())) {
  191. queryWrapper.like(CostProjectTask::getProjectName, req.getProjectName());
  192. }
  193. if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
  194. queryWrapper.like(CostProjectTask::getAuditedUnitName, req.getAuditedUnitName());
  195. }
  196. if (StringUtil.isNotEmpty(req.getStatus())) {
  197. queryWrapper.eq(CostProjectTask::getStatus, req.getStatus());
  198. }
  199. // 根据是否归档字段过滤
  200. if (StringUtil.isNotEmpty(req.getIsGd())) {
  201. queryWrapper.eq(CostProjectTask::getIsGd, req.getIsGd());
  202. }
  203. // 按创建时间倒序排列
  204. queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
  205. // 创建分页对象并执行查询
  206. Page<CostProjectTask> page = new Page<>(req.getPageNum(), req.getPageSize());
  207. IPage<CostProjectTask> result = costProjectTaskManager.page(page, queryWrapper);
  208. // 只填充节点名称,不查询子任务
  209. for (CostProjectTask rootTask : result.getRecords()) {
  210. rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
  211. }
  212. return result;
  213. }
  214. @Override
  215. @Transactional
  216. public void createOrUpdate(CostProjectTask costProjectTask) {
  217. //新建或更新
  218. this.saveOrUpdate(costProjectTask);
  219. }
  220. @Override
  221. @Transactional
  222. public String saveTask(CostTaskPageReq costTaskPageReq) {
  223. // 1.校验内容是否填写完毕!t
  224. List<CostProjectTaskMaterial> costProjectTaskMaterials = costProjectTaskMaterialManager.listByTaskId(costTaskPageReq.getTaskId());
  225. boolean c = costProjectTaskMaterials.stream()
  226. .filter(item ->"1".equals(item.getIsRequired()))
  227. .allMatch(
  228. item -> "1".equals(item.getIsUpload())
  229. );
  230. if (!c) {
  231. throw new RuntimeException("报送资料必填文件未全部填写完成!");
  232. }
  233. List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(costTaskPageReq.getTaskId());
  234. boolean d = costSurveyTemplateUploads.stream()
  235. .filter(item ->"1".equals(item.getIsRequired()))
  236. .allMatch(
  237. item -> "1".equals(item.getIsUpload())
  238. );
  239. if (!d) {
  240. throw new RuntimeException("成本调查必填文件未全部填写完成!");
  241. }
  242. // 2. 子流程状态改为审核中
  243. CostProjectTask task = this.getById(costTaskPageReq.getTaskId());
  244. task.setCurrentNode(NodeConstant.clcs.getNodeKey());
  245. task.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  246. this.updateById(task);
  247. return "任务提交成功,已进入材料初审阶段";
  248. }
  249. @Override
  250. public String saveYjTask(CostProjectTaskPreliminaryOpinion costProjectTaskPreliminaryOpinion) {
  251. // 1.校验内容是否填写完毕!todo
  252. preliminaryOpinionManager.createOrUpdate(costProjectTaskPreliminaryOpinion);
  253. // 3. 子流程状态改为已反馈
  254. CostProjectTask task = this.getById(costProjectTaskPreliminaryOpinion.getTaskId());
  255. task.setStatus(TaskStatusConstant.FEEDBACKED.getStatusCode());
  256. this.updateById(task);
  257. return "意见反馈完成";
  258. }
  259. @Override
  260. public String doProcessBtn(CostTaskPageReq req) {
  261. CostProjectTask task = costProjectTaskManager.getById(req.getTaskId());
  262. String resultMessage = "";
  263. switch (req.getKey()) {
  264. case "1":
  265. // 补充材料
  266. resultMessage = supplementMaterial(task, req);
  267. break;
  268. case "2":
  269. // 中止/恢复
  270. resultMessage = suspendTask(task, req);
  271. break;
  272. case "3":
  273. // 通过
  274. resultMessage = completeTask(task);
  275. break;
  276. case "4":
  277. // 退回
  278. resultMessage = returnToSubmit(task, req);
  279. break;
  280. case "6":
  281. // 退回上一步
  282. resultMessage = backPreToSubmit(task, req);
  283. break;
  284. case "7":
  285. // 扭转下一步
  286. resultMessage = toNextSubmit(task, req);
  287. break;
  288. default:
  289. return "未知的操作类型";
  290. }
  291. return resultMessage;
  292. }
  293. /**
  294. * 通过,填写原因 修改状态
  295. */
  296. private String completeTask(CostProjectTask task) {
  297. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  298. if (nTask == null) {
  299. return "任务不存在";
  300. }
  301. List<CostProjectTask> children = costProjectTaskManager.list(
  302. new LambdaQueryWrapper<CostProjectTask>()
  303. .eq(CostProjectTask::getPid, nTask.getId())
  304. );
  305. if (children.isEmpty()) {
  306. // 子任务 所有“是否必填”为“是”的资料“初审结果”均为“通过”.
  307. List<CostProjectTaskMaterial> costProjectTaskMaterials = costProjectTaskMaterialManager.listByTaskId(nTask.getId());
  308. boolean c = costProjectTaskMaterials.stream()
  309. .filter(item -> "1".equals(item.getIsRequired()))
  310. .allMatch(
  311. item -> "1".equals(item.getAuditedStatus())
  312. );
  313. if (!c) {
  314. throw new RuntimeException("报送资料未全部通过!");
  315. }
  316. List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(nTask.getId());
  317. boolean d = costSurveyTemplateUploads.stream()
  318. .filter(item -> "1".equals(item.getIsRequired()))
  319. .allMatch(
  320. item -> "1".equals(item.getAuditedStatus())
  321. );
  322. if (!d) {
  323. throw new RuntimeException("成本调查表未全部通过!");
  324. }
  325. } else {
  326. // 主任务
  327. boolean b = children.stream().noneMatch(child ->
  328. child.getStatus().equals(TaskStatusConstant.AUDITING.getStatusCode()));
  329. if (!b) {
  330. throw new RuntimeException("子任务未全部办理,主任务无法办结");
  331. }
  332. }
  333. task.setStatus(TaskStatusConstant.COMPLETED.getStatusCode());
  334. costProjectTaskManager.updateById(task);
  335. // 发送通知
  336. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "通过";
  337. // 操作人
  338. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已通过" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  339. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  340. String noticeSource = "系统";
  341. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  342. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  343. return title;
  344. }
  345. /**
  346. * 退回,填写原因 修改状态
  347. */
  348. private String returnToSubmit(CostProjectTask task, CostTaskPageReq req) {
  349. switch (req.getProcessNodeKey()) {
  350. case "sdsh":
  351. throw new RuntimeException("当前节点无法退回");
  352. default:
  353. // 通知内容组装
  354. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "退回";
  355. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  356. String noticeSource = "系统";
  357. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  358. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已退回" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  359. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  360. // 更新任务的当前节点和状态
  361. task.setStatus(TaskStatusConstant.NOT_PASSED.getStatusCode());
  362. costProjectTaskManager.updateById(task);
  363. return title;
  364. }
  365. }
  366. /**
  367. * 中止,填写原因 修改状态
  368. */
  369. private String suspendTask(CostProjectTask task, CostTaskPageReq req) {
  370. // 更新任务状态为中止/恢复
  371. String status = req.getStatus() == null ? TaskStatusConstant.SUSPENDED.getStatusCode() : TaskStatusConstant.AUDITING.getStatusCode();
  372. task.setStatus(status);
  373. costProjectTaskManager.updateById(task);
  374. // 通知内容组装
  375. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + TaskStatusConstant.getStatusNameByCode(status);
  376. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已" + TaskStatusConstant.getStatusNameByCode(status) + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  377. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  378. String noticeSource = "系统";
  379. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  380. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  381. return title;
  382. }
  383. /**
  384. * 补充材料,发送通知+修改任务状态
  385. */
  386. private String supplementMaterial(CostProjectTask task, CostTaskPageReq req) {
  387. String currentNode = task.getCurrentNode();
  388. String title = NodeConstant.getNodeValueByKey(currentNode) + TaskStatusConstant.BCCL.getStatusName();
  389. String noticeSource = "系统";
  390. switch (currentNode) {
  391. // 集体审议节点:支持指定多个子任务补充材料
  392. case "jtsy":
  393. if (StringUtil.isNotEmpty(req.getChildTaskId())) {
  394. String[] childTaskIdArray = req.getChildTaskId().split(",");
  395. List<String> unitNames = new java.util.ArrayList<>();
  396. for (String childTaskId : childTaskIdArray) {
  397. CostProjectTask childTask = costProjectTaskManager.getById(childTaskId);
  398. if (childTask == null) {
  399. throw new RuntimeException("子任务不存在:" + childTaskId);
  400. }
  401. // 验证子任务是否属于当前主任务
  402. if (!childTask.getPid().equals(task.getId())) {
  403. throw new RuntimeException("子任务不属于当前主任务:" + childTaskId);
  404. }
  405. // 更新子任务状态为补充材料
  406. childTask.setStatus(TaskStatusConstant.BCCL.getStatusCode());
  407. costProjectTaskManager.updateById(childTask);
  408. // 通知内容组装(针对子任务对应的单位)
  409. String childContent = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求" + childTask.getAuditedUnitName() + "补充材料,项目(" + task.getProjectName() + ")";
  410. String childEnterpriseId = childTask.getAuditedUnitId() == null ? "" : childTask.getAuditedUnitId();
  411. String childSendTarget = childTask.getCreateBy() == null ? "" : childTask.getCreateBy();
  412. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, childContent, childEnterpriseId, noticeSource, childSendTarget);
  413. // 收集单位名称
  414. if (StringUtil.isNotEmpty(childTask.getAuditedUnitName())) {
  415. unitNames.add(childTask.getAuditedUnitName());
  416. }
  417. }
  418. // 返回结果,包含所有单位名称
  419. String unitNamesStr = unitNames.isEmpty() ? "" : String.join("、", unitNames);
  420. return title + "(单位:" + unitNamesStr + ")";
  421. }
  422. default:
  423. task.setStatus(TaskStatusConstant.BCCL.getStatusCode());
  424. costProjectTaskManager.updateById(task);
  425. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求" + task.getAuditedUnitName() + "补充材料,项目(" + task.getProjectName() + ")";
  426. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  427. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  428. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  429. return title;
  430. }
  431. }
  432. /**
  433. * 退回上一步,填写原因 修改状态和节点
  434. */
  435. private String backPreToSubmit(CostProjectTask task, CostTaskPageReq req) {
  436. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  437. if (nTask == null || !nTask.getPid().equals("0")) {
  438. throw new RuntimeException("当前节点无法退回");
  439. }
  440. // 获取退回后的上一节点
  441. NodeConstant prevNode = NodeConstant.getPrevNode(nTask.getCurrentNode());
  442. if (prevNode == null) {
  443. throw new RuntimeException("当前节点已是第一步,无法退回");
  444. }
  445. String prevNodeStatus = prevNode.getNodeKey();
  446. // 主任务退回上一步
  447. nTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  448. nTask.setCurrentNode(prevNodeStatus);
  449. costProjectTaskManager.updateById(nTask);
  450. // 子任务都要退回,并根据退回后的节点设置正确的状态
  451. List<CostProjectTask> children = costProjectTaskManager.list(
  452. new LambdaQueryWrapper<CostProjectTask>()
  453. .eq(CostProjectTask::getPid, nTask.getId())
  454. .eq(CostProjectTask::getIsDeleted, "0")
  455. );
  456. // 根据退回后的节点,设置子任务状态(参考completeTask的逻辑)
  457. String childStatus = "";
  458. switch (prevNodeStatus) {
  459. case "yjfk":
  460. childStatus = TaskStatusConstant.WAIT_FEEDBACK.getStatusCode();
  461. break;
  462. case "cjbg":
  463. case "jtsy":
  464. childStatus = TaskStatusConstant.COMPLETED.getStatusCode();
  465. break;
  466. default:
  467. childStatus = TaskStatusConstant.AUDITING.getStatusCode();
  468. break;
  469. }
  470. for (CostProjectTask child : children) {
  471. child.setStatus(childStatus);
  472. child.setCurrentNode(prevNodeStatus);
  473. costProjectTaskManager.updateById(child);
  474. }
  475. // 通知内容组装
  476. String title = NodeConstant.getNodeValueByKey(prevNodeStatus) + "退回上一步";
  477. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  478. String noticeSource = "系统";
  479. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  480. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, req.getContent(), enterpriseId, noticeSource, sendTarget);
  481. return title;
  482. }
  483. /**
  484. * 扭转下一步,填写原因 修改状态和节点
  485. */
  486. private String toNextSubmit(CostProjectTask task, CostTaskPageReq req) {
  487. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  488. if (nTask == null || !nTask.getPid().equals("0")) {
  489. throw new RuntimeException("当前节点无法扭转");
  490. }
  491. if (!task.getStatus().equals(TaskStatusConstant.COMPLETED.getStatusCode())) {
  492. throw new RuntimeException("请办结任务后,在进行扭转下一步");
  493. }
  494. // 子任务都办结才可以扭转
  495. List<CostProjectTask> children = costProjectTaskManager.list(
  496. new LambdaQueryWrapper<CostProjectTask>()
  497. .eq(CostProjectTask::getPid, nTask.getId())
  498. );
  499. boolean b = children.stream().noneMatch(
  500. child -> child.getStatus().equals(TaskStatusConstant.AUDITING.getStatusCode()));
  501. if (!b) {
  502. throw new RuntimeException("子任务未全部办结,主任务无法扭转");
  503. }
  504. // 将当前任务置为办结
  505. String nextNodeStatus = NodeConstant.getNextNode(nTask.getCurrentNode()).getNodeKey();
  506. task.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  507. task.setCurrentNode(nextNodeStatus);
  508. nTask.setIsGd("0");
  509. costProjectTaskManager.updateById(task);
  510. // 如果所有子任务都办结,则将父子任务都扭转
  511. String status = "";
  512. switch (nextNodeStatus) {
  513. case "yjfk":
  514. status = TaskStatusConstant.WAIT_FEEDBACK.getStatusCode();
  515. break;
  516. case "jtsy":
  517. status = TaskStatusConstant.COMPLETED.getStatusCode();
  518. break;
  519. default:
  520. status = TaskStatusConstant.AUDITING.getStatusCode();
  521. break;
  522. }
  523. for (CostProjectTask child : children) {
  524. if (!child.getStatus().equals(TaskStatusConstant.SUSPENDED.getStatusCode())) {
  525. child.setStatus(status);
  526. child.setCurrentNode(nextNodeStatus);
  527. costProjectTaskManager.updateById(child);
  528. }
  529. }
  530. // 通知内容组装
  531. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "扭转至下一步";
  532. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  533. String noticeSource = "系统";
  534. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  535. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, req.getContent(), enterpriseId, noticeSource, sendTarget);
  536. return title;
  537. }
  538. @Override
  539. public Integer countForReviewTask(CostTaskReviewPageReq req) {
  540. LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  541. queryWrapper.eq(CostProjectTask::getIsDeleted, "0")
  542. .eq(CostProjectTask::getPid, "0")
  543. ;
  544. if (StringUtil.isNotEmpty(req.getCurrentNode())) {
  545. queryWrapper.eq(CostProjectTask::getCurrentNode, req.getCurrentNode());
  546. } else {
  547. queryWrapper.ne(CostProjectTask::getCurrentNode, NodeConstant.guidang.getNodeKey());
  548. }
  549. return costProjectTaskManager.count(queryWrapper);
  550. }
  551. }