package com.jeesite.modules.mes.service; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import cn.hutool.core.util.IdUtil; import com.jeesite.common.lang.StringUtils; import com.jeesite.common.service.ServiceException; import com.jeesite.common.mybatis.mapper.query.QueryType; import com.jeesite.modules.mes.dao.MesDeviceConsumableRecordDao; import com.jeesite.modules.mes.entity.MesDeviceConsumableRecord; import com.jeesite.modules.mes.entity.MesDevicePreventTaskUser; import com.jeesite.modules.sys.entity.User; import com.jeesite.modules.sys.utils.UserUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.jeesite.common.entity.Page; import com.jeesite.common.service.CrudService; import com.jeesite.modules.mes.entity.MesDevicePreventTask; import com.jeesite.modules.mes.dao.MesDevicePreventTaskDao; import com.jeesite.modules.file.utils.FileUploadUtils; /** * 预防性维修计划Service * @author hzd * @version 2023-08-17 */ @Service public class MesDevicePreventTaskService extends CrudService { @Autowired private MesDeviceConsumableRecordDao mesDeviceConsumableRecordDao; @Autowired private MesDevicePreventTaskUserService mesDevicePreventTaskUserService; /** * 获取单条数据 * @param mesDevicePreventTask * @return */ @Override public MesDevicePreventTask get(MesDevicePreventTask mesDevicePreventTask) { MesDevicePreventTask entity = super.get(mesDevicePreventTask); if (entity != null){ MesDeviceConsumableRecord mesDeviceConsumableRecord = new MesDeviceConsumableRecord(); mesDeviceConsumableRecord.setStatus(MesDeviceConsumableRecord.STATUS_NORMAL); mesDeviceConsumableRecord.setBusType("2"); mesDeviceConsumableRecord.setBusId(entity.getId()); entity.setMesDeviceConsumableRecordList(mesDeviceConsumableRecordDao.findList(mesDeviceConsumableRecord)); fillAssigneeDisplay(entity); } return entity; } /** * 查询分页数据 * @param mesDevicePreventTask 查询条件 * @param mesDevicePreventTask.page 分页对象 * @return */ @Override public Page findPage(MesDevicePreventTask mesDevicePreventTask) { Page page = super.findPage(mesDevicePreventTask); if (page != null && page.getList() != null) { for (MesDevicePreventTask item : page.getList()) { fillAssigneeDisplay(item); } } return page; } /** * 查询列表数据 * @param mesDevicePreventTask * @return */ @Override public List findList(MesDevicePreventTask mesDevicePreventTask) { List list = super.findList(mesDevicePreventTask); if (list != null) { for (MesDevicePreventTask item : list) { fillAssigneeDisplay(item); } } return list; } /** * 保存数据(插入或更新) * @param mesDevicePreventTask */ @Override @Transactional public void save(MesDevicePreventTask mesDevicePreventTask) { super.save(mesDevicePreventTask); // 保存上传图片 FileUploadUtils.saveFileUpload(mesDevicePreventTask, mesDevicePreventTask.getId(), "mesDevicePreventTask_image"); for (MesDeviceConsumableRecord mesDeviceConsumableRecord : mesDevicePreventTask.getMesDeviceConsumableRecordList()){ if (!MesDeviceConsumableRecord.STATUS_DELETE.equals(mesDeviceConsumableRecord.getStatus())){ mesDeviceConsumableRecord.setBusType("2"); mesDeviceConsumableRecord.setBusId(mesDevicePreventTask.getId()); mesDeviceConsumableRecord.setDeviceId(mesDevicePreventTask.getDeviceId()); if (mesDeviceConsumableRecord.getIsNewRecord()){ mesDeviceConsumableRecordDao.insert(mesDeviceConsumableRecord); }else{ mesDeviceConsumableRecordDao.update(mesDeviceConsumableRecord); } }else{ mesDeviceConsumableRecordDao.delete(mesDeviceConsumableRecord); } } } /** * 保存计划并同步执行人关系(一人完成即整单完成) * @param mesDevicePreventTask 计划 * @param userCodes 执行人编码列表 */ @Transactional public void saveWithAssignees(MesDevicePreventTask mesDevicePreventTask, List userCodes) { if (mesDevicePreventTask.getIsNewRecord() && StringUtils.isBlank(mesDevicePreventTask.getState())) { mesDevicePreventTask.setState("0"); } if (mesDevicePreventTask.getIsNewRecord() && StringUtils.isBlank(mesDevicePreventTask.getBatchId())) { mesDevicePreventTask.setBatchId(IdUtil.getSnowflakeNextIdStr()); } // 主表冗余存逗号分隔,便于表单回显与PDA字段兼容 mesDevicePreventTask.setUserCode(StringUtils.join(userCodes, ",")); StringBuilder nameBuilder = new StringBuilder(); for (int i = 0; i < userCodes.size(); i++) { User user = UserUtils.get(userCodes.get(i)); if (user != null && StringUtils.isNotBlank(user.getUserName())) { if (nameBuilder.length() > 0) { nameBuilder.append(","); } nameBuilder.append(user.getUserName()); } } mesDevicePreventTask.setUserName(nameBuilder.toString()); this.save(mesDevicePreventTask); mesDevicePreventTaskUserService.deleteByTaskId(mesDevicePreventTask.getId()); for (String userCode : userCodes) { MesDevicePreventTaskUser link = new MesDevicePreventTaskUser(); link.setIsNewRecord(true); link.setPreventTaskId(mesDevicePreventTask.getId()); link.setUserCode(userCode); mesDevicePreventTaskUserService.save(link); } } /** * 按首保时间和周期,在结束时间范围内生成多条维护计划。 * 每条计划的结束时间固定为当天 17:00。 * @param template 表单数据(任务清单、设备、首保时间、结束时间) * @param userCodes 执行人 * @param cycleDays 周期(天) * @return 生成条数 */ @Transactional public int saveRecurringWithAssignees(MesDevicePreventTask template, List userCodes, int cycleDays) { if (template == null || template.getStartDate() == null || template.getEndDate() == null) { throw new ServiceException("首保时间和任务结束时间不能为空"); } if (cycleDays <= 0) { throw new ServiceException("周期必须大于0,单位为天"); } Date firstStart = template.getStartDate(); Date rangeEnd = atSeventeen(template.getEndDate()); if (firstStart.after(rangeEnd)) { throw new ServiceException("首保时间不能晚于任务结束时间"); } long spanMs = rangeEnd.getTime() - firstStart.getTime(); long estimated = spanMs / (cycleDays * 24L * 3600L * 1000L) + 1; if (estimated > 2000) { throw new ServiceException("按当前周期生成的计划数量过多,请缩小时间范围或增大周期"); } Date cursor = firstStart; int count = 0; String batchId = IdUtil.getSnowflakeNextIdStr(); while (!cursor.after(rangeEnd)) { MesDevicePreventTask task = new MesDevicePreventTask(); task.setIsNewRecord(true); task.setBatchId(batchId); task.setPreventId(template.getPreventId()); task.setDeviceId(template.getDeviceId()); task.setStartDate(cursor); task.setEndDate(atSeventeen(cursor)); this.saveWithAssignees(task, userCodes); count++; Calendar cal = Calendar.getInstance(); cal.setTime(cursor); cal.add(Calendar.DAY_OF_MONTH, cycleDays); Date next = cal.getTime(); if (!next.after(cursor)) { break; } cursor = next; } if (count == 0) { throw new ServiceException("未生成任何维护计划,请检查首保时间、周期和结束时间"); } return count; } /** * 将日期调整为当天 17:00:00 */ private Date atSeventeen(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, 17); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); return cal.getTime(); } /** * 维护计划一级列表:按批次分页,一行代表一份计划。 */ public Page findPlanPage(MesDevicePreventTask query) { Page page = query.getPage(); query.setPage(null); long count = dao.findPlanCount(query); page.setCount(count); query.setPage(page); List list = dao.findPlanList(query); if (list != null) { for (MesDevicePreventTask item : list) { fillUserNameFromCodes(item); } } page.setList(list); return page; } /** * 删除同一批次下的全部周期任务 */ @Transactional public void deleteByBatch(String batchId) { if (StringUtils.isBlank(batchId)) { return; } MesDevicePreventTask query = new MesDevicePreventTask(); query.setBatchId(batchId); List list = dao.findList(query); if (list == null) { return; } for (MesDevicePreventTask task : list) { if (task != null && StringUtils.isNotBlank(task.getId())) { this.delete(task); } } } /** * 按执行人过滤计划(我的计划 / PDA ulist) * 不改接口入参:外部仍可传 userCode,此处改为走关系表 */ public void applyAssigneeFilter(MesDevicePreventTask mesDevicePreventTask, String userCode) { if (mesDevicePreventTask == null || StringUtils.isBlank(userCode)) { return; } // 避免主表 user_code 等值/模糊条件干扰 mesDevicePreventTask.setUserCode(null); List links = mesDevicePreventTaskUserService.findByUserCode(userCode); List taskIds = new ArrayList<>(); if (links != null) { for (MesDevicePreventTaskUser link : links) { if (link != null && StringUtils.isNotBlank(link.getPreventTaskId()) && !taskIds.contains(link.getPreventTaskId())) { taskIds.add(link.getPreventTaskId()); } } } if (taskIds.isEmpty()) { mesDevicePreventTask.getSqlMap().getWhere().and("id", QueryType.EQ, "__NONE__"); } else { mesDevicePreventTask.getSqlMap().getWhere().and("id", QueryType.IN, taskIds.toArray(new String[0])); } } /** * 判断当前用户是否可处理该计划 */ public boolean canDeal(String taskId, String userCode) { return mesDevicePreventTaskUserService.isAssignee(taskId, userCode); } /** * 设备是否存在已到期仍未完成的预防性计划(待处理,且当前时间已过结束时间;无结束时间则按开始时间)。 */ public boolean hasOverdueUnfinished(String deviceId) { if (StringUtils.isBlank(deviceId)) { return false; } MesDevicePreventTask query = new MesDevicePreventTask(); query.setDeviceId(deviceId); query.setState("0"); List list = super.findList(query); if (list == null || list.isEmpty()) { return false; } Date now = new Date(); for (MesDevicePreventTask task : list) { if (task == null) { continue; } Date deadline = task.getEndDate() != null ? task.getEndDate() : task.getStartDate(); if (deadline != null && !deadline.after(now)) { return true; } } return false; } /** * 更新状态 * @param mesDevicePreventTask */ @Override @Transactional public void updateStatus(MesDevicePreventTask mesDevicePreventTask) { super.updateStatus(mesDevicePreventTask); } /** * 删除数据(物理删除,避免 status 字段配置导致逻辑删除后仍出现在列表) * @param mesDevicePreventTask */ @Override @Transactional public void delete(MesDevicePreventTask mesDevicePreventTask) { if (mesDevicePreventTask != null && StringUtils.isNotBlank(mesDevicePreventTask.getId())) { // 先删执行人关系 mesDevicePreventTaskUserService.deleteByTaskId(mesDevicePreventTask.getId()); // 同步清理关联耗材记录 MesDeviceConsumableRecord consumable = new MesDeviceConsumableRecord(); consumable.setBusType("2"); consumable.setBusId(mesDevicePreventTask.getId()); mesDeviceConsumableRecordDao.deleteByEntity(consumable); } dao.phyDelete(mesDevicePreventTask); } /** * 按主表冗余的执行人编码填充名称(一级汇总行没有单条任务主键) */ private void fillUserNameFromCodes(MesDevicePreventTask entity) { if (entity == null || StringUtils.isBlank(entity.getUserCode())) { return; } String[] arr = StringUtils.split(entity.getUserCode(), ","); if (arr == null) { return; } List names = new ArrayList<>(); for (String code : arr) { String userCode = StringUtils.trim(code); if (StringUtils.isBlank(userCode)) { continue; } User user = UserUtils.get(userCode); names.add(user != null && StringUtils.isNotBlank(user.getUserName()) ? user.getUserName() : userCode); } entity.setUserName(StringUtils.join(names, ",")); } /** * 填充执行人名称(关系表优先,兼容主表冗余) */ private void fillAssigneeDisplay(MesDevicePreventTask entity) { if (entity == null || StringUtils.isBlank(entity.getId())) { return; } List links = mesDevicePreventTaskUserService.findByTaskId(entity.getId()); List codes = new ArrayList<>(); List names = new ArrayList<>(); if (links != null && !links.isEmpty()) { for (MesDevicePreventTaskUser link : links) { if (link == null || StringUtils.isBlank(link.getUserCode())) { continue; } codes.add(link.getUserCode()); User user = UserUtils.get(link.getUserCode()); names.add(user != null && StringUtils.isNotBlank(user.getUserName()) ? user.getUserName() : link.getUserCode()); } entity.setUserCode(StringUtils.join(codes, ",")); entity.setUserName(StringUtils.join(names, ",")); return; } // 无关系数据时,按主表冗余解析名称 if (StringUtils.isNotBlank(entity.getUserCode())) { String[] arr = StringUtils.split(entity.getUserCode(), ","); if (arr != null) { for (String code : arr) { String userCode = StringUtils.trim(code); if (StringUtils.isBlank(userCode)) { continue; } codes.add(userCode); User user = UserUtils.get(userCode); names.add(user != null && StringUtils.isNotBlank(user.getUserName()) ? user.getUserName() : userCode); } entity.setUserName(StringUtils.join(names, ",")); } } } }