CostProjectTaskManagerImpl.java 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561
  1. package com.hotent.project.manager.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.baomidou.mybatisplus.core.metadata.IPage;
  5. import com.baomidou.mybatisplus.core.toolkit.StringUtils;
  6. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  7. import com.hotent.base.manager.impl.BaseManagerImpl;
  8. import com.hotent.base.query.PageList;
  9. import com.hotent.base.query.QueryFilter;
  10. import com.hotent.base.util.AuthenticationUtil;
  11. import com.hotent.base.util.StringUtil;
  12. import com.hotent.baseInfo.manager.AuditedUnitManager;
  13. import com.hotent.baseInfo.manager.CostCatalogManager;
  14. import com.hotent.baseInfo.manager.CostDictDataManager;
  15. import com.hotent.baseInfo.manager.CostDistrictManager;
  16. import com.hotent.baseInfo.model.AuditedUnit;
  17. import com.hotent.baseInfo.model.CostCatalog;
  18. import com.hotent.baseInfo.model.CostDictData;
  19. import com.hotent.baseInfo.model.CostDistrict;
  20. import com.hotent.baseInfo.req.CostTaskSearchReq;
  21. import com.hotent.constant.NodeConstant;
  22. import com.hotent.constant.TaskStatusConstant;
  23. import com.hotent.enterpriseDeclare.req.CostTaskPageReq;
  24. import com.hotent.enterpriseDeclare.req.CostTaskReviewPageReq;
  25. import com.hotent.project.dao.CostProjectTaskDao;
  26. import com.hotent.project.manager.*;
  27. import com.hotent.project.model.*;
  28. import com.hotent.project.resp.CostProjectApprovalDetailResp;
  29. import com.hotent.surveyinfo.manager.CostSurveyTemplateUploadManager;
  30. import com.hotent.surveyinfo.model.CostSurveyTemplateUpload;
  31. import com.hotent.sys.persistence.manager.DataDictManager;
  32. import com.hotent.sys.persistence.model.DataDict;
  33. import com.hotent.uc.api.model.IUser;
  34. import com.hotent.uc.manager.OrgManager;
  35. import com.hotent.uc.manager.UserManager;
  36. import com.hotent.uc.model.Org;
  37. import com.hotent.uc.model.User;
  38. import com.hotent.uc.util.ContextUtil;
  39. import org.springframework.beans.factory.annotation.Autowired;
  40. import org.springframework.scheduling.annotation.Async;
  41. import org.springframework.stereotype.Service;
  42. import org.springframework.transaction.annotation.Transactional;
  43. import javax.annotation.Resource;
  44. import java.time.LocalDateTime;
  45. import java.util.*;
  46. import java.util.stream.Collectors;
  47. import static com.hotent.base.util.AuthenticationUtil.getCurrentUserMainOrgId;
  48. /**
  49. * 项目任务表 服务实现类
  50. *
  51. * @author 超级管理员
  52. * @company 山西清众科技股份有限公司
  53. * @since 2025-10-03
  54. */
  55. @Service
  56. public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskDao, CostProjectTask> implements CostProjectTaskManager {
  57. @Autowired
  58. private CostDistrictManager costDistrictManager;
  59. @Autowired
  60. private CostProjectTaskProccessManager costProjectTaskProccessManager;
  61. @Autowired
  62. private CostProjectTaskManager costProjectTaskManager;
  63. @Autowired
  64. private CostNoticeManager costNoticeManager;
  65. @Resource
  66. DataDictManager dataDictManager;
  67. @Autowired
  68. UserManager userService;
  69. @Autowired
  70. private CostProjectApprovalManager costProjectApprovalManager;
  71. @Autowired
  72. private CostProjectTaskPreliminaryOpinionManager preliminaryOpinionManager;
  73. @Autowired
  74. private CostProjectTaskApprovalManager costProjectTaskApprovalManager;
  75. @Autowired
  76. private CostProjectProccessNodeManager costProjectProccessNodeManager;
  77. @Autowired
  78. private CostProjectProccessManager costProjectProccessManager;
  79. @Autowired
  80. private CostProjectTaskMaterialManager costProjectTaskMaterialManager;
  81. @Autowired
  82. private CostSurveyTemplateUploadManager costSurveyTemplateUploadManager;
  83. @Autowired
  84. private CostProjectTaskNodeManager costProjectTaskNodeManager;
  85. @Autowired
  86. private OrgManager orgManager;
  87. @Autowired
  88. private CostCatalogManager costCatalogManager;
  89. @Autowired
  90. private AuditedUnitManager auditedUnitManager;
  91. @Autowired
  92. private CostProjectTaskMaterialSummaryManager costProjectTaskMaterialSummaryManager;
  93. @Autowired
  94. private com.hotent.project.service.AsyncMaterialSummaryService asyncMaterialSummaryService;
  95. @Override
  96. public List<CostProjectTask> getTaskList(CostTaskSearchReq req) throws Exception {
  97. // 获取当前用户
  98. IUser currentUser = ContextUtil.getCurrentUser();
  99. String currentUserId = currentUser.getUserId();
  100. // 1. 先查询当前用户有权限的立项(负责人或项目组成员)
  101. LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
  102. approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
  103. approvalQueryWrapper.and(wrapper -> wrapper
  104. .eq(CostProjectApproval::getLeaderId, currentUserId)
  105. .or(projectMembersWrapper -> {
  106. projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
  107. })
  108. );
  109. List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);
  110. // 如果没有权限的立项,返回空结果
  111. if (accessibleApprovals.isEmpty()) {
  112. return new ArrayList<>();
  113. }
  114. // 提取有权限的立项ID列表
  115. List<String> accessibleProjectIds = accessibleApprovals.stream()
  116. .map(CostProjectApproval::getProjectId)
  117. .distinct()
  118. .collect(java.util.stream.Collectors.toList());
  119. // 2. 构建任务查询条件
  120. LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  121. // 查询未删除的记录
  122. queryWrapper.eq(CostProjectTask::getIsDeleted, "0");
  123. // 只查询当前用户有权限的立项对应的任务
  124. queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);
  125. // 按创建时间倒序排列
  126. queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
  127. return costProjectTaskManager.list(queryWrapper);
  128. }
  129. /**
  130. * 计算任务预警状态
  131. *
  132. * @param task 任务对象
  133. * @return 预警状态:green-绿色预警(在办理期限内) yellow-黄色预警(超过环节期限但没超过流程期限) red-红色预警(超过流程期限)
  134. */
  135. private String calculateWarningStatus(CostProjectTask task) {
  136. // 获取任务对应的流程信息
  137. CostProjectTaskProccess process = costProjectTaskProccessManager.getOne(
  138. new LambdaQueryWrapper<CostProjectTaskProccess>()
  139. .eq(CostProjectTaskProccess::getTaskId, task.getId())
  140. );
  141. if (process == null) {
  142. return "green"; // 默认绿色预警
  143. }
  144. // 获取当前环节的节点信息
  145. CostProjectTaskNode currentNode = costProjectTaskNodeManager.getOne(
  146. new LambdaQueryWrapper<CostProjectTaskNode>()
  147. .eq(CostProjectTaskNode::getTaskId, task.getId())
  148. .eq(CostProjectTaskNode::getProcessNodeKey, task.getCurrentNode())
  149. );
  150. // 获取当前时间
  151. LocalDateTime now = LocalDateTime.now();
  152. // 1. 如果超过流程期限,红色预警
  153. if (process.getPlannedAuditEndDate() != null &&
  154. now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
  155. return "red";
  156. }
  157. // 2. 如果当前环节有截止时间且已超过,但未超过流程期限,黄色预警
  158. if (currentNode != null && currentNode.getEndTime() != null &&
  159. now.isAfter(currentNode.getEndTime())) {
  160. // 检查是否超过流程期限
  161. if (process.getPlannedAuditEndDate() != null &&
  162. now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
  163. return "red"; // 超过流程期限,红色预警
  164. } else {
  165. return "yellow"; // 超过环节期限但未超过流程期限,黄色预警
  166. }
  167. }
  168. // 3. 默认绿色预警(在办理期限内)
  169. return "green";
  170. }
  171. @Override
  172. public IPage<CostProjectTask> pageListForReviewTask(CostTaskReviewPageReq req) throws Exception {
  173. // 获取当前用户
  174. IUser currentUser = ContextUtil.getCurrentUser();
  175. String currentUserId = currentUser.getUserId();
  176. LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
  177. if (req.getType().equals(1)) {
  178. String userId = currentUser.getUserId();
  179. User user = userService.getById(userId);
  180. Integer dataScope = user.getDataScope();
  181. // 只能查自己和自己下属的
  182. if(dataScope != null && dataScope != 0){
  183. Set<String> areaSet = new HashSet<>();
  184. if(dataScope == 1){
  185. String cityCode = user.getCityCode();
  186. String codeSub = cityCode.substring(0, 4);
  187. QueryWrapper<CostDistrict> districtQueryWrapper = new QueryWrapper<>();
  188. districtQueryWrapper.like("code", codeSub);
  189. List<CostDistrict> costDistricts = costDistrictManager.list(districtQueryWrapper);
  190. for (CostDistrict costDistrict1 : costDistricts) {
  191. areaSet.add(costDistrict1.getCode());
  192. }
  193. }
  194. if(dataScope == 2){
  195. String code = user.getCountyCode();
  196. areaSet.add(code);
  197. }
  198. approvalQueryWrapper.in(CostProjectApproval::getAreaCode,areaSet);
  199. //queryWrapper.in("area_code", areaSet);
  200. }
  201. }else {
  202. // 1. 先查询当前用户有权限的立项(负责人或项目组成员)
  203. approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
  204. approvalQueryWrapper.and(wrapper -> wrapper
  205. .eq(CostProjectApproval::getLeaderId, currentUserId)
  206. .or(projectMembersWrapper -> {
  207. projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
  208. })
  209. );
  210. }
  211. if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
  212. approvalQueryWrapper.like(CostProjectApproval::getAuditedUnitName,req.getAuditedUnitName());
  213. }
  214. if (StringUtil.isNotEmpty(req.getAuditedUnitId())) {
  215. approvalQueryWrapper.like(CostProjectApproval::getAuditedUnitId,req.getAuditedUnitId());
  216. }
  217. if (StringUtil.isNotEmpty(req.getProjectName())) {
  218. approvalQueryWrapper.like(CostProjectApproval::getProjectName,req.getProjectName());
  219. }
  220. if (StringUtil.isNotEmpty(req.getEndYear()) && StringUtil.isNotEmpty(req.getStartYear())) {
  221. List<String> years = new ArrayList<>();
  222. int startYear =Integer.parseInt(req.getStartYear());
  223. int endYear =Integer.parseInt(req.getEndYear());
  224. for (int year = startYear; year <=endYear; year++) {
  225. years.add(String.valueOf(year));
  226. }
  227. String sql = "(" +
  228. years.stream()
  229. .map(y -> "FIND_IN_SET('" + y + "', audit_period) > 0")
  230. .collect(Collectors.joining(" OR ")) +
  231. ")";
  232. approvalQueryWrapper.apply(sql);
  233. }
  234. List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);
  235. // 如果没有权限的立项,返回空结果
  236. if (accessibleApprovals.isEmpty()) {
  237. return new Page<>(req.getPageNum(), req.getPageSize());
  238. }
  239. // 提取有权限的立项ID列表
  240. List<String> accessibleProjectIds = accessibleApprovals.stream()
  241. .map(CostProjectApproval::getProjectId)
  242. .distinct()
  243. .collect(java.util.stream.Collectors.toList());
  244. if (StringUtil.isNotEmpty(req.getAreaCode())) {
  245. List<CostProjectTaskApproval> list = costProjectTaskApprovalManager.list(
  246. new LambdaQueryWrapper<CostProjectTaskApproval>().eq(CostProjectTaskApproval::getAreaCode, req.getAreaCode())
  247. );
  248. if (list.isEmpty()) {
  249. return new Page<>(req.getPageNum(), req.getPageSize());
  250. }
  251. List<String> projectIds =
  252. list.stream().map(CostProjectTaskApproval::getProjectId).collect(Collectors.toList());
  253. accessibleProjectIds.addAll(projectIds);
  254. }
  255. // 2. 构建任务查询条件
  256. LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  257. // 查询未删除的记录
  258. queryWrapper.eq(CostProjectTask::getIsDeleted, "0");
  259. // 查询根任务(pid为0)
  260. queryWrapper.eq(CostProjectTask::getPid, "0");
  261. // 只查询当前用户有权限的立项对应的任务
  262. queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);
  263. // 根据请求参数添加查询条件
  264. if (StringUtil.isNotEmpty(req.getProjectName())) {
  265. queryWrapper.like(CostProjectTask::getProjectName, req.getProjectName());
  266. }
  267. if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
  268. queryWrapper.like(CostProjectTask::getAuditedUnitName, req.getAuditedUnitName());
  269. }
  270. if (StringUtil.isNotEmpty(req.getStatus())) {
  271. queryWrapper.eq(CostProjectTask::getStatus, req.getStatus());
  272. }
  273. if (StringUtil.isNotEmpty(req.getYear())) {
  274. queryWrapper.eq(CostProjectTask::getYear, req.getYear());
  275. }
  276. if (StringUtil.isNotEmpty(req.getIsGd())) {
  277. queryWrapper.eq(CostProjectTask::getIsGd, req.getIsGd());
  278. }
  279. if (StringUtil.isNotEmpty(req.getArchiveNo())) {
  280. queryWrapper.eq(CostProjectTask::getArchiveNo, req.getArchiveNo());
  281. }
  282. if (StringUtil.isNotEmpty(req.getCurrentNode())) {
  283. queryWrapper.eq(CostProjectTask::getCurrentNode, req.getCurrentNode());
  284. }
  285. if (StringUtil.isNotEmpty(req.getNCurrentNode())) {
  286. queryWrapper.ne(CostProjectTask::getCurrentNode, req.getNCurrentNode());
  287. }
  288. if (StringUtil.isNotEmpty(req.getNStatus())) {
  289. queryWrapper.ne(CostProjectTask::getStatus, req.getNStatus());
  290. }
  291. // 按创建时间倒序排列
  292. queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
  293. Page<CostProjectTask> page = new Page<>(req.getPageNum(), req.getPageSize());
  294. IPage<CostProjectTask> result = costProjectTaskManager.page(page, queryWrapper);
  295. List<CostProjectTask> rootList = result.getRecords();
  296. if (rootList == null || rootList.isEmpty()) {
  297. return result;
  298. }
  299. List<String> rootIds = rootList.stream()
  300. .map(CostProjectTask::getId)
  301. .collect(Collectors.toList());
  302. List<CostProjectTask> allChildTasks = costProjectTaskManager.list(
  303. new LambdaQueryWrapper<CostProjectTask>()
  304. .in(CostProjectTask::getPid, rootIds)
  305. .eq(CostProjectTask::getIsDeleted, "0")
  306. .orderByAsc(CostProjectTask::getOrderNum)
  307. );
  308. Map<String, List<CostProjectTask>> childGroup =
  309. allChildTasks.stream()
  310. .collect(Collectors.groupingBy(CostProjectTask::getPid));
  311. Set<String> allProjectIds = new HashSet<>();
  312. rootList.forEach(t -> allProjectIds.add(t.getProjectId()));
  313. allChildTasks.forEach(t -> allProjectIds.add(t.getProjectId()));
  314. List<CostProjectApproval> approvalList = costProjectApprovalManager.list(
  315. new LambdaQueryWrapper<CostProjectApproval>()
  316. .in(CostProjectApproval::getProjectId, allProjectIds)
  317. );
  318. Map<String, CostProjectApproval> approvalMap =
  319. approvalList.stream().collect(
  320. Collectors.toMap(CostProjectApproval::getProjectId, v -> v)
  321. );
  322. List<String> list = rootList.stream().map(CostProjectTask::getAuditType).distinct().collect(Collectors.toList());
  323. //List<CostDictData> costDictDatas= costDictDataManager.getValueByDictType(list,null,"sys_audit_type");
  324. QueryWrapper<DataDict> wrapper = new QueryWrapper<>();
  325. wrapper.eq("TYPE_ID_","1970328589832323072");
  326. wrapper.in("KEY_",list);
  327. List<DataDict> costDictDatas= dataDictManager.list(wrapper);
  328. List<String> collect = accessibleApprovals.stream().map(CostProjectApproval::getOrgId).distinct().collect(Collectors.toList());
  329. List<Org> orgs = orgManager.getOrgByIds(collect);
  330. for (CostProjectTask rootTask : rootList) {
  331. costDictDatas.stream()
  332. .filter(c -> rootTask.getAuditType() != null &&
  333. rootTask.getAuditType().equals(String.valueOf(c.getKey())))
  334. .findAny().ifPresent(costDictData -> rootTask.setAuditTypeName(costDictData.getName()));
  335. // 根任务状态
  336. rootTask.setStatusName(TaskStatusConstant.getStatusNameByCode(rootTask.getStatus()));
  337. rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
  338. rootTask.setWarningStatus(calculateWarningStatus(rootTask));
  339. // 设置目录
  340. CostProjectApproval rootDetail = approvalMap.get(rootTask.getProjectId());
  341. if (rootDetail != null) {
  342. orgs.stream()
  343. .filter(c -> rootDetail.getOrgId() != null &&
  344. rootDetail.getOrgId().equals(c.getId()))
  345. .findAny().ifPresent(costDictData -> rootTask.setOrgName(costDictData.getName()));
  346. rootTask.setCatalogId(rootDetail.getCatalogId());
  347. if (StringUtil.isNotEmpty(rootDetail.getAreaCode())) {
  348. CostDistrict district = costDistrictManager.getOne(
  349. new LambdaQueryWrapper<CostDistrict>()
  350. .eq(CostDistrict::getCode, rootDetail.getAreaCode())
  351. );
  352. rootTask.setAreaName(district != null ? district.getName() : "山西省");
  353. }
  354. }
  355. // 子任务
  356. List<CostProjectTask> childTasks =
  357. childGroup.getOrDefault(rootTask.getId(), Collections.emptyList());
  358. for (CostProjectTask childTask : childTasks) {
  359. childTask.setStatusName(TaskStatusConstant.getStatusNameByCode(childTask.getStatus()));
  360. CostProjectApproval detail = approvalMap.get(childTask.getProjectId());
  361. if (detail != null) {
  362. childTask.setCatalogId(detail.getCatalogId());
  363. }
  364. }
  365. rootTask.setChildTasks(childTasks);
  366. }
  367. return result;
  368. }
  369. @Override
  370. @Transactional
  371. public void createOrUpdate(CostProjectTask costProjectTask) {
  372. //新建或更新
  373. this.saveOrUpdate(costProjectTask);
  374. }
  375. @Override
  376. @Transactional
  377. public String saveTask(CostTaskPageReq costTaskPageReq) {
  378. // 1.校验内容是否填写完毕!t
  379. List<CostProjectTaskMaterial> costProjectTaskMaterials = costProjectTaskMaterialManager.listByTaskId(costTaskPageReq.getTaskId());
  380. boolean c = costProjectTaskMaterials.stream()
  381. .filter(item -> "1".equals(item.getIsRequired()))
  382. .allMatch(
  383. item -> "1".equals(item.getIsUpload())
  384. );
  385. if (!c) {
  386. throw new RuntimeException("报送资料必填文件未全部填写完成!");
  387. }
  388. List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(costTaskPageReq.getTaskId());
  389. boolean d = costSurveyTemplateUploads.stream()
  390. .filter(item -> "1".equals(item.getIsRequired()))
  391. .allMatch(
  392. item -> "1".equals(item.getIsUpload())
  393. );
  394. if (!d) {
  395. throw new RuntimeException("成本调查必填文件未全部填写完成!");
  396. }
  397. // 2. 子流程状态改为审核中
  398. CostProjectTask task = this.getById(costTaskPageReq.getTaskId());
  399. String currentNode = task.getCurrentNode();
  400. // 如果当前节点不是tjcl,则保持当前节点不变,只修改状态
  401. if (!"tjcl".equals(currentNode)) {
  402. task.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  403. } else {
  404. task.setCurrentNode(NodeConstant.clcs.getNodeKey());
  405. task.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  406. CostProjectTask parentTask = this.getById(task.getPid());
  407. String parentCurrentNode = parentTask.getCurrentNode();
  408. parentTask.setCurrentNode(NodeConstant.clcs.getNodeKey());
  409. parentTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  410. this.updateById(parentTask);
  411. }
  412. this.updateById(task);
  413. // 发送通知
  414. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "材料已提交";
  415. // 操作人
  416. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "材料已提交" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  417. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  418. String orgId = getCurrentUserMainOrgId();
  419. Org org = orgManager.getById(orgId);
  420. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  421. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  422. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  423. return "任务提交成功";
  424. }
  425. @Override
  426. public String saveYjTask(CostProjectTaskPreliminaryOpinion costProjectTaskPreliminaryOpinion) {
  427. // 1.校验内容是否填写完毕!todo
  428. preliminaryOpinionManager.createOrUpdate(costProjectTaskPreliminaryOpinion);
  429. // 2. 子流程状态改为已反馈
  430. CostProjectTask task = this.getById(costProjectTaskPreliminaryOpinion.getTaskId());
  431. task.setStatus(TaskStatusConstant.FEEDBACKED.getStatusCode());
  432. this.updateById(task);
  433. // 发送通知
  434. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "意见已反馈";
  435. // 操作人
  436. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "意见已反馈" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  437. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  438. String orgId = getCurrentUserMainOrgId();
  439. Org org = orgManager.getById(orgId);
  440. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  441. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  442. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  443. return "意见反馈完成";
  444. }
  445. @Override
  446. public String doProcessBtn(CostTaskPageReq req) {
  447. CostProjectTask task = costProjectTaskManager.getById(req.getTaskId());
  448. // 检查任务是否已办结,只允许恢复操作
  449. if (TaskStatusConstant.COMPLETED.getStatusCode().equals(task.getStatus())) {
  450. if (!"2".equals(req.getKey())) {
  451. throw new RuntimeException("任务已办结,仅支持恢复操作");
  452. }
  453. }
  454. String resultMessage = "";
  455. switch (req.getKey()) {
  456. case "1":
  457. // 补充材料
  458. resultMessage = supplementMaterial(task, req);
  459. break;
  460. case "2":
  461. // 中止/恢复
  462. resultMessage = suspendTask(task, req);
  463. break;
  464. case "3":
  465. // 通过
  466. resultMessage = completeTask(task);
  467. break;
  468. case "4":
  469. // 退回
  470. resultMessage = returnToSubmit(task, req);
  471. break;
  472. case "5":
  473. // 催办
  474. resultMessage = remindTask(task, req);
  475. break;
  476. case "6":
  477. // 退回上一步
  478. resultMessage = backPreToSubmit(task, req);
  479. break;
  480. case "7":
  481. // 扭转下一步
  482. resultMessage = toNextSubmit(task, req);
  483. break;
  484. case "8":
  485. // 复核
  486. resultMessage = reviewTask(task, req);
  487. break;
  488. case "10":
  489. // 催报
  490. resultMessage = remindUnitTask(task, req);
  491. break;
  492. case "9":
  493. // 归档(没有这个东西)
  494. resultMessage = archiveTask(task, req);
  495. break;
  496. default:
  497. return "未知的操作类型";
  498. }
  499. return resultMessage;
  500. }
  501. /**
  502. * 通过,填写原因 修改状态
  503. */
  504. private String completeTask(CostProjectTask task) {
  505. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  506. if (!"0".equals(task.getPid())) {
  507. // 子任务 所有“是否必填”为“是”的资料“初审结果”均为“通过”.
  508. List<CostProjectTaskMaterial> costProjectTaskMaterials = costProjectTaskMaterialManager.listByTaskId(nTask.getId());
  509. boolean c = costProjectTaskMaterials.stream()
  510. .filter(item -> "1".equals(item.getIsRequired()) && "1".equals(item.getIsUpload()))
  511. .allMatch(
  512. item -> "1".equals(item.getAuditedStatus())
  513. );
  514. if (!c) {
  515. throw new RuntimeException("报送资料未全部通过!");
  516. }
  517. List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(nTask.getId());
  518. boolean d = costSurveyTemplateUploads.stream()
  519. .filter(item -> "1".equals(item.getIsRequired()) && "1".equals(item.getIsUpload()))
  520. .allMatch(
  521. item -> "1".equals(item.getAuditedStatus())
  522. );
  523. if (!d) {
  524. throw new RuntimeException("成本调查表未全部通过!");
  525. }
  526. } else {
  527. List<CostProjectTask> children = costProjectTaskManager.list(
  528. new LambdaQueryWrapper<CostProjectTask>()
  529. .eq(CostProjectTask::getPid, nTask.getId())
  530. );
  531. // 主任务:检查所有非中止的子任务是否都已办结
  532. boolean allChildrenCompleted = children.stream()
  533. .filter(child -> !TaskStatusConstant.SUSPENDED.getStatusCode().equals(child.getStatus()))
  534. .allMatch(child -> TaskStatusConstant.COMPLETED.getStatusCode().equals(child.getStatus()));
  535. if (!allChildrenCompleted) {
  536. throw new RuntimeException("子任务未全部办结,主任务无法办结");
  537. }
  538. }
  539. task.setStatus(TaskStatusConstant.COMPLETED.getStatusCode());
  540. costProjectTaskManager.updateById(task);
  541. // 发送通知
  542. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "通过";
  543. // 操作人
  544. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已通过" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  545. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  546. String orgId = getCurrentUserMainOrgId();
  547. Org org = orgManager.getById(orgId);
  548. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  549. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  550. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  551. return title;
  552. }
  553. /**
  554. * 退回,只修改状态为不通过,不修改节点(子任务操作)
  555. */
  556. private String returnToSubmit(CostProjectTask task, CostTaskPageReq req) {
  557. if ("0".equals(task.getPid())) {
  558. return "仅支持子任务进行此操作!";
  559. }
  560. // 通知内容组装
  561. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "退回";
  562. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  563. String orgId = getCurrentUserMainOrgId();
  564. Org org = orgManager.getById(orgId);
  565. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  566. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  567. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已退回" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  568. if (StringUtil.isNotEmpty(req.getContent())) {
  569. content += ",原因:" + req.getContent();
  570. }
  571. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  572. task.setStatus(TaskStatusConstant.NOT_PASSED.getStatusCode());
  573. costProjectTaskManager.updateById(task);
  574. return title;
  575. }
  576. /**
  577. * 中止/恢复,如果是主任务中止,所有子任务同步中止;如果是主任务恢复,所有子任务同步恢复
  578. */
  579. private String suspendTask(CostProjectTask task, CostTaskPageReq req) {
  580. // 恢复操作只支持主任务
  581. if (!"0".equals(task.getPid())) {
  582. throw new RuntimeException("仅支持主任务进行此操作");
  583. }
  584. // 判断是中止还是恢复
  585. String status = req.getStatus() == null || TaskStatusConstant.SUSPENDED.getStatusCode().equals(req.getStatus()) ? TaskStatusConstant.SUSPENDED.getStatusCode() : TaskStatusConstant.AUDITING.getStatusCode();
  586. // 中止操作:保存中止前的状态
  587. if (TaskStatusConstant.SUSPENDED.getStatusCode().equals(status)) {
  588. task.setPreSuspendStatus(task.getStatus());
  589. List<CostProjectTask> children = costProjectTaskManager.list(
  590. new LambdaQueryWrapper<CostProjectTask>()
  591. .eq(CostProjectTask::getPid, task.getId())
  592. .eq(CostProjectTask::getIsDeleted, "0")
  593. );
  594. for (CostProjectTask child : children) {
  595. child.setPreSuspendStatus(child.getStatus());
  596. child.setStatus(status);
  597. costProjectTaskManager.updateById(child);
  598. }
  599. } else {
  600. // 恢复操作:恢复到中止前的状态
  601. String preStatus = task.getPreSuspendStatus();
  602. task.setStatus(StringUtil.isNotEmpty(preStatus) ? preStatus : TaskStatusConstant.AUDITING.getStatusCode());
  603. task.setPreSuspendStatus(null);
  604. List<CostProjectTask> children = costProjectTaskManager.list(
  605. new LambdaQueryWrapper<CostProjectTask>()
  606. .eq(CostProjectTask::getPid, task.getId())
  607. .eq(CostProjectTask::getIsDeleted, "0")
  608. );
  609. for (CostProjectTask child : children) {
  610. String childPreStatus = child.getPreSuspendStatus();
  611. child.setStatus(StringUtil.isNotEmpty(childPreStatus) ? childPreStatus : TaskStatusConstant.AUDITING.getStatusCode());
  612. child.setPreSuspendStatus(null);
  613. costProjectTaskManager.updateById(child);
  614. }
  615. }
  616. task.setStatus(status);
  617. costProjectTaskManager.updateById(task);
  618. // 通知内容组装
  619. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + TaskStatusConstant.getStatusNameByCode(status);
  620. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已" + TaskStatusConstant.getStatusNameByCode(status) + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  621. if (StringUtil.isNotEmpty(req.getContent())) {
  622. content += ",原因:" + req.getContent();
  623. }
  624. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  625. String orgId = getCurrentUserMainOrgId();
  626. Org org = orgManager.getById(orgId);
  627. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  628. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  629. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  630. return title;
  631. }
  632. /**
  633. * 补充材料,发送通知+修改任务状态
  634. */
  635. private String supplementMaterial(CostProjectTask task, CostTaskPageReq req) {
  636. String currentNode = task.getCurrentNode();
  637. String title = NodeConstant.getNodeValueByKey(currentNode) + TaskStatusConstant.BCCL.getStatusName();
  638. String orgId = getCurrentUserMainOrgId();
  639. Org org = orgManager.getById(orgId);
  640. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  641. switch (currentNode) {
  642. // 集体审议节点:支持指定多个子任务补充材料
  643. case "jtsy":
  644. if (StringUtil.isNotEmpty(req.getAuditedUnitIds())) {
  645. String[] childUnitIds = req.getAuditedUnitIds().split(",");
  646. List<String> unitNames = new java.util.ArrayList<>();
  647. for (String auditedUnitId : childUnitIds) {
  648. CostProjectTask childTask = costProjectTaskManager.getOne(
  649. new LambdaQueryWrapper<CostProjectTask>()
  650. .eq(CostProjectTask::getPid, task.getId())
  651. .eq(CostProjectTask::getAuditedUnitId, auditedUnitId)
  652. );
  653. if (childTask == null) {
  654. throw new RuntimeException("未知的子任务");
  655. }
  656. // 检查子任务是否已中止
  657. if (TaskStatusConstant.SUSPENDED.getStatusCode().equals(childTask.getStatus())) {
  658. throw new RuntimeException("子任务已中止,无法补充材料:" + childTask.getAuditedUnitName());
  659. }
  660. // 更新子任务状态为补充材料
  661. childTask.setStatus(TaskStatusConstant.BCCL.getStatusCode());
  662. costProjectTaskManager.updateById(childTask);
  663. // 通知内容组装(针对子任务对应的单位)
  664. String childContent = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求" + childTask.getAuditedUnitName() + "补充材料,项目(" + task.getProjectName() + ")";
  665. String childEnterpriseId = childTask.getAuditedUnitId() == null ? "" : childTask.getAuditedUnitId();
  666. String childSendTarget = childTask.getCreateBy() == null ? "" : childTask.getCreateBy();
  667. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, childContent, childEnterpriseId, noticeSource, childSendTarget);
  668. // 收集单位名称
  669. if (StringUtil.isNotEmpty(childTask.getAuditedUnitName())) {
  670. unitNames.add(childTask.getAuditedUnitName());
  671. }
  672. }
  673. // 返回结果,包含所有单位名称
  674. String unitNamesStr = unitNames.isEmpty() ? "" : String.join("、", unitNames);
  675. return title + "(单位:" + unitNamesStr + ")";
  676. }
  677. default:
  678. // 检查任务是否已中止
  679. if (TaskStatusConstant.SUSPENDED.getStatusCode().equals(task.getStatus())) {
  680. throw new RuntimeException("任务已中止,无法补充材料");
  681. }
  682. task.setStatus(TaskStatusConstant.BCCL.getStatusCode());
  683. costProjectTaskManager.updateById(task);
  684. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求" + task.getAuditedUnitName() + "补充材料,项目(" + task.getProjectName() + ")";
  685. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  686. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  687. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  688. return title;
  689. }
  690. }
  691. /**
  692. * 退回上一步,修改状态和节点(主任务操作,子任务同步节点流转)
  693. */
  694. private String backPreToSubmit(CostProjectTask task, CostTaskPageReq req) {
  695. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  696. if (!"0".equals(task.getPid())) {
  697. return "仅支持主任务进行此操作";
  698. }
  699. // 获取退回后的上一节点
  700. NodeConstant prevNode = NodeConstant.getPrevNode(nTask.getCurrentNode());
  701. if (prevNode == null) {
  702. throw new RuntimeException("当前节点已是第一步,无法退回");
  703. }
  704. String prevNodeStatus = prevNode.getNodeKey();
  705. // 更新流程节点时间:清空当前节点的结束时间,重置上一节点的开始时间
  706. CostProjectProccess proccess = costProjectProccessManager.getOne(
  707. new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
  708. );
  709. // 清空当前节点的实际结束时间和操作信息
  710. CostProjectProccessNode currentNode = costProjectProccessNodeManager.getOne(
  711. new LambdaQueryWrapper<CostProjectProccessNode>()
  712. .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
  713. .eq(CostProjectProccessNode::getProcessNodeKey, task.getCurrentNode())
  714. );
  715. if (currentNode != null) {
  716. currentNode.setActEndTime(null);
  717. currentNode.setActUserIds(null);
  718. currentNode.setActUserNames(null);
  719. currentNode.setActRemarks(null);
  720. costProjectProccessNodeManager.updateById(currentNode);
  721. }
  722. // 重置上一节点的开始时间
  723. CostProjectProccessNode prevNodeObj = costProjectProccessNodeManager.getOne(
  724. new LambdaQueryWrapper<CostProjectProccessNode>()
  725. .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
  726. .eq(CostProjectProccessNode::getProcessNodeKey, prevNodeStatus)
  727. );
  728. if (prevNodeObj != null) {
  729. prevNodeObj.setActStartTime(LocalDateTime.now());
  730. costProjectProccessNodeManager.updateById(prevNodeObj);
  731. }
  732. // 主任务退回上一步,重置归档状态
  733. nTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  734. nTask.setCurrentNode(prevNodeStatus);
  735. nTask.setIsGd("0");
  736. costProjectTaskManager.updateById(nTask);
  737. // 子任务同步节点流转,并根据退回后的节点设置正确的状态
  738. List<CostProjectTask> children = costProjectTaskManager.list(
  739. new LambdaQueryWrapper<CostProjectTask>()
  740. .eq(CostProjectTask::getPid, nTask.getId())
  741. .eq(CostProjectTask::getIsDeleted, "0")
  742. );
  743. // 根据退回后的节点,设置子任务状态
  744. String childStatus = "";
  745. switch (prevNodeStatus) {
  746. case "yjfk":
  747. childStatus = TaskStatusConstant.WAIT_FEEDBACK.getStatusCode();
  748. break;
  749. case "jtsy":
  750. case "cjbg":
  751. case "gd":
  752. childStatus = TaskStatusConstant.COMPLETED.getStatusCode();
  753. break;
  754. default:
  755. childStatus = TaskStatusConstant.AUDITING.getStatusCode();
  756. break;
  757. }
  758. // 同步所有非中止状态的子任务
  759. for (CostProjectTask child : children) {
  760. if (!child.getStatus().equals(TaskStatusConstant.SUSPENDED.getStatusCode())) {
  761. child.setStatus(childStatus);
  762. child.setCurrentNode(prevNodeStatus);
  763. costProjectTaskManager.updateById(child);
  764. // 如果退回到意见反馈节点,通知企业
  765. if ("yjfk".equals(prevNodeStatus) && StringUtil.isNotEmpty(child.getAuditedUnitId())) {
  766. AuditedUnit auditedUnit = auditedUnitManager.getOne(
  767. new LambdaQueryWrapper<AuditedUnit>()
  768. .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
  769. .eq(AuditedUnit::getIsDeleted, "0")
  770. );
  771. if (auditedUnit != null && StringUtil.isNotEmpty(auditedUnit.getAccount())) {
  772. String noticeTitle = "意见反馈通知";
  773. String noticeContent = "您的项目(" + child.getProjectName() + ")需要反馈意见,请及时处理";
  774. String orgId = getCurrentUserMainOrgId();
  775. Org org = orgManager.getById(orgId);
  776. String noticeSource = (org != null ? org.getName() : "系统") + " " + AuthenticationUtil.getCurrentUserFullname();
  777. costNoticeManager.sendNotice(
  778. child.getProjectId(),
  779. child.getId(),
  780. "1",
  781. noticeTitle,
  782. noticeContent,
  783. child.getAuditedUnitId(),
  784. noticeSource,
  785. auditedUnit.getAccount()
  786. );
  787. }
  788. }
  789. }
  790. }
  791. // 通知内容组装
  792. String title = "已退回至" + NodeConstant.getNodeValueByKey(prevNodeStatus);
  793. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  794. String orgId = getCurrentUserMainOrgId();
  795. Org org = orgManager.getById(orgId);
  796. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  797. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  798. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]已退回至[" + NodeConstant.getNodeValueByKey(prevNodeStatus) + "]," + task.getProjectName();
  799. if (StringUtil.isNotEmpty(req.getContent())) {
  800. content += ",原因:" + req.getContent();
  801. }
  802. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  803. return title;
  804. }
  805. /**
  806. * 扭转下一步,修改状态和节点(主任务操作,子任务同步节点流转)
  807. * 自动完成办结操作并扭转到下一步
  808. */
  809. private String toNextSubmit(CostProjectTask task, CostTaskPageReq req) {
  810. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  811. if (!"0".equals(task.getPid())) {
  812. return "仅支持主任务进行此操作";
  813. }
  814. // 获取下一节点
  815. NodeConstant nextNode = NodeConstant.getNextNode(nTask.getCurrentNode());
  816. if (nextNode == null) {
  817. throw new RuntimeException("当前节点已是最后一步,无法扭转");
  818. }
  819. String nextNodeStatus = nextNode.getNodeKey();
  820. // 获取所有子任务
  821. List<CostProjectTask> children = costProjectTaskManager.list(
  822. new LambdaQueryWrapper<CostProjectTask>()
  823. .eq(CostProjectTask::getPid, nTask.getId())
  824. .eq(CostProjectTask::getIsDeleted, "0")
  825. );
  826. // 检查所有非中止的子任务是否都已办结
  827. boolean allChildrenCompleted = children.stream()
  828. .filter(child -> !TaskStatusConstant.SUSPENDED.getStatusCode().equals(child.getStatus()))
  829. .allMatch(child -> TaskStatusConstant.COMPLETED.getStatusCode().equals(child.getStatus()));
  830. if (!allChildrenCompleted) {
  831. throw new RuntimeException("子任务未全部办结,主任务无法扭转");
  832. }
  833. // 先完成当前节点的办结操作(如果未办结)
  834. if (!nTask.getStatus().equals(TaskStatusConstant.COMPLETED.getStatusCode())) {
  835. nTask.setStatus(TaskStatusConstant.COMPLETED.getStatusCode());
  836. costProjectTaskManager.updateById(nTask);
  837. }
  838. // 修改当前节点的结束时间
  839. CostProjectProccess proccess = costProjectProccessManager.getOne(
  840. new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
  841. );
  842. CostProjectProccessNode one = costProjectProccessNodeManager.getOne(
  843. new LambdaQueryWrapper<CostProjectProccessNode>()
  844. .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
  845. .eq(CostProjectProccessNode::getProcessNodeKey, task.getCurrentNode())
  846. );
  847. one.setActUserIds(req.getUserIds());
  848. one.setActUserNames(req.getUserIdNames());
  849. one.setActRemarks(req.getContent());
  850. one.setActEndTime(LocalDateTime.now());
  851. costProjectProccessNodeManager.updateById(one);
  852. // 主任务扭转到下一节点
  853. nTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  854. nTask.setCurrentNode(nextNodeStatus);
  855. nTask.setIsGd("0");
  856. costProjectTaskManager.updateById(nTask);
  857. // 设置下一节点的开始时间
  858. CostProjectProccessNode two = costProjectProccessNodeManager.getOne(
  859. new LambdaQueryWrapper<CostProjectProccessNode>()
  860. .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
  861. .eq(CostProjectProccessNode::getProcessNodeKey, nextNodeStatus)
  862. );
  863. two.setActStartTime(LocalDateTime.now());
  864. costProjectProccessNodeManager.updateById(two);
  865. // 子任务同步节点流转,根据节点设置对应状态
  866. String childStatus = "";
  867. switch (nextNodeStatus) {
  868. case "yjfk":
  869. childStatus = TaskStatusConstant.WAIT_FEEDBACK.getStatusCode();
  870. break;
  871. case "jtsy":
  872. case "cjbg":
  873. case "gd":
  874. childStatus = TaskStatusConstant.COMPLETED.getStatusCode();
  875. break;
  876. default:
  877. childStatus = TaskStatusConstant.AUDITING.getStatusCode();
  878. break;
  879. }
  880. // 同步所有非中止状态的子任务
  881. for (CostProjectTask child : children) {
  882. if (!child.getStatus().equals(TaskStatusConstant.SUSPENDED.getStatusCode())) {
  883. child.setStatus(childStatus);
  884. child.setCurrentNode(nextNodeStatus);
  885. costProjectTaskManager.updateById(child);
  886. // 如果扭转到意见反馈节点,通知企业
  887. if ("yjfk".equals(nextNodeStatus) && StringUtil.isNotEmpty(child.getAuditedUnitId())) {
  888. AuditedUnit auditedUnit = auditedUnitManager.getOne(
  889. new LambdaQueryWrapper<AuditedUnit>()
  890. .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
  891. .eq(AuditedUnit::getIsDeleted, "0")
  892. );
  893. if (auditedUnit != null && StringUtil.isNotEmpty(auditedUnit.getAccount())) {
  894. String noticeTitle = "意见反馈通知";
  895. String noticeContent = "您的项目(" + child.getProjectName() + ")需要反馈意见,请及时处理";
  896. String orgId = getCurrentUserMainOrgId();
  897. Org org = orgManager.getById(orgId);
  898. String noticeSource = (org != null ? org.getName() : "系统") + " " + AuthenticationUtil.getCurrentUserFullname();
  899. costNoticeManager.sendNotice(
  900. child.getProjectId(),
  901. child.getId(),
  902. "1",
  903. noticeTitle,
  904. noticeContent,
  905. child.getAuditedUnitId(),
  906. noticeSource,
  907. auditedUnit.getAccount()
  908. );
  909. }
  910. }
  911. }
  912. }
  913. // 通知内容组装
  914. String title = NodeConstant.getNodeValueByKey(nextNodeStatus) + "已开始";
  915. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  916. String orgId = getCurrentUserMainOrgId();
  917. Org org = orgManager.getById(orgId);
  918. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  919. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  920. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]已办结并扭转至[" + NodeConstant.getNodeValueByKey(nextNodeStatus) + "]," + task.getProjectName();
  921. if (StringUtil.isNotEmpty(req.getContent())) {
  922. content += ",备注:" + req.getContent();
  923. }
  924. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  925. return title;
  926. }
  927. @Override
  928. public List<CostProjectTask> getDoList(String projectId) {
  929. // 获取当前用户
  930. IUser currentUser = ContextUtil.getCurrentUser();
  931. String currentUserId = currentUser.getUserId();
  932. // 1. 先查询当前用户有权限的立项(负责人或项目组成员)
  933. LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
  934. approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
  935. approvalQueryWrapper.and(wrapper -> wrapper
  936. .eq(CostProjectApproval::getLeaderId, currentUserId)
  937. .or(projectMembersWrapper -> {
  938. projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
  939. })
  940. );
  941. List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);
  942. // 如果没有权限的立项,返回空结果
  943. if (accessibleApprovals.isEmpty()) {
  944. return new ArrayList<>();
  945. }
  946. // 提取有权限的立项ID列表
  947. List<String> accessibleProjectIds = accessibleApprovals.stream()
  948. .map(CostProjectApproval::getProjectId)
  949. .distinct()
  950. .collect(java.util.stream.Collectors.toList());
  951. // 2. 构建任务查询条件
  952. LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  953. // 查询未删除的记录
  954. queryWrapper.eq(CostProjectTask::getIsDeleted, "0");
  955. // 查询子任务
  956. queryWrapper.ne(CostProjectTask::getPid, "0");
  957. // 只查询当前用户有权限的立项对应的任务
  958. queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);
  959. // 根据请求参数添加查询条件
  960. queryWrapper.eq(projectId != null, CostProjectTask::getProjectId, projectId);
  961. // 按创建时间倒序排列
  962. queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
  963. List<CostProjectTask> list = costProjectTaskManager.list(queryWrapper);
  964. for (CostProjectTask rootTask : list) {
  965. rootTask.setStatusName(TaskStatusConstant.getStatusNameByCode(rootTask.getStatus()));
  966. rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
  967. }
  968. return list;
  969. }
  970. @Override
  971. public List<Map<String, Object>> getDoChartList(String year, String region) {
  972. List<CostCatalog> list = costCatalogManager.list(
  973. new LambdaQueryWrapper<CostCatalog>().eq(CostCatalog::getParentId, "1969351600934948833")
  974. );
  975. List<Map<String, Object>> maps = new ArrayList<>();
  976. for (CostCatalog costCatalog : list) {
  977. // 递归获取所有下级目录ID
  978. List<String> allCatalogIds = getAllChildCatalogIds(costCatalog.getCatalogId());
  979. // 通过项目立项表关联查询目录
  980. List<CostProjectApproval> approvals = costProjectApprovalManager.list(
  981. new LambdaQueryWrapper<CostProjectApproval>()
  982. .in(CostProjectApproval::getCatalogId, allCatalogIds)
  983. .eq(CostProjectApproval::getIsDeleted, "0")
  984. );
  985. if (approvals.isEmpty()) {
  986. Map<String, Object> map = new HashMap<>();
  987. map.put("name", costCatalog.getCatalogName());
  988. map.put("finish", 0);
  989. map.put("nFinish", 0);
  990. maps.add(map);
  991. continue;
  992. }
  993. List<String> projectIds = approvals.stream()
  994. .map(CostProjectApproval::getProjectId)
  995. .collect(Collectors.toList());
  996. // 查询子任务
  997. LambdaQueryWrapper<CostProjectTask> taskQuery = new LambdaQueryWrapper<>();
  998. taskQuery.eq(CostProjectTask::getIsDeleted, "0")
  999. .ne(CostProjectTask::getPid, "0")
  1000. .in(CostProjectTask::getProjectId, projectIds);
  1001. if (StringUtil.isNotEmpty(year)) {
  1002. taskQuery.eq(CostProjectTask::getYear, year);
  1003. }
  1004. List<CostProjectTask> tasks = this.list(taskQuery);
  1005. // 统计完成和未完成的任务
  1006. long finishCount = tasks.stream()
  1007. .filter(task -> TaskStatusConstant.COMPLETED.getStatusCode().equals(task.getStatus()))
  1008. .count();
  1009. long nFinishCount = tasks.size() - finishCount;
  1010. Map<String, Object> map = new HashMap<>();
  1011. map.put("name", costCatalog.getCatalogName());
  1012. map.put("finish", finishCount);
  1013. map.put("nFinish", nFinishCount);
  1014. maps.add(map);
  1015. }
  1016. return maps;
  1017. }
  1018. @Override
  1019. public List<CostNotice> getDoMsgList() {
  1020. IUser currentUser = ContextUtil.getCurrentUser();
  1021. String currentUserId = currentUser.getUserId();
  1022. AuditedUnit unit = auditedUnitManager.getOne(
  1023. new LambdaQueryWrapper<AuditedUnit>()
  1024. .eq(AuditedUnit::getAccount, currentUserId)
  1025. .last("limit 1")
  1026. );
  1027. LambdaQueryWrapper<CostNotice> queryWrapper = new LambdaQueryWrapper<>();
  1028. queryWrapper.eq(CostNotice::getIsDeleted, "0");
  1029. if (unit != null) {
  1030. queryWrapper.and(q -> q.eq(CostNotice::getEnterpriseId, unit.getUnitId())
  1031. .or()
  1032. .eq(CostNotice::getSendTarget, currentUserId));
  1033. } else {
  1034. // unit 为空时,只看是否发给当前用户
  1035. queryWrapper.eq(CostNotice::getSendTarget, currentUserId);
  1036. }
  1037. queryWrapper.orderByDesc(CostNotice::getCreateTime)
  1038. .last("limit 8");
  1039. return costNoticeManager.list(queryWrapper);
  1040. }
  1041. @Override
  1042. public IPage<CostProjectTask> pageListForReviewTaskChild(CostTaskReviewPageReq req) {
  1043. // 获取当前用户
  1044. IUser currentUser = ContextUtil.getCurrentUser();
  1045. String currentUserId = currentUser.getUserId();
  1046. // 1. 先查询当前用户有权限的立项(负责人或项目组成员)
  1047. LambdaQueryWrapper<CostProjectApproval> approvalQueryWrapper = new LambdaQueryWrapper<>();
  1048. approvalQueryWrapper.eq(CostProjectApproval::getIsDeleted, "0");
  1049. approvalQueryWrapper.and(wrapper -> wrapper
  1050. .eq(CostProjectApproval::getLeaderId, currentUserId)
  1051. .or(projectMembersWrapper -> {
  1052. projectMembersWrapper.like(CostProjectApproval::getProjectMembers, currentUserId);
  1053. })
  1054. );
  1055. List<CostProjectApproval> accessibleApprovals = costProjectApprovalManager.list(approvalQueryWrapper);
  1056. // 如果没有权限的立项,返回空结果
  1057. if (accessibleApprovals.isEmpty()) {
  1058. return new Page<>(req.getPageNum(), req.getPageSize());
  1059. }
  1060. // 提取有权限的立项ID列表
  1061. List<String> accessibleProjectIds = accessibleApprovals.stream()
  1062. .map(CostProjectApproval::getProjectId)
  1063. .distinct()
  1064. .collect(java.util.stream.Collectors.toList());
  1065. if (req.getAreaCode() != null) {
  1066. List<CostProjectTaskApproval> list = costProjectTaskApprovalManager.list(
  1067. new LambdaQueryWrapper<CostProjectTaskApproval>().eq(CostProjectTaskApproval::getAreaCode, req.getAreaCode())
  1068. );
  1069. if (list.isEmpty()) {
  1070. return new Page<>(req.getPageNum(), req.getPageSize());
  1071. }
  1072. List<String> projectIds =
  1073. list.stream().map(CostProjectTaskApproval::getProjectId).collect(Collectors.toList());
  1074. accessibleProjectIds.addAll(projectIds);
  1075. }
  1076. // 2. 构建任务查询条件
  1077. LambdaQueryWrapper<CostProjectTask> queryWrapper = new LambdaQueryWrapper<>();
  1078. // 查询未删除的记录
  1079. queryWrapper.eq(CostProjectTask::getIsDeleted, "0");
  1080. // 查询根任务(pid为0)
  1081. queryWrapper.ne(CostProjectTask::getPid, "0");
  1082. // 只查询当前用户有权限的立项对应的任务
  1083. queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);
  1084. // 根据请求参数添加查询条件
  1085. if (StringUtil.isNotEmpty(req.getProjectName())) {
  1086. queryWrapper.like(CostProjectTask::getProjectName, req.getProjectName());
  1087. }
  1088. if (StringUtil.isNotEmpty(req.getAuditedUnitName())) {
  1089. queryWrapper.like(CostProjectTask::getAuditedUnitName, req.getAuditedUnitName());
  1090. }
  1091. if (StringUtil.isNotEmpty(req.getStatus())) {
  1092. queryWrapper.eq(CostProjectTask::getStatus, req.getStatus());
  1093. }
  1094. if (StringUtil.isNotEmpty(req.getYear())) {
  1095. queryWrapper.eq(CostProjectTask::getYear, req.getYear());
  1096. }
  1097. queryWrapper.eq(req.getCurrentNode() != null, CostProjectTask::getCurrentNode, req.getCurrentNode());
  1098. queryWrapper.ne(req.getNCurrentNode() != null, CostProjectTask::getCurrentNode, req.getNCurrentNode());
  1099. queryWrapper.ne(req.getNStatus() != null, CostProjectTask::getStatus, req.getNStatus());
  1100. // 按创建时间倒序排列
  1101. queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
  1102. Page<CostProjectTask> page = new Page<>(req.getPageNum(), req.getPageSize());
  1103. IPage<CostProjectTask> result = costProjectTaskManager.page(page, queryWrapper);
  1104. List<CostProjectTask> rootList = result.getRecords();
  1105. if (rootList == null || rootList.isEmpty()) {
  1106. return result;
  1107. }
  1108. Set<String> allProjectIds = new HashSet<>();
  1109. rootList.forEach(t -> allProjectIds.add(t.getProjectId()));
  1110. List<CostProjectApproval> approvalList = costProjectApprovalManager.list(
  1111. new LambdaQueryWrapper<CostProjectApproval>()
  1112. .in(CostProjectApproval::getProjectId, allProjectIds)
  1113. );
  1114. Map<String, CostProjectApproval> approvalMap =
  1115. approvalList.stream().collect(
  1116. Collectors.toMap(CostProjectApproval::getProjectId, v -> v)
  1117. );
  1118. for (CostProjectTask rootTask : rootList) {
  1119. // 任务状态
  1120. rootTask.setStatusName(TaskStatusConstant.getStatusNameByCode(rootTask.getStatus()));
  1121. rootTask.setCurrentNodeName(NodeConstant.getNodeValueByKey(rootTask.getCurrentNode()));
  1122. rootTask.setWarningStatus(calculateWarningStatus(rootTask));
  1123. // 找根任务
  1124. String pid = rootTask.getPid();
  1125. if (StringUtils.isNotBlank(pid)) {
  1126. CostProjectTask rrootTask = this.getById(pid);
  1127. if (rrootTask != null) {
  1128. rootTask.setAuditPeriod(rrootTask.getAuditPeriod());
  1129. }
  1130. }
  1131. // 设置目录
  1132. CostProjectApproval rootDetail = approvalMap.get(rootTask.getProjectId());
  1133. if (rootDetail != null) {
  1134. rootTask.setCatalogId(rootDetail.getCatalogId());
  1135. if (StringUtil.isNotEmpty(rootDetail.getAreaCode())) {
  1136. CostDistrict district = costDistrictManager.getOne(
  1137. new LambdaQueryWrapper<CostDistrict>()
  1138. .eq(CostDistrict::getCode, rootDetail.getAreaCode())
  1139. );
  1140. rootTask.setAreaName(district != null ? district.getName() : "山西省");
  1141. }
  1142. }
  1143. }
  1144. return result;
  1145. }
  1146. @Override
  1147. public List<CostProjectTask> findTaskByProjectId(String projectId, String enterpriseId) {
  1148. QueryWrapper<CostProjectTask> wrapper = new QueryWrapper<>();
  1149. wrapper.eq("project_id",projectId);
  1150. wrapper.eq("audited_unit_id",enterpriseId);
  1151. return this.list(wrapper);
  1152. }
  1153. private List<String> getAllChildCatalogIds(String catalogId) {
  1154. List<String> result = new ArrayList<>();
  1155. result.add(catalogId);
  1156. List<CostCatalog> children = costCatalogManager.list(
  1157. new LambdaQueryWrapper<CostCatalog>().eq(CostCatalog::getParentId, catalogId)
  1158. );
  1159. for (CostCatalog child : children) {
  1160. result.addAll(getAllChildCatalogIds(child.getCatalogId()));
  1161. }
  1162. return result;
  1163. }
  1164. /**
  1165. * 催办任务,仅记录消息
  1166. *
  1167. * @param task 任务对象
  1168. * @param req 请求参数
  1169. * @return 催办结果消息
  1170. */
  1171. private String remindTask(CostProjectTask task, CostTaskPageReq req) {
  1172. // 检查是否提供了用户ID
  1173. if (StringUtil.isEmpty(req.getUserIds())) {
  1174. throw new RuntimeException("未指定催办人员");
  1175. }
  1176. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "催办";
  1177. // 分割用户ID并逐个发送通知
  1178. for (String userId : req.getUserIds().split(",")) {
  1179. // 发送催办通知
  1180. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "催办" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  1181. if (StringUtil.isNotEmpty(req.getContent())) {
  1182. content += ",原因:" + req.getContent();
  1183. }
  1184. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  1185. String orgId = getCurrentUserMainOrgId();
  1186. Org org = orgManager.getById(orgId);
  1187. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  1188. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  1189. // 使用传入的用户ID作为发送目标
  1190. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  1191. }
  1192. return title;
  1193. }
  1194. /**
  1195. * 催办任务,仅记录消息
  1196. *
  1197. * @param task 任务对象
  1198. * @param req 请求参数
  1199. * @return 催办结果消息
  1200. */
  1201. private String remindUnitTask(CostProjectTask task, CostTaskPageReq req) {
  1202. // 检查是否提供了用户ID
  1203. if (StringUtil.isEmpty(req.getAuditedUnitIds())) {
  1204. throw new RuntimeException("未指定催报企业");
  1205. }
  1206. String title = NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "催办";
  1207. // 分割用户ID并逐个发送通知
  1208. for (String unitId : req.getAuditedUnitIds().split(",")) {
  1209. // 发送催办通知
  1210. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "催报" + task.getAuditedUnitName() + "的项目(" + task.getProjectName() + ")";
  1211. if (StringUtil.isNotEmpty(req.getContent())) {
  1212. content += ",原因:" + req.getContent();
  1213. }
  1214. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  1215. String orgId = getCurrentUserMainOrgId();
  1216. Org org = orgManager.getById(orgId);
  1217. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  1218. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  1219. // 使用传入的用户ID作为发送目标
  1220. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  1221. }
  1222. return title;
  1223. }
  1224. /**
  1225. * 复核,主任务退回到实地审核节点,子任务恢复到流程初始状态
  1226. *
  1227. * @param task 任务对象
  1228. * @param req 请求参数
  1229. * @return 复核结果消息
  1230. */
  1231. private String reviewTask(CostProjectTask task, CostTaskPageReq req) {
  1232. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  1233. if (!"0".equals(task.getPid())) {
  1234. return "仅支持主任务进行此操作";
  1235. }
  1236. // 获取实地审核节点
  1237. String reviewNodeKey = NodeConstant.sdshenhe.getNodeKey();
  1238. // 更新流程节点时间:清空当前节点及之后节点的时间,重置实地审核节点的开始时间
  1239. CostProjectProccess proccess = costProjectProccessManager.getOne(
  1240. new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
  1241. );
  1242. if (proccess != null) {
  1243. // 清空当前节点的实际结束时间和操作信息
  1244. CostProjectProccessNode currentNode = costProjectProccessNodeManager.getOne(
  1245. new LambdaQueryWrapper<CostProjectProccessNode>()
  1246. .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
  1247. .eq(CostProjectProccessNode::getProcessNodeKey, task.getCurrentNode())
  1248. );
  1249. if (currentNode != null) {
  1250. currentNode.setActEndTime(null);
  1251. currentNode.setActUserIds(null);
  1252. currentNode.setActUserNames(null);
  1253. currentNode.setActRemarks(null);
  1254. costProjectProccessNodeManager.updateById(currentNode);
  1255. }
  1256. // 清空实地审核之后所有节点的时间和操作信息
  1257. boolean foundReviewNode = false;
  1258. for (NodeConstant nodeConstant : NodeConstant.values()) {
  1259. if (nodeConstant.getNodeKey().equals(reviewNodeKey)) {
  1260. foundReviewNode = true;
  1261. continue;
  1262. }
  1263. if (foundReviewNode) {
  1264. CostProjectProccessNode node = costProjectProccessNodeManager.getOne(
  1265. new LambdaQueryWrapper<CostProjectProccessNode>()
  1266. .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
  1267. .eq(CostProjectProccessNode::getProcessNodeKey, nodeConstant.getNodeKey())
  1268. );
  1269. if (node != null) {
  1270. node.setActStartTime(null);
  1271. node.setActEndTime(null);
  1272. node.setActUserIds(null);
  1273. node.setActUserNames(null);
  1274. node.setActRemarks(null);
  1275. costProjectProccessNodeManager.updateById(node);
  1276. }
  1277. }
  1278. }
  1279. // 重置实地审核节点的开始时间
  1280. CostProjectProccessNode reviewNode = costProjectProccessNodeManager.getOne(
  1281. new LambdaQueryWrapper<CostProjectProccessNode>()
  1282. .eq(CostProjectProccessNode::getProcessId, proccess.getProcessId())
  1283. .eq(CostProjectProccessNode::getProcessNodeKey, reviewNodeKey)
  1284. );
  1285. if (reviewNode != null) {
  1286. reviewNode.setActStartTime(LocalDateTime.now());
  1287. costProjectProccessNodeManager.updateById(reviewNode);
  1288. }
  1289. }
  1290. // 主任务退回到实地审核节点
  1291. nTask.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  1292. nTask.setCurrentNode(reviewNodeKey);
  1293. nTask.setIsGd("0");
  1294. costProjectTaskManager.updateById(nTask);
  1295. // 子任务恢复到流程初始状态(实地审核节点,审核中状态)
  1296. List<CostProjectTask> children = costProjectTaskManager.list(
  1297. new LambdaQueryWrapper<CostProjectTask>()
  1298. .eq(CostProjectTask::getPid, nTask.getId())
  1299. .eq(CostProjectTask::getIsDeleted, "0")
  1300. );
  1301. String initialNodeKey = NodeConstant.sdshenhe.getNodeKey();
  1302. for (CostProjectTask child : children) {
  1303. // 非中止状态的子任务恢复到初始状态
  1304. if (!child.getStatus().equals(TaskStatusConstant.SUSPENDED.getStatusCode())) {
  1305. child.setStatus(TaskStatusConstant.AUDITING.getStatusCode());
  1306. child.setCurrentNode(initialNodeKey);
  1307. costProjectTaskManager.updateById(child);
  1308. }
  1309. }
  1310. // 发送通知
  1311. String title = "复核-已退回至" + NodeConstant.getNodeValueByKey(reviewNodeKey);
  1312. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  1313. String orgId = getCurrentUserMainOrgId();
  1314. Org org = orgManager.getById(orgId);
  1315. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  1316. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  1317. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "要求复核,已退回至[" + NodeConstant.getNodeValueByKey(reviewNodeKey) + "]," + task.getProjectName();
  1318. if (StringUtil.isNotEmpty(req.getContent())) {
  1319. content += ",原因:" + req.getContent();
  1320. }
  1321. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  1322. return title;
  1323. }
  1324. /**
  1325. * 归档任务,修改任务归档状态并异步生成资料归纳主表
  1326. *
  1327. * @param task 任务对象
  1328. * @param req 请求参数
  1329. * @return 归档结果消息
  1330. */
  1331. private String archiveTask(CostProjectTask task, CostTaskPageReq req) {
  1332. CostProjectTask nTask = costProjectTaskManager.getById(task.getId());
  1333. if (!"0".equals(task.getPid())) {
  1334. return "仅支持主任务进行归档操作";
  1335. }
  1336. // 检查任务是否已办结
  1337. if (!TaskStatusConstant.COMPLETED.getStatusCode().equals(nTask.getStatus())) {
  1338. throw new RuntimeException("任务未办结,无法归档");
  1339. }
  1340. // 检查所有子任务是否都已办结
  1341. List<CostProjectTask> children = costProjectTaskManager.list(
  1342. new LambdaQueryWrapper<CostProjectTask>()
  1343. .eq(CostProjectTask::getPid, nTask.getId())
  1344. .eq(CostProjectTask::getIsDeleted, "0")
  1345. );
  1346. boolean allChildrenCompleted = children.stream()
  1347. .filter(child -> !TaskStatusConstant.SUSPENDED.getStatusCode().equals(child.getStatus()))
  1348. .allMatch(child -> TaskStatusConstant.COMPLETED.getStatusCode().equals(child.getStatus()));
  1349. if (!allChildrenCompleted) {
  1350. throw new RuntimeException("子任务未全部办结,主任务无法归档");
  1351. }
  1352. // 更新主任务归档状态
  1353. nTask.setIsGd("1");
  1354. costProjectTaskManager.updateById(nTask);
  1355. // 发送通知
  1356. String title = "任务已归档";
  1357. String content = "[" + NodeConstant.getNodeValueByKey(task.getCurrentNode()) + "]" + AuthenticationUtil.getCurrentUserFullname() + "已归档" + task.getProjectName();
  1358. if (StringUtil.isNotEmpty(req.getContent())) {
  1359. content += ",备注:" + req.getContent();
  1360. }
  1361. String enterpriseId = task.getAuditedUnitId() == null ? "" : task.getAuditedUnitId();
  1362. String orgId = getCurrentUserMainOrgId();
  1363. Org org = orgManager.getById(orgId);
  1364. String noticeSource = (org.getName()) + " " + AuthenticationUtil.getCurrentUserFullname();
  1365. String sendTarget = task.getCreateBy() == null ? "" : task.getCreateBy();
  1366. costNoticeManager.sendNotice(task.getProjectId(), task.getId(), "1", title, content, enterpriseId, noticeSource, sendTarget);
  1367. return title;
  1368. }
  1369. }