MesDevicePreventTaskService.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. package com.jeesite.modules.mes.service;
  2. import java.util.ArrayList;
  3. import java.util.Calendar;
  4. import java.util.Date;
  5. import java.util.List;
  6. import cn.hutool.core.util.IdUtil;
  7. import com.jeesite.common.lang.StringUtils;
  8. import com.jeesite.common.service.ServiceException;
  9. import com.jeesite.common.mybatis.mapper.query.QueryType;
  10. import com.jeesite.modules.mes.dao.MesDeviceConsumableRecordDao;
  11. import com.jeesite.modules.mes.entity.MesDeviceConsumableRecord;
  12. import com.jeesite.modules.mes.entity.MesDevicePreventTaskUser;
  13. import com.jeesite.modules.sys.entity.User;
  14. import com.jeesite.modules.sys.utils.UserUtils;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.stereotype.Service;
  17. import org.springframework.transaction.annotation.Transactional;
  18. import com.jeesite.common.entity.Page;
  19. import com.jeesite.common.service.CrudService;
  20. import com.jeesite.modules.mes.entity.MesDevicePreventTask;
  21. import com.jeesite.modules.mes.dao.MesDevicePreventTaskDao;
  22. import com.jeesite.modules.file.utils.FileUploadUtils;
  23. /**
  24. * 预防性维修计划Service
  25. * @author hzd
  26. * @version 2023-08-17
  27. */
  28. @Service
  29. public class MesDevicePreventTaskService extends CrudService<MesDevicePreventTaskDao, MesDevicePreventTask> {
  30. @Autowired
  31. private MesDeviceConsumableRecordDao mesDeviceConsumableRecordDao;
  32. @Autowired
  33. private MesDevicePreventTaskUserService mesDevicePreventTaskUserService;
  34. /**
  35. * 获取单条数据
  36. * @param mesDevicePreventTask
  37. * @return
  38. */
  39. @Override
  40. public MesDevicePreventTask get(MesDevicePreventTask mesDevicePreventTask) {
  41. MesDevicePreventTask entity = super.get(mesDevicePreventTask);
  42. if (entity != null){
  43. MesDeviceConsumableRecord mesDeviceConsumableRecord = new MesDeviceConsumableRecord();
  44. mesDeviceConsumableRecord.setStatus(MesDeviceConsumableRecord.STATUS_NORMAL);
  45. mesDeviceConsumableRecord.setBusType("2");
  46. mesDeviceConsumableRecord.setBusId(entity.getId());
  47. entity.setMesDeviceConsumableRecordList(mesDeviceConsumableRecordDao.findList(mesDeviceConsumableRecord));
  48. fillAssigneeDisplay(entity);
  49. }
  50. return entity;
  51. }
  52. /**
  53. * 查询分页数据
  54. * @param mesDevicePreventTask 查询条件
  55. * @param mesDevicePreventTask.page 分页对象
  56. * @return
  57. */
  58. @Override
  59. public Page<MesDevicePreventTask> findPage(MesDevicePreventTask mesDevicePreventTask) {
  60. Page<MesDevicePreventTask> page = super.findPage(mesDevicePreventTask);
  61. if (page != null && page.getList() != null) {
  62. for (MesDevicePreventTask item : page.getList()) {
  63. fillAssigneeDisplay(item);
  64. }
  65. }
  66. return page;
  67. }
  68. /**
  69. * 查询列表数据
  70. * @param mesDevicePreventTask
  71. * @return
  72. */
  73. @Override
  74. public List<MesDevicePreventTask> findList(MesDevicePreventTask mesDevicePreventTask) {
  75. List<MesDevicePreventTask> list = super.findList(mesDevicePreventTask);
  76. if (list != null) {
  77. for (MesDevicePreventTask item : list) {
  78. fillAssigneeDisplay(item);
  79. }
  80. }
  81. return list;
  82. }
  83. /**
  84. * 保存数据(插入或更新)
  85. * @param mesDevicePreventTask
  86. */
  87. @Override
  88. @Transactional
  89. public void save(MesDevicePreventTask mesDevicePreventTask) {
  90. super.save(mesDevicePreventTask);
  91. // 保存上传图片
  92. FileUploadUtils.saveFileUpload(mesDevicePreventTask, mesDevicePreventTask.getId(), "mesDevicePreventTask_image");
  93. for (MesDeviceConsumableRecord mesDeviceConsumableRecord : mesDevicePreventTask.getMesDeviceConsumableRecordList()){
  94. if (!MesDeviceConsumableRecord.STATUS_DELETE.equals(mesDeviceConsumableRecord.getStatus())){
  95. mesDeviceConsumableRecord.setBusType("2");
  96. mesDeviceConsumableRecord.setBusId(mesDevicePreventTask.getId());
  97. mesDeviceConsumableRecord.setDeviceId(mesDevicePreventTask.getDeviceId());
  98. if (mesDeviceConsumableRecord.getIsNewRecord()){
  99. mesDeviceConsumableRecordDao.insert(mesDeviceConsumableRecord);
  100. }else{
  101. mesDeviceConsumableRecordDao.update(mesDeviceConsumableRecord);
  102. }
  103. }else{
  104. mesDeviceConsumableRecordDao.delete(mesDeviceConsumableRecord);
  105. }
  106. }
  107. }
  108. /**
  109. * 保存计划并同步执行人关系(一人完成即整单完成)
  110. * @param mesDevicePreventTask 计划
  111. * @param userCodes 执行人编码列表
  112. */
  113. @Transactional
  114. public void saveWithAssignees(MesDevicePreventTask mesDevicePreventTask, List<String> userCodes) {
  115. if (mesDevicePreventTask.getIsNewRecord() && StringUtils.isBlank(mesDevicePreventTask.getState())) {
  116. mesDevicePreventTask.setState("0");
  117. }
  118. if (mesDevicePreventTask.getIsNewRecord() && StringUtils.isBlank(mesDevicePreventTask.getBatchId())) {
  119. mesDevicePreventTask.setBatchId(IdUtil.getSnowflakeNextIdStr());
  120. }
  121. // 主表冗余存逗号分隔,便于表单回显与PDA字段兼容
  122. mesDevicePreventTask.setUserCode(StringUtils.join(userCodes, ","));
  123. StringBuilder nameBuilder = new StringBuilder();
  124. for (int i = 0; i < userCodes.size(); i++) {
  125. User user = UserUtils.get(userCodes.get(i));
  126. if (user != null && StringUtils.isNotBlank(user.getUserName())) {
  127. if (nameBuilder.length() > 0) {
  128. nameBuilder.append(",");
  129. }
  130. nameBuilder.append(user.getUserName());
  131. }
  132. }
  133. mesDevicePreventTask.setUserName(nameBuilder.toString());
  134. this.save(mesDevicePreventTask);
  135. mesDevicePreventTaskUserService.deleteByTaskId(mesDevicePreventTask.getId());
  136. for (String userCode : userCodes) {
  137. MesDevicePreventTaskUser link = new MesDevicePreventTaskUser();
  138. link.setIsNewRecord(true);
  139. link.setPreventTaskId(mesDevicePreventTask.getId());
  140. link.setUserCode(userCode);
  141. mesDevicePreventTaskUserService.save(link);
  142. }
  143. }
  144. /**
  145. * 按首保时间和周期,在结束时间范围内生成多条维护计划。
  146. * 每条计划的结束时间固定为当天 17:00。
  147. * @param template 表单数据(任务清单、设备、首保时间、结束时间)
  148. * @param userCodes 执行人
  149. * @param cycleDays 周期(天)
  150. * @return 生成条数
  151. */
  152. @Transactional
  153. public int saveRecurringWithAssignees(MesDevicePreventTask template, List<String> userCodes, int cycleDays) {
  154. if (template == null || template.getStartDate() == null || template.getEndDate() == null) {
  155. throw new ServiceException("首保时间和任务结束时间不能为空");
  156. }
  157. if (cycleDays <= 0) {
  158. throw new ServiceException("周期必须大于0,单位为天");
  159. }
  160. Date firstStart = template.getStartDate();
  161. Date rangeEnd = atSeventeen(template.getEndDate());
  162. if (firstStart.after(rangeEnd)) {
  163. throw new ServiceException("首保时间不能晚于任务结束时间");
  164. }
  165. long spanMs = rangeEnd.getTime() - firstStart.getTime();
  166. long estimated = spanMs / (cycleDays * 24L * 3600L * 1000L) + 1;
  167. if (estimated > 2000) {
  168. throw new ServiceException("按当前周期生成的计划数量过多,请缩小时间范围或增大周期");
  169. }
  170. Date cursor = firstStart;
  171. int count = 0;
  172. String batchId = IdUtil.getSnowflakeNextIdStr();
  173. while (!cursor.after(rangeEnd)) {
  174. MesDevicePreventTask task = new MesDevicePreventTask();
  175. task.setIsNewRecord(true);
  176. task.setBatchId(batchId);
  177. task.setPreventId(template.getPreventId());
  178. task.setDeviceId(template.getDeviceId());
  179. task.setStartDate(cursor);
  180. task.setEndDate(atSeventeen(cursor));
  181. this.saveWithAssignees(task, userCodes);
  182. count++;
  183. Calendar cal = Calendar.getInstance();
  184. cal.setTime(cursor);
  185. cal.add(Calendar.DAY_OF_MONTH, cycleDays);
  186. Date next = cal.getTime();
  187. if (!next.after(cursor)) {
  188. break;
  189. }
  190. cursor = next;
  191. }
  192. if (count == 0) {
  193. throw new ServiceException("未生成任何维护计划,请检查首保时间、周期和结束时间");
  194. }
  195. return count;
  196. }
  197. /**
  198. * 将日期调整为当天 17:00:00
  199. */
  200. private Date atSeventeen(Date date) {
  201. Calendar cal = Calendar.getInstance();
  202. cal.setTime(date);
  203. cal.set(Calendar.HOUR_OF_DAY, 17);
  204. cal.set(Calendar.MINUTE, 0);
  205. cal.set(Calendar.SECOND, 0);
  206. cal.set(Calendar.MILLISECOND, 0);
  207. return cal.getTime();
  208. }
  209. /**
  210. * 维护计划一级列表:按批次分页,一行代表一份计划。
  211. */
  212. public Page<MesDevicePreventTask> findPlanPage(MesDevicePreventTask query) {
  213. Page<MesDevicePreventTask> page = query.getPage();
  214. query.setPage(null);
  215. long count = dao.findPlanCount(query);
  216. page.setCount(count);
  217. query.setPage(page);
  218. List<MesDevicePreventTask> list = dao.findPlanList(query);
  219. if (list != null) {
  220. for (MesDevicePreventTask item : list) {
  221. fillUserNameFromCodes(item);
  222. }
  223. }
  224. page.setList(list);
  225. return page;
  226. }
  227. /**
  228. * 删除同一批次下的全部周期任务
  229. */
  230. @Transactional
  231. public void deleteByBatch(String batchId) {
  232. if (StringUtils.isBlank(batchId)) {
  233. return;
  234. }
  235. MesDevicePreventTask query = new MesDevicePreventTask();
  236. query.setBatchId(batchId);
  237. List<MesDevicePreventTask> list = dao.findList(query);
  238. if (list == null) {
  239. return;
  240. }
  241. for (MesDevicePreventTask task : list) {
  242. if (task != null && StringUtils.isNotBlank(task.getId())) {
  243. this.delete(task);
  244. }
  245. }
  246. }
  247. /**
  248. * 按执行人过滤计划(我的计划 / PDA ulist)
  249. * 不改接口入参:外部仍可传 userCode,此处改为走关系表
  250. */
  251. public void applyAssigneeFilter(MesDevicePreventTask mesDevicePreventTask, String userCode) {
  252. if (mesDevicePreventTask == null || StringUtils.isBlank(userCode)) {
  253. return;
  254. }
  255. // 避免主表 user_code 等值/模糊条件干扰
  256. mesDevicePreventTask.setUserCode(null);
  257. List<MesDevicePreventTaskUser> links = mesDevicePreventTaskUserService.findByUserCode(userCode);
  258. List<String> taskIds = new ArrayList<>();
  259. if (links != null) {
  260. for (MesDevicePreventTaskUser link : links) {
  261. if (link != null && StringUtils.isNotBlank(link.getPreventTaskId())
  262. && !taskIds.contains(link.getPreventTaskId())) {
  263. taskIds.add(link.getPreventTaskId());
  264. }
  265. }
  266. }
  267. if (taskIds.isEmpty()) {
  268. mesDevicePreventTask.getSqlMap().getWhere().and("id", QueryType.EQ, "__NONE__");
  269. } else {
  270. mesDevicePreventTask.getSqlMap().getWhere().and("id", QueryType.IN, taskIds.toArray(new String[0]));
  271. }
  272. }
  273. /**
  274. * 判断当前用户是否可处理该计划
  275. */
  276. public boolean canDeal(String taskId, String userCode) {
  277. return mesDevicePreventTaskUserService.isAssignee(taskId, userCode);
  278. }
  279. /**
  280. * 设备是否存在已到期仍未完成的预防性计划(待处理,且当前时间已过结束时间;无结束时间则按开始时间)。
  281. */
  282. public boolean hasOverdueUnfinished(String deviceId) {
  283. if (StringUtils.isBlank(deviceId)) {
  284. return false;
  285. }
  286. MesDevicePreventTask query = new MesDevicePreventTask();
  287. query.setDeviceId(deviceId);
  288. query.setState("0");
  289. List<MesDevicePreventTask> list = super.findList(query);
  290. if (list == null || list.isEmpty()) {
  291. return false;
  292. }
  293. Date now = new Date();
  294. for (MesDevicePreventTask task : list) {
  295. if (task == null) {
  296. continue;
  297. }
  298. Date deadline = task.getEndDate() != null ? task.getEndDate() : task.getStartDate();
  299. if (deadline != null && !deadline.after(now)) {
  300. return true;
  301. }
  302. }
  303. return false;
  304. }
  305. /**
  306. * 更新状态
  307. * @param mesDevicePreventTask
  308. */
  309. @Override
  310. @Transactional
  311. public void updateStatus(MesDevicePreventTask mesDevicePreventTask) {
  312. super.updateStatus(mesDevicePreventTask);
  313. }
  314. /**
  315. * 删除数据(物理删除,避免 status 字段配置导致逻辑删除后仍出现在列表)
  316. * @param mesDevicePreventTask
  317. */
  318. @Override
  319. @Transactional
  320. public void delete(MesDevicePreventTask mesDevicePreventTask) {
  321. if (mesDevicePreventTask != null && StringUtils.isNotBlank(mesDevicePreventTask.getId())) {
  322. // 先删执行人关系
  323. mesDevicePreventTaskUserService.deleteByTaskId(mesDevicePreventTask.getId());
  324. // 同步清理关联耗材记录
  325. MesDeviceConsumableRecord consumable = new MesDeviceConsumableRecord();
  326. consumable.setBusType("2");
  327. consumable.setBusId(mesDevicePreventTask.getId());
  328. mesDeviceConsumableRecordDao.deleteByEntity(consumable);
  329. }
  330. dao.phyDelete(mesDevicePreventTask);
  331. }
  332. /**
  333. * 按主表冗余的执行人编码填充名称(一级汇总行没有单条任务主键)
  334. */
  335. private void fillUserNameFromCodes(MesDevicePreventTask entity) {
  336. if (entity == null || StringUtils.isBlank(entity.getUserCode())) {
  337. return;
  338. }
  339. String[] arr = StringUtils.split(entity.getUserCode(), ",");
  340. if (arr == null) {
  341. return;
  342. }
  343. List<String> names = new ArrayList<>();
  344. for (String code : arr) {
  345. String userCode = StringUtils.trim(code);
  346. if (StringUtils.isBlank(userCode)) {
  347. continue;
  348. }
  349. User user = UserUtils.get(userCode);
  350. names.add(user != null && StringUtils.isNotBlank(user.getUserName()) ? user.getUserName() : userCode);
  351. }
  352. entity.setUserName(StringUtils.join(names, ","));
  353. }
  354. /**
  355. * 填充执行人名称(关系表优先,兼容主表冗余)
  356. */
  357. private void fillAssigneeDisplay(MesDevicePreventTask entity) {
  358. if (entity == null || StringUtils.isBlank(entity.getId())) {
  359. return;
  360. }
  361. List<MesDevicePreventTaskUser> links = mesDevicePreventTaskUserService.findByTaskId(entity.getId());
  362. List<String> codes = new ArrayList<>();
  363. List<String> names = new ArrayList<>();
  364. if (links != null && !links.isEmpty()) {
  365. for (MesDevicePreventTaskUser link : links) {
  366. if (link == null || StringUtils.isBlank(link.getUserCode())) {
  367. continue;
  368. }
  369. codes.add(link.getUserCode());
  370. User user = UserUtils.get(link.getUserCode());
  371. names.add(user != null && StringUtils.isNotBlank(user.getUserName())
  372. ? user.getUserName() : link.getUserCode());
  373. }
  374. entity.setUserCode(StringUtils.join(codes, ","));
  375. entity.setUserName(StringUtils.join(names, ","));
  376. return;
  377. }
  378. // 无关系数据时,按主表冗余解析名称
  379. if (StringUtils.isNotBlank(entity.getUserCode())) {
  380. String[] arr = StringUtils.split(entity.getUserCode(), ",");
  381. if (arr != null) {
  382. for (String code : arr) {
  383. String userCode = StringUtils.trim(code);
  384. if (StringUtils.isBlank(userCode)) {
  385. continue;
  386. }
  387. codes.add(userCode);
  388. User user = UserUtils.get(userCode);
  389. names.add(user != null && StringUtils.isNotBlank(user.getUserName())
  390. ? user.getUserName() : userCode);
  391. }
  392. entity.setUserName(StringUtils.join(names, ","));
  393. }
  394. }
  395. }
  396. }