From b871e526e794c09708de431899ef6de75886bbc4 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期二, 20 十月 2026 15:22:32 +0800
Subject: [PATCH] feat: 设备巡检优化,巡检项目拆分

---
 src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java |  211 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 190 insertions(+), 21 deletions(-)

diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
index 09491ab..e4156bd 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -4,11 +4,16 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.inspectiontask.dto.TimingTaskDto;
+import com.ruoyi.inspectiontask.mapper.InspectionItemMapper;
+import com.ruoyi.inspectiontask.mapper.TimingTaskItemMapper;
 import com.ruoyi.inspectiontask.mapper.TimingTaskMapper;
+import com.ruoyi.inspectiontask.pojo.InspectionItem;
 import com.ruoyi.inspectiontask.pojo.TimingTask;
+import com.ruoyi.inspectiontask.pojo.TimingTaskItem;
 import com.ruoyi.inspectiontask.service.TimingTaskService;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysUserMapper;
@@ -18,9 +23,24 @@
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.time.*;
+import java.time.DayOfWeek;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Year;
+import java.time.YearMonth;
 import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -35,9 +55,11 @@
     private final TimingTaskMapper timingTaskMapper;
     private final TimingTaskScheduler timingTaskScheduler;
     private final SysUserMapper sysUserMapper;
+    private final InspectionItemMapper inspectionItemMapper;
+    private final TimingTaskItemMapper timingTaskItemMapper;
+
     private static final int ENABLED = 1;
     private static final int DISABLED = 0;
-
 
     @Override
     public IPage<TimingTaskDto> selectTimingTaskList(Page<TimingTask> page, TimingTask timingTask) {
@@ -47,9 +69,7 @@
         if (StringUtils.isNotBlank(timingTask.getTaskName())) {
             queryWrapper.like(TimingTask::getTaskName, timingTask.getTaskName());
         }
-        if (StringUtils.isNotBlank(timingTask.getInspectionProject())) {
-            queryWrapper.like(TimingTask::getInspectionProject, timingTask.getInspectionProject());
-        }
+        queryWrapper.eq(TimingTask::getDeleted, 0);
         if (timingTask.getIsEnabled() != null) {
             queryWrapper.eq(TimingTask::getIsEnabled, timingTask.getIsEnabled());
         }
@@ -113,6 +133,16 @@
                 dto.setInspector(inspectorNickNames);
             }
 
+            List<TimingTaskItem> taskItems = timingTaskItemMapper.selectList(
+                    new LambdaQueryWrapper<TimingTaskItem>()
+                            .eq(TimingTaskItem::getTimingTaskId, task.getId())
+                            .orderByAsc(TimingTaskItem::getSortNum));
+            dto.setInspectionItems(taskItems);
+            dto.setInspectionItemIds(taskItems.stream()
+                    .map(TimingTaskItem::getInspectionItemId)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toList()));
+
             return dto;
         }).collect(Collectors.toList());
 
@@ -132,6 +162,11 @@
                 throw new IllegalArgumentException("瀹氭椂浠诲姟涓嶅瓨鍦�");
             }
         }
+        List<InspectionItem> selectedItems = resolveSelectedItems(timingTaskDto, oldTimingTask);
+        List<TimingTaskItem> customItems = normalizeCustomItems(timingTaskDto.getCustomItems());
+        if (selectedItems.isEmpty() && customItems.isEmpty()) {
+            throw new ServiceException("璇烽�夋嫨鎴栨坊鍔犺嚦灏戜竴涓贰妫�鍐呭");
+        }
         TimingTask timingTask = new TimingTask();
         BeanUtils.copyProperties(timingTaskDto, timingTask);
         timingTask.setIsEnabled(resolveEnabledValue(timingTask.getIsEnabled(), oldTimingTask));
@@ -139,7 +174,7 @@
         // 1. 瑙f瀽瀛楃涓蹭负 LocalDate锛堝彧鍖呭惈骞存湀鏃ワ級
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
         LocalDate localDate = LocalDate.now();
-        if(StringUtils.isNotEmpty(timingTaskDto.getDateStr())){
+        if (StringUtils.isNotEmpty(timingTaskDto.getDateStr())) {
             localDate = LocalDate.parse(timingTaskDto.getDateStr(), formatter);
         }
         // 2. 鑾峰彇褰撳墠绯荤粺鐨� LocalTime锛堝寘鍚椂鍒嗙锛�
@@ -156,17 +191,23 @@
             LocalDateTime firstExecutionTime = calculateFirstExecutionTime(timingTask);
             timingTask.setNextExecutionTime(firstExecutionTime);
             int result = timingTaskMapper.insert(timingTask);
+            if (result > 0) {
+                saveTaskItems(timingTask, selectedItems, customItems);
+            }
             if (result > 0 && isEnabled(timingTask.getIsEnabled(), timingTask.isActive())) {
                 // 鏂板鎴愬姛鍚庢坊鍔犲埌璋冨害鍣�
                 timingTaskScheduler.scheduleTimingTask(timingTask);
             }
             return result;
         } else {
-
-
             int result = timingTaskMapper.updateById(timingTask);
             if (result > 0) {
-                boolean oldEnabled = isEnabled(oldTimingTask == null ? null : oldTimingTask.getIsEnabled(), oldTimingTask != null && oldTimingTask.isActive());
+                timingTaskItemMapper.delete(new LambdaQueryWrapper<TimingTaskItem>()
+                        .eq(TimingTaskItem::getTimingTaskId, timingTask.getId()));
+                saveTaskItems(timingTask, selectedItems, customItems);
+                boolean oldEnabled = isEnabled(
+                        oldTimingTask == null ? null : oldTimingTask.getIsEnabled(),
+                        oldTimingTask != null && oldTimingTask.isActive());
                 boolean newEnabled = isEnabled(timingTask.getIsEnabled(), timingTask.isActive());
                 if (!newEnabled) {
                     timingTaskScheduler.unscheduleTimingTask(timingTask.getId());
@@ -182,8 +223,94 @@
         }
     }
 
+    private List<InspectionItem> resolveSelectedItems(TimingTask request, TimingTask oldTask) {
+        List<Long> itemIds = request.getInspectionItemIds();
+        if (itemIds == null && oldTask != null) {
+            itemIds = timingTaskItemMapper.selectList(new LambdaQueryWrapper<TimingTaskItem>()
+                            .eq(TimingTaskItem::getTimingTaskId, oldTask.getId()))
+                    .stream().map(TimingTaskItem::getInspectionItemId).filter(Objects::nonNull).toList();
+        }
+        if (request.getTaskId() == null || StringUtils.isBlank(request.getFrequencyType())) {
+            throw new ServiceException("璁惧鍜屽贰妫�棰戠巼涓嶈兘涓虹┖");
+        }
+        if (itemIds == null || itemIds.isEmpty()) {
+            return new ArrayList<>();
+        }
+        if (new HashSet<>(itemIds).size() != itemIds.size()) {
+            throw new ServiceException("宸℃鍐呭涓嶈兘閲嶅閫夋嫨");
+        }
+        List<InspectionItem> items = inspectionItemMapper.selectBatchIds(itemIds);
+        if (items.size() != itemIds.size()) {
+            throw new ServiceException("鎵�閫夊贰妫�鍐呭涓嶅瓨鍦�");
+        }
+        Long deviceId = request.getTaskId().longValue();
+        String frequency = request.getFrequencyType();
+        Set<Long> oldItemIds = oldTask == null ? Collections.emptySet()
+                : new HashSet<>(timingTaskItemMapper.selectList(new LambdaQueryWrapper<TimingTaskItem>()
+                        .eq(TimingTaskItem::getTimingTaskId, oldTask.getId()))
+                        .stream().map(TimingTaskItem::getInspectionItemId).filter(Objects::nonNull).toList());
+        boolean invalid = items.stream().anyMatch(item ->
+                (item.getDeviceLedgerId() != null && !deviceId.equals(item.getDeviceLedgerId()))
+                        || !(frequency.equals(item.getFrequencyType()) || "ALL".equals(item.getFrequencyType()))
+                        || (item.getDeleted() != null && item.getDeleted() == 1
+                        || item.getIsActive() == null || item.getIsActive() != 1) && !oldItemIds.contains(item.getId()));
+        if (invalid) {
+            throw new ServiceException("鎵�閫夊贰妫�鍐呭涓庤澶囨垨棰戠巼涓嶅尮閰�");
+        }
+        Map<Long, InspectionItem> itemMap = items.stream()
+                .collect(Collectors.toMap(InspectionItem::getId, Function.identity()));
+        return itemIds.stream().map(itemMap::get).toList();
+    }
+
+    private List<TimingTaskItem> normalizeCustomItems(List<TimingTaskItem> customItems) {
+        if (customItems == null) {
+            return new ArrayList<>();
+        }
+        return customItems.stream()
+                .filter(Objects::nonNull)
+                .filter(item -> StringUtils.isNotBlank(item.getItemProject())
+                        && StringUtils.isNotBlank(item.getItemContent()))
+                .peek(item -> {
+                    item.setItemProject(item.getItemProject().trim());
+                    item.setItemContent(item.getItemContent().trim());
+                })
+                .toList();
+    }
+
+    private void saveTaskItems(
+            TimingTask task,
+            List<InspectionItem> selectedItems,
+            List<TimingTaskItem> customItems) {
+        for (int index = 0; index < selectedItems.size(); index++) {
+            InspectionItem source = selectedItems.get(index);
+            TimingTaskItem taskItem = new TimingTaskItem();
+            taskItem.setTimingTaskId(task.getId());
+            taskItem.setInspectionItemId(source.getId());
+            taskItem.setItemProject(source.getItemProject());
+            taskItem.setItemContent(source.getItemContent());
+            taskItem.setSortNum(index);
+            taskItem.setTenantId(task.getTenantId());
+            taskItem.setDeptId(task.getDeptId());
+            timingTaskItemMapper.insert(taskItem);
+        }
+        for (int index = 0; index < customItems.size(); index++) {
+            TimingTaskItem source = customItems.get(index);
+            TimingTaskItem taskItem = new TimingTaskItem();
+            taskItem.setTimingTaskId(task.getId());
+            taskItem.setItemProject(source.getItemProject());
+            taskItem.setItemContent(source.getItemContent());
+            taskItem.setSortNum(selectedItems.size() + index);
+            taskItem.setTenantId(task.getTenantId());
+            taskItem.setDeptId(task.getDeptId());
+            timingTaskItemMapper.insert(taskItem);
+        }
+    }
+
     public LocalDateTime calculateFirstExecutionTime(TimingTask task) {
         // 鏍规嵁棰戠巼绫诲瀷鍜岃鎯呰绠楅娆℃墽琛屾椂闂�
+        if (task == null || StringUtils.isBlank(task.getFrequencyDetail())) {
+            throw new IllegalArgumentException("璇峰~鍐欎换鍔℃墽琛屾棩鏈熷拰鏃堕棿");
+        }
         String frequencyType = task.getFrequencyType();
         if ("DAILY".equals(frequencyType)) {
             // 濡傛灉鏄瘡澶╂墽琛岋紝璁$畻浠婂ぉ鎴栨槑澶╃殑鍏蜂綋鏃堕棿
@@ -214,6 +341,7 @@
 
     // 鏄犲皠鏄熸湡绠�鍐欎笌DayOfWeek
     private static final Map<String, DayOfWeek> WEEK_DAY_MAP = new HashMap<>();
+
     static {
         WEEK_DAY_MAP.put("MON", DayOfWeek.MONDAY);
         WEEK_DAY_MAP.put("TUE", DayOfWeek.TUESDAY);
@@ -316,7 +444,31 @@
     }
 
     private LocalDateTime calculateCustomFirstExecution(String frequencyDetail) {
-        return null;
+        String[] parts = frequencyDetail.split(",");
+        if (parts.length != 3) {
+            throw new IllegalArgumentException("瀛e害棰戠巼鏍煎紡閿欒锛屽簲涓�'瀛e害鍐呮湀浠�,鏃ユ湡,鏃堕棿'");
+        }
+        int monthInQuarter = Integer.parseInt(parts[0]);
+        int dayOfMonth = Integer.parseInt(parts[1]);
+        LocalTime time = LocalTime.parse(parts[2], DateTimeFormatter.ofPattern("HH:mm"));
+        if (monthInQuarter < 1 || monthInQuarter > 3 || dayOfMonth < 1 || dayOfMonth > 31) {
+            throw new IllegalArgumentException("瀛e害棰戠巼鏃ユ湡鏃犳晥");
+        }
+
+        LocalDateTime now = LocalDateTime.now();
+        int currentMonthInQuarter = (now.getMonthValue() - 1) % 3 + 1;
+        int monthsUntilTarget = monthInQuarter - currentMonthInQuarter;
+        if (monthsUntilTarget < 0) {
+            monthsUntilTarget += 3;
+        }
+        YearMonth targetMonth = YearMonth.from(now).plusMonths(monthsUntilTarget);
+        int targetDay = Math.min(dayOfMonth, targetMonth.lengthOfMonth());
+        LocalDateTime target = targetMonth.atDay(targetDay).atTime(time);
+        if (!target.isAfter(now)) {
+            targetMonth = targetMonth.plusMonths(3);
+            target = targetMonth.atDay(Math.min(dayOfMonth, targetMonth.lengthOfMonth())).atTime(time);
+        }
+        return target;
     }
 
     @Override
@@ -464,13 +616,27 @@
 
         for (String dayStr : dayStrs) {
             switch (dayStr) {
-                case "MON": days.add(DayOfWeek.MONDAY); break;
-                case "TUE": days.add(DayOfWeek.TUESDAY); break;
-                case "WED": days.add(DayOfWeek.WEDNESDAY); break;
-                case "THU": days.add(DayOfWeek.THURSDAY); break;
-                case "FRI": days.add(DayOfWeek.FRIDAY); break;
-                case "SAT": days.add(DayOfWeek.SATURDAY); break;
-                case "SUN": days.add(DayOfWeek.SUNDAY); break;
+                case "MON":
+                    days.add(DayOfWeek.MONDAY);
+                    break;
+                case "TUE":
+                    days.add(DayOfWeek.TUESDAY);
+                    break;
+                case "WED":
+                    days.add(DayOfWeek.WEDNESDAY);
+                    break;
+                case "THU":
+                    days.add(DayOfWeek.THURSDAY);
+                    break;
+                case "FRI":
+                    days.add(DayOfWeek.FRIDAY);
+                    break;
+                case "SAT":
+                    days.add(DayOfWeek.SATURDAY);
+                    break;
+                case "SUN":
+                    days.add(DayOfWeek.SUNDAY);
+                    break;
                 default: throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈熷嚑: " + dayStr);
             }
         }
@@ -498,12 +664,15 @@
         return activeFallback;
     }
 
-
-
     @Override
     public int delByIds(Long[] ids) {
+        if (ids == null || ids.length == 0) {
+            return 0;
+        }
         int i = timingTaskMapper.deleteBatchIds(Arrays.asList(ids));
-        if(i > 0){
+        if (i > 0) {
+            timingTaskItemMapper.delete(new LambdaQueryWrapper<TimingTaskItem>()
+                    .in(TimingTaskItem::getTimingTaskId, Arrays.asList(ids)));
             for (Long id : ids) {
                 timingTaskScheduler.unscheduleTimingTask(id);
             }

--
Gitblit v1.9.3