gongchunyi
4 天以前 b7080587bc00e5451aa8435f093f0d8cc6f80320
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. 解析字符串为 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("季度频率格式错误,应为'季度内月份,日期,时间'");
        }
        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("季度频率日期无效");
        }
        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);
            }