gongchunyi
5 小时以前 9e713fac3f6186b735c484bed5b2c1652467bed1
Revert "feat: 设备巡检优化,巡检项目拆分"

This reverts commit b7080587bc00e5451aa8435f093f0d8cc6f80320.
已删除10个文件
已修改5个文件
914 ■■■■■ 文件已修改
doc/20261016_设备巡检项目完整脚本.sql 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/controller/InspectionItemController.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/mapper/InspectionItemMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/mapper/InspectionTaskItemMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/mapper/TimingTaskItemMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionItem.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTaskItem.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/pojo/TimingTaskItem.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/InspectionItemService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionItemServiceImpl.java 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionTaskServiceImpl.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java 211 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/20261016_É豸Ѳ¼ìÏîÄ¿ÍêÕû½Å±¾.sql
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/controller/InspectionItemController.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/mapper/InspectionItemMapper.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/mapper/InspectionTaskItemMapper.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/mapper/TimingTaskItemMapper.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionItem.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java
@@ -8,7 +8,6 @@
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
/**
 * @author :yys
@@ -31,11 +30,12 @@
    @Excel(name = "巡检任务名称")
    private String taskName;
    @Schema(description = "巡检项目")
    @Excel(name = "巡检项目")
    private String inspectionProject;
    @Schema(description = "设备id")
    private Integer taskId;
    @TableField(exist = false)
    private List<InspectionTaskItem> inspectionItems;
    @Schema(description = "巡检人ID")
    private String inspectorId;
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTaskItem.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java
@@ -11,7 +11,6 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
 * @author :yys
@@ -34,17 +33,12 @@
    @Excel(name = "巡检任务名称")
    private String taskName;
    @Schema(description = "巡检项目")
    @Excel(name = "巡检项目")
    private String inspectionProject;
    @Schema(description = "设备id")
    private Integer taskId;
    @TableField(exist = false)
    private List<Long> inspectionItemIds;
    @TableField(exist = false)
    private List<TimingTaskItem> inspectionItems;
    @TableField(exist = false)
    private List<TimingTaskItem> customItems;
    @Schema(description = "巡检人")
    @Excel(name = "执行巡检人")
@@ -99,17 +93,17 @@
    private String dateStr;
    @Schema(description = "创建该记录的用户")
    @TableField(fill = FieldFill.INSERT)
    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
    private Integer createUser;
    @Schema(description = "记录创建时间")
    @TableField(fill = FieldFill.INSERT)
    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
//    @JsonFormat(pattern = "yyyy-MM-dd")
//    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDateTime createTime;
    @Schema(description = "最后修改该记录的用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @Schema(description = "记录最后更新时间")
@@ -117,7 +111,7 @@
    private LocalDateTime updateTime;
    @Schema(description = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
    private Long tenantId;
src/main/java/com/ruoyi/inspectiontask/pojo/TimingTaskItem.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/service/InspectionItemService.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionItemServiceImpl.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionTaskServiceImpl.java
@@ -17,10 +17,8 @@
import com.ruoyi.device.pojo.DeviceLedger;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.inspectiontask.dto.InspectionTaskDto;
import com.ruoyi.inspectiontask.mapper.InspectionTaskItemMapper;
import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper;
import com.ruoyi.inspectiontask.pojo.InspectionTask;
import com.ruoyi.inspectiontask.pojo.InspectionTaskItem;
import com.ruoyi.inspectiontask.service.InspectionTaskService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
@@ -29,18 +27,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
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.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -51,12 +40,10 @@
@Service
@Slf4j
@RequiredArgsConstructor
public class InspectionTaskServiceImpl
        extends ServiceImpl<InspectionTaskMapper, InspectionTask>
        implements InspectionTaskService {
public class InspectionTaskServiceImpl extends ServiceImpl<InspectionTaskMapper, InspectionTask> implements InspectionTaskService {
    private final InspectionTaskMapper inspectionTaskMapper;
    private final InspectionTaskItemMapper inspectionTaskItemMapper;
    private final SysUserMapper sysUserMapper;
@@ -77,22 +64,17 @@
        if (StringUtils.isNotBlank(inspectionTaskDto.getTaskName())) {
            queryWrapper.like(InspectionTask::getTaskName, inspectionTaskDto.getTaskName());
        }
        if (StringUtils.isNotBlank(inspectionTaskDto.getInspectionProject())) {
            queryWrapper.like(InspectionTask::getInspectionProject, inspectionTaskDto.getInspectionProject());
        }
        IPage<InspectionTask> entityPage = inspectionTaskMapper.selectPage(page, queryWrapper);
        //  æ— æ•°æ®æå‰è¿”回
        if (CollectionUtils.isEmpty(entityPage.getRecords())) {
            return new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
        }
        List<Long> inspectionTaskIds = entityPage.getRecords().stream().map(InspectionTask::getId).toList();
        Map<Long, List<InspectionTaskItem>> recordItemsByTask = inspectionTaskItemMapper.selectList(
                        new LambdaQueryWrapper<InspectionTaskItem>()
                                .in(InspectionTaskItem::getInspectionTaskId, inspectionTaskIds)
                                .orderByAsc(InspectionTaskItem::getSortNum))
                .stream().collect(Collectors.groupingBy(InspectionTaskItem::getInspectionTaskId));
        //登记人ids
        List<Long> registrantIds = entityPage.getRecords().stream()
                .map(InspectionTask::getRegistrantId)
                .collect(Collectors.toList());
        List<Long> registrantIds = entityPage.getRecords().stream().map(InspectionTask::getRegistrantId).collect(Collectors.toList());
        // æ‰¹é‡æŸ¥è¯¢ç™»è®°äºº
        Map<Long, SysUser> sysUserMap;
        if (!registrantIds.isEmpty()) {
@@ -119,15 +101,15 @@
        // ä½¿ç”¨SQL批量查询用户信息
        Map<Long, String> userIdToNameMap = allUserIds.isEmpty()
                ? Collections.emptyMap()
                : sysUserMapper.selectUsersByIds(new ArrayList<>(allUserIds)).stream()
                        .collect(Collectors.toMap(
                                SysUser::getUserId,
                                SysUser::getNickName,
                                (existing, replacement) -> existing));
                : sysUserMapper.selectUsersByIds(new ArrayList<>(allUserIds))
                .stream()
                .collect(Collectors.toMap(
                        SysUser::getUserId,
                        SysUser::getNickName,
                        (existing, replacement) -> existing));
        List<InspectionTaskDto> dtoList = entityPage.getRecords().stream().map(inspectionTask -> {
            InspectionTaskDto dto = new InspectionTaskDto();
            BeanUtils.copyProperties(inspectionTask, dto);  // å¤åˆ¶ä¸»å¯¹è±¡å±žæ€§
            dto.setInspectionItems(recordItemsByTask.getOrDefault(inspectionTask.getId(), Collections.emptyList()));
            // è®¾ç½®ç™»è®°äºº
            SysUser sysUser = sysUserMap.get(inspectionTask.getRegistrantId());
@@ -152,12 +134,10 @@
            dto.setDateStr(inspectionTask.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            // åˆå§‹åŒ–三个附件列表
            dto.setCommonFileListVO(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(
                    ApplicationTypeEnum.FILE, RecordTypeEnum.INSPECTION_TASK, inspectionTask.getId()));
            dto.setCommonFileListAfterVO(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(
                    ApplicationTypeEnum.AFTER_FILE, RecordTypeEnum.INSPECTION_TASK, inspectionTask.getId()));
            dto.setCommonFileListBeforeVO(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(
                    ApplicationTypeEnum.BEFORE_FILE, RecordTypeEnum.INSPECTION_TASK, inspectionTask.getId()));
            dto.setCommonFileListVO(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.FILE, RecordTypeEnum.INSPECTION_TASK, inspectionTask.getId()));
            dto.setCommonFileListAfterVO(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.AFTER_FILE, RecordTypeEnum.INSPECTION_TASK, inspectionTask.getId()));
            dto.setCommonFileListBeforeVO(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.BEFORE_FILE, RecordTypeEnum.INSPECTION_TASK, inspectionTask.getId()));
            return dto;
        }).collect(Collectors.toList());
@@ -195,9 +175,6 @@
        if (i <= 0) {
            return i;
        }
        if (inspectionTaskDto.getInspectionItems() != null) {
            updateInspectionItemStatuses(inspectionTask.getId(), inspectionTaskDto);
        }
        Long linkedRepairId = syncRepairOrderIfAbnormal(inspectionTask, oldInspectionTask);
        if (linkedRepairId != null && !Objects.equals(linkedRepairId, inspectionTask.getDeviceRepairId())) {
            InspectionTask relationUpdate = new InspectionTask();
@@ -210,33 +187,6 @@
        saveInspectionAttachments(inspectionTask.getId(), inspectionTaskDto);
        return i;
    }
    private void updateInspectionItemStatuses(Long inspectionTaskId, InspectionTaskDto request) {
        List<InspectionTaskItem> requestedItems = request.getInspectionItems();
        List<InspectionTaskItem> currentItems = inspectionTaskItemMapper.selectList(
                new LambdaQueryWrapper<InspectionTaskItem>()
                        .eq(InspectionTaskItem::getInspectionTaskId, inspectionTaskId));
        Map<Long, InspectionTaskItem> currentById = currentItems.stream()
                .collect(Collectors.toMap(InspectionTaskItem::getId, Function.identity()));
        Set<Long> seenIds = new HashSet<>();
        for (InspectionTaskItem requested : requestedItems) {
            if (requested == null || requested.getId() == null
                    || requested.getItemStatus() == null
                    || (requested.getItemStatus() != 0 && requested.getItemStatus() != 1)
                    || !seenIds.add(requested.getId())) {
                throw new IllegalArgumentException("巡检内容状态无效");
            }
            InspectionTaskItem current = currentById.get(requested.getId());
            if (current == null) {
                throw new IllegalArgumentException("巡检内容清单已变化,请刷新后重试");
            }
            current.setItemStatus(requested.getItemStatus());
            current.setRemarks(requested.getRemarks());
            current.setCompletedBy(requested.getItemStatus() == 1 ? SecurityUtils.getUserId() : null);
            current.setCompletedTime(requested.getItemStatus() == 1 ? LocalDateTime.now() : null);
            inspectionTaskItemMapper.updateById(current);
        }
    }
    private void validateInspectionInput(InspectionTaskDto inspectionTaskDto, InspectionTask oldInspectionTask) {
@@ -272,24 +222,19 @@
    private boolean hasAnyInspectionPhotoAfterSave(InspectionTaskDto inspectionTaskDto, InspectionTask oldInspectionTask) {
        Long recordId = oldInspectionTask == null ? null : oldInspectionTask.getId();
        return hasApplicationPhotoAfterSave(
                inspectionTaskDto.getCommonFileListDTO(), ApplicationTypeEnum.FILE, recordId)
                || hasApplicationPhotoAfterSave(
                        inspectionTaskDto.getCommonFileListAfterDTO(), ApplicationTypeEnum.AFTER_FILE, recordId)
                || hasApplicationPhotoAfterSave(
                        inspectionTaskDto.getCommonFileListBeforeDTO(), ApplicationTypeEnum.BEFORE_FILE, recordId);
        return hasApplicationPhotoAfterSave(inspectionTaskDto.getCommonFileListDTO(), ApplicationTypeEnum.FILE, recordId)
                || hasApplicationPhotoAfterSave(inspectionTaskDto.getCommonFileListAfterDTO(), ApplicationTypeEnum.AFTER_FILE, recordId)
                || hasApplicationPhotoAfterSave(inspectionTaskDto.getCommonFileListBeforeDTO(), ApplicationTypeEnum.BEFORE_FILE, recordId);
    }
    private boolean hasApplicationPhotoAfterSave(
            List<StorageBlobDTO> requestPhotos, ApplicationTypeEnum applicationType, Long recordId) {
    private boolean hasApplicationPhotoAfterSave(List<StorageBlobDTO> requestPhotos, ApplicationTypeEnum applicationType, Long recordId) {
        if (requestPhotos != null) {
            return !requestPhotos.isEmpty();
        }
        if (recordId == null) {
            return false;
        }
        return CollectionUtils.isNotEmpty(fileUtil.getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(
                applicationType, RecordTypeEnum.INSPECTION_TASK, recordId));
        return CollectionUtils.isNotEmpty(fileUtil.getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(applicationType, RecordTypeEnum.INSPECTION_TASK, recordId));
    }
    private void fillAcceptanceInfo(InspectionTask inspectionTask, InspectionTask oldInspectionTask) {
@@ -438,8 +383,6 @@
        if (ids == null || ids.length == 0) {
            return 0;
        }
        inspectionTaskItemMapper.delete(new LambdaQueryWrapper<InspectionTaskItem>()
                .in(InspectionTaskItem::getInspectionTaskId, Arrays.asList(ids)));
        // åˆ é™¤æ–‡ä»¶
        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.INSPECTION_TASK, Arrays.asList(ids));
        fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.AFTER_FILE, RecordTypeEnum.INSPECTION_TASK, Arrays.asList(ids));
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
@@ -1,19 +1,10 @@
package com.ruoyi.inspectiontask.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.inspectiontask.mapper.InspectionTaskItemMapper;
import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper;
import com.ruoyi.inspectiontask.mapper.TimingTaskItemMapper;
import com.ruoyi.inspectiontask.pojo.InspectionTask;
import com.ruoyi.inspectiontask.pojo.InspectionTaskItem;
import com.ruoyi.inspectiontask.pojo.TimingTask;
import com.ruoyi.inspectiontask.pojo.TimingTaskItem;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import com.ruoyi.common.utils.StringUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -31,14 +22,10 @@
@Component
@DisallowConcurrentExecution // ç¦æ­¢å¹¶å‘执行同一个Job
public class TimingTaskJob implements Job, Serializable {
    private static final long serialVersionUID = 1L;
    private static final long serialVersionUID = 1L; // å¿…须定义序列化ID
    @Autowired
    private InspectionTaskMapper inspectionTaskMapper;
    @Autowired
    private TimingTaskItemMapper timingTaskItemMapper;
    @Autowired
    private InspectionTaskItemMapper inspectionTaskItemMapper;
    @Autowired
    private JdbcTemplate jdbcTemplate;
@@ -51,7 +38,7 @@
        try {
            // 3. å°è¯•查询你的业务数据
            // é€šè¿‡JDBC模板查询定时任务信息,使用参数化查询防止SQL注入
            String yourSql = "SELECT * FROM timing_task WHERE id = ?";
            String yourSql = "SELECT * FROM timing_task where id = ?";
            List<TimingTask> tasks = jdbcTemplate.query(
                    yourSql,
                    new BeanPropertyRowMapper<>(TimingTask.class),
@@ -72,7 +59,6 @@
            // 2. åˆ›å»ºå¹¶ä¿å­˜å·¡æ£€ä»»åŠ¡è®°å½• - è¿™å°±æ˜¯æ‚¨æä¾›çš„代码应该放的位置
            InspectionTask inspectionTask = createInspectionTask(timingTask);
            inspectionTaskMapper.insert(inspectionTask);
            copyTaskItemsToRecord(timingTask.getId(), inspectionTask.getId());
            // 3. æ›´æ–°å®šæ—¶ä»»åŠ¡çš„æ‰§è¡Œæ—¶é—´
            if (!tasks.isEmpty()) {
@@ -89,9 +75,9 @@
                );
                // æ‰§è¡Œæ›´æ–°æ“ä½œ
                String updateSql = "UPDATE timing_task "
                        + "SET last_execution_time = ?, next_execution_time = ? "
                        + "WHERE id = ?";
                String updateSql = "UPDATE timing_task " +
                        "SET last_execution_time = ?, next_execution_time = ? " +
                        "WHERE id = ?";
                jdbcTemplate.update(
                        updateSql,
@@ -117,6 +103,7 @@
        // å¤åˆ¶åŸºæœ¬å±žæ€§
        inspectionTask.setTaskName(timingTask.getTaskName());
        inspectionTask.setInspectionProject(timingTask.getInspectionProject());
        inspectionTask.setTaskId(timingTask.getTaskId());
        inspectionTask.setInspectorId(timingTask.getInspectorIds());
        inspectionTask.setInspectionLocation(timingTask.getInspectionLocation());
@@ -131,25 +118,6 @@
        inspectionTask.setTenantId(timingTask.getTenantId());
        return inspectionTask;
    }
    private void copyTaskItemsToRecord(Long timingTaskId, Long inspectionTaskId) {
        List<TimingTaskItem> taskItems = timingTaskItemMapper.selectList(
                new LambdaQueryWrapper<TimingTaskItem>()
                        .eq(TimingTaskItem::getTimingTaskId, timingTaskId)
                        .orderByAsc(TimingTaskItem::getSortNum));
        for (TimingTaskItem source : taskItems) {
            InspectionTaskItem recordItem = new InspectionTaskItem();
            recordItem.setInspectionTaskId(inspectionTaskId);
            recordItem.setInspectionItemId(source.getInspectionItemId());
            recordItem.setItemProject(source.getItemProject());
            recordItem.setItemContent(source.getItemContent());
            recordItem.setItemStatus(0);
            recordItem.setSortNum(source.getSortNum());
            recordItem.setTenantId(source.getTenantId());
            recordItem.setDeptId(source.getDeptId());
            inspectionTaskItemMapper.insert(recordItem);
        }
    }
@@ -275,27 +243,13 @@
        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);
            }
        }
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -4,16 +4,11 @@
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;
@@ -23,24 +18,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
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.*;
import java.time.format.DateTimeFormatter;
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.*;
import java.util.stream.Collectors;
/**
@@ -55,11 +35,9 @@
    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) {
@@ -69,7 +47,9 @@
        if (StringUtils.isNotBlank(timingTask.getTaskName())) {
            queryWrapper.like(TimingTask::getTaskName, timingTask.getTaskName());
        }
        queryWrapper.eq(TimingTask::getDeleted, 0);
        if (StringUtils.isNotBlank(timingTask.getInspectionProject())) {
            queryWrapper.like(TimingTask::getInspectionProject, timingTask.getInspectionProject());
        }
        if (timingTask.getIsEnabled() != null) {
            queryWrapper.eq(TimingTask::getIsEnabled, timingTask.getIsEnabled());
        }
@@ -133,16 +113,6 @@
                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());
@@ -162,11 +132,6 @@
                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));
@@ -174,7 +139,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(包含时分秒)
@@ -191,23 +156,17 @@
            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) {
                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 oldEnabled = isEnabled(oldTimingTask == null ? null : oldTimingTask.getIsEnabled(), oldTimingTask != null && oldTimingTask.isActive());
                boolean newEnabled = isEnabled(timingTask.getIsEnabled(), timingTask.isActive());
                if (!newEnabled) {
                    timingTaskScheduler.unscheduleTimingTask(timingTask.getId());
@@ -223,94 +182,8 @@
        }
    }
    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)) {
            // å¦‚果是每天执行,计算今天或明天的具体时间
@@ -341,7 +214,6 @@
    // æ˜ å°„星期简写与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);
@@ -444,31 +316,7 @@
    }
    private LocalDateTime calculateCustomFirstExecution(String frequencyDetail) {
        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;
        return null;
    }
    @Override
@@ -616,27 +464,13 @@
        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);
            }
        }
@@ -664,15 +498,12 @@
        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) {
            timingTaskItemMapper.delete(new LambdaQueryWrapper<TimingTaskItem>()
                    .in(TimingTaskItem::getTimingTaskId, Arrays.asList(ids)));
        if(i > 0){
            for (Long id : ids) {
                timingTaskScheduler.unscheduleTimingTask(id);
            }