| 2026-05-18 | gongchunyi | ![]() |
| 2026-05-18 | gongchunyi | ![]() |
| 2026-05-18 | gongchunyi | ![]() |
| 2026-05-18 | gongchunyi | ![]() |
| 2026-05-18 | gongchunyi | ![]() |
| 2026-05-18 | gongchunyi | ![]() |
doc/fix_maintenance_tables.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,52 @@ -- ============================================================ -- 设å¤ä¿å »æ¨¡åæ°æ®åºä¿®å¤èæ¬ -- ä¿®å¤ä¿å »é¨ä½åä¿å »é¡¹ç®å段缺失é®é¢ -- å建æ¶é´: 2026-05-18 -- ============================================================ -- ============================================================ -- é®é¢è¯´æï¼ -- 1. maintenance_task è¡¨ç¼ºå° maintenance_location (ä¿å »é¨ä½) åæ®µ -- 2. device_maintenance è¡¨ç¼ºå° maintenance_items (ä¿å »é¡¹ç®) åæ®µ -- ============================================================ -- ---------------------------- -- ä¿®å¤ 1: å¨ maintenance_task 表添å maintenance_location (ä¿å »é¨ä½) åæ®µ -- ---------------------------- -- å æ£æ¥å段æ¯å¦åå¨ï¼ä¸åå¨åæ·»å SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'maintenance_task' AND COLUMN_NAME = 'maintenance_location'); SET @sql = IF(@col_exists = 0, 'ALTER TABLE `maintenance_task` ADD COLUMN `maintenance_location` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT ''ä¿å »é¨ä½''', 'SELECT ''maintenance_location column already exists'' AS result'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- ---------------------------- -- ä¿®å¤ 2: å¨ device_maintenance 表添å maintenance_items (ä¿å »é¡¹ç®) åæ®µ -- ---------------------------- -- å æ£æ¥å段æ¯å¦åå¨ï¼ä¸åå¨åæ·»å SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'device_maintenance' AND COLUMN_NAME = 'maintenance_items'); SET @sql = IF(@col_exists = 0, 'ALTER TABLE `device_maintenance` ADD COLUMN `maintenance_items` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT ''ä¿å »é¡¹ç®''', 'SELECT ''maintenance_items column already exists'' AS result'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- ============================================================ -- éªè¯æ§è¡ï¼æ¥è¯¢è¡¨ç»æç¡®è®¤å段已添å -- ============================================================ -- SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT -- FROM INFORMATION_SCHEMA.COLUMNS -- WHERE TABLE_NAME IN ('maintenance_task', 'device_maintenance') -- AND COLUMN_NAME IN ('maintenance_location', 'maintenance_items'); src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
@@ -23,9 +23,12 @@ @ApiModelProperty("è§æ ¼åå·") private String deviceModel; @ApiModelProperty("设å¤ä¿å »ä½ç½®") @ApiModelProperty("ä¿å »é¨ä½") private String maintenanceLocation; @ApiModelProperty("ä¿å »é¡¹ç®") private String maintenanceItems; @ApiModelProperty("计åä¿å »æ¥æ") private String maintenancePlanTimeReq; src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
@@ -10,6 +10,7 @@ import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import java.util.List; @Data @TableName("device_maintenance") @@ -91,6 +92,13 @@ @TableField(fill = FieldFill.INSERT) private Long tenantId; @ApiModelProperty("设å¤ä¿å »ä½ç½®") @ApiModelProperty("ä¿å »é¨ä½") private String maintenanceLocation; @ApiModelProperty("ä¿å »é¡¹ç®") private String maintenanceItems; @ApiModelProperty("ä¸´æ¶æä»¶IDå表") @TableField(exist = false) private List<String> tempFileIds; } src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
@@ -56,7 +56,7 @@ private LocalDateTime lastExecutionTime; @ApiModelProperty(value = "æ¯å¦æ¿æ´»") private boolean isActive; private Integer isActive; @ApiModelProperty(value = "夿³¨") @Excel(name = "夿³¨") @@ -80,6 +80,10 @@ @Excel(name = "ä¿å »é¡¹ç®") private String maintenanceItems; @ApiModelProperty(value = "ä¿å »é¨ä½") @Excel(name = "ä¿å »å 容") private String maintenanceLocation; @ApiModelProperty(value = "å½å ¥æ¥æ") @Excel(name = "å½å ¥æ¥æ", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd") src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java
@@ -10,10 +10,12 @@ import com.ruoyi.device.execl.DeviceMaintenanceExeclDto; import com.ruoyi.device.mapper.DeviceMaintenanceMapper; import com.ruoyi.device.pojo.DeviceMaintenance; import com.ruoyi.device.service.DeviceMaintenanceFileService; import com.ruoyi.device.service.IDeviceMaintenanceService; import com.ruoyi.framework.web.domain.AjaxResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; @@ -28,6 +30,9 @@ @Autowired private DeviceMaintenanceMapper deviceMaintenanceMapper; @Autowired private DeviceMaintenanceFileService deviceMaintenanceFileService; @Override public IPage<DeviceMaintenanceDto> queryPage(Page page, DeviceMaintenanceDto deviceMaintenanceDto) { @@ -35,16 +40,42 @@ } @Override @Transactional(rollbackFor = Exception.class) public AjaxResult saveDeviceRepair(DeviceMaintenance deviceMaintenance) { // å ä¿å设å¤ä¿å »è®°å½ boolean save = this.save(deviceMaintenance); if (save) { return AjaxResult.success(deviceMaintenance); if (!save) { return AjaxResult.error("ä¿å失败"); } return AjaxResult.error(); // å¤çä¸´æ¶æä»¶å ³è if (deviceMaintenance.getTempFileIds() != null && !deviceMaintenance.getTempFileIds().isEmpty()) { for (String tempId : deviceMaintenance.getTempFileIds()) { try { deviceMaintenanceFileService.bindFromTemp(tempId, deviceMaintenance.getId().intValue(), null); } catch (Exception e) { throw new RuntimeException("å ³èä¸´æ¶æä»¶å¤±è´¥: " + e.getMessage()); } } } return AjaxResult.success(deviceMaintenance); } @Override @Transactional(rollbackFor = Exception.class) public AjaxResult updateDeviceDeviceMaintenance(DeviceMaintenance deviceMaintenance) { // å¤çä¸´æ¶æä»¶å ³è if (deviceMaintenance.getTempFileIds() != null && !deviceMaintenance.getTempFileIds().isEmpty()) { for (String tempId : deviceMaintenance.getTempFileIds()) { try { deviceMaintenanceFileService.bindFromTemp(tempId, deviceMaintenance.getId().intValue(), null); } catch (Exception e) { return AjaxResult.error("å ³èä¸´æ¶æä»¶å¤±è´¥: " + e.getMessage()); } } } if (this.updateById(deviceMaintenance)) { return AjaxResult.success(); } src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
@@ -45,21 +45,26 @@ try{ TriggerKey triggerKey = new TriggerKey("triggerMaintenanceTask_" + task.getId()); // è·åç°æè§¦åå¨å¹¶è½¬æ¢ä¸º CronTrigger // è·åç°æè§¦åå¨ Trigger oldTrigger = scheduler.getTrigger(triggerKey); // ä¸åå¨åæ·»å if (oldTrigger == null) { scheduleMaintenanceTask(task); return; } if (!(oldTrigger instanceof CronTrigger)) { throw new SchedulerException("Existing trigger is not a CronTrigger"); } // 3. æå»ºCronTriggerï¼ç¡®ä¿æä¹ åé ç½® // æå»ºæ°çCronTrigger CronTrigger newTrigger = TriggerBuilder.newTrigger() .withIdentity(triggerKey) // å¯ä¸æ è¯ï¼ç¨äºæä¹ ååå¨ .withDescription(task.getTaskName() + "_TRIGGER") // 触åå¨æè¿° .forJob(oldTrigger.getJobKey()) // å ³è对åºçJob .withIdentity(triggerKey) .withDescription(task.getTaskName() + "_TRIGGER") .forJob(oldTrigger.getJobKey()) .withSchedule(CronScheduleBuilder .cronSchedule(convertToCronExpression(task)) // éè¿æ§è¡æ¶ççç¥ï¼æ ¹æ®ä¸å¡è°æ´ï¼ .cronSchedule(convertToCronExpression(task)) ) // 4. 设置å¼å§æ¶é´ï¼è¥ä¸ºnullåç«å³çæï¼ .startAt(task.getNextExecutionTime() != null ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant()) : new Date()) src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 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.device.mapper.MaintenanceTaskMapper; @@ -47,8 +48,8 @@ if (StringUtils.isNotEmpty(maintenanceTask.getTaskName())) { queryWrapper.like(MaintenanceTask::getTaskName, maintenanceTask.getTaskName()); } if (StringUtils.isNotEmpty(maintenanceTask.getStatus())) { queryWrapper.eq(MaintenanceTask::getStatus, maintenanceTask.getStatus()); if (maintenanceTask.getIsActive() != null) { queryWrapper.eq(MaintenanceTask::getIsActive, maintenanceTask.getIsActive()); } } queryWrapper.orderByDesc(MaintenanceTask::getCreateTime); @@ -90,15 +91,20 @@ @Override public AjaxResult add(MaintenanceTask maintenanceTask) { maintenanceTask.setActive(true); // 计ç®é¦æ¬¡æ§è¡æ¶é´ TimingTask task = new TimingTask(); task.setFrequencyType(maintenanceTask.getFrequencyType()); task.setFrequencyDetail(maintenanceTask.getFrequencyDetail()); LocalDateTime firstExecutionTime = timingTaskService.calculateFirstExecutionTime(task); maintenanceTask.setNextExecutionTime(firstExecutionTime); if (maintenanceTask == null){ throw new ServiceException("æ°å¢å¤±è´¥,æ°æ®ä¸è½ä¸ºç©º"); } // åªæå¯ç¨ç¶æææ·»å if (maintenanceTask.getIsActive() != null && maintenanceTask.getIsActive() == 1) { // 计ç®é¦æ¬¡æ§è¡æ¶é´ TimingTask task = new TimingTask(); task.setFrequencyType(maintenanceTask.getFrequencyType()); task.setFrequencyDetail(maintenanceTask.getFrequencyDetail()); LocalDateTime firstExecutionTime = timingTaskService.calculateFirstExecutionTime(task); maintenanceTask.setNextExecutionTime(firstExecutionTime); } int insert = maintenanceTaskMapper.insert(maintenanceTask); if (insert > 0) { if (insert > 0 && maintenanceTask.getIsActive() != null && maintenanceTask.getIsActive() == 1) { maintenanceTaskScheduler.scheduleMaintenanceTask(maintenanceTask); } return AjaxResult.success("æ·»å æå"); @@ -110,10 +116,23 @@ if (maintenanceTask1 == null) { return AjaxResult.warn("æ²¡ææ¤æ°æ®"); } Integer oldIsActive = maintenanceTask1.getIsActive(); Integer newIsActive = maintenanceTask.getIsActive(); BeanUtils.copyProperties(maintenanceTask, maintenanceTask1); int update = maintenanceTaskMapper.updateById(maintenanceTask1); if (update > 0) { maintenanceTaskScheduler.rescheduleMaintenanceTask(maintenanceTask1); // æ ¹æ®isActiveç¶æå忥å¤çä»»å¡ if (oldIsActive != null && oldIsActive == 1 && newIsActive != null && newIsActive == 0) { // ä»å¯ç¨å为åç¨ï¼ç§»é¤ä»»å¡ maintenanceTaskScheduler.unscheduleMaintenanceTask(maintenanceTask.getId()); } else if ((oldIsActive == null || oldIsActive == 0) && newIsActive != null && newIsActive == 1) { // ä»åç¨å为å¯ç¨ï¼æ·»å maintenanceTaskScheduler.scheduleMaintenanceTask(maintenanceTask1); } else { maintenanceTaskScheduler.rescheduleMaintenanceTask(maintenanceTask1); } } return AjaxResult.success("æ´æ°æå"); } src/main/java/com/ruoyi/inspectiontask/controller/TimingTaskController.java
@@ -60,7 +60,7 @@ @PostMapping("/addOrEditTimingTask") @ApiOperation(value = "æ°å¢ä¿®æ¹å®æ¶ä»»å¡") @Log(title = "宿¶ä»»å¡", businessType = BusinessType.INSERT) public R addOrEditTimingTask(@RequestBody TimingTaskDto timingTaskDto) throws SchedulerException { public R addOrEditTimingTask(@RequestBody TimingTaskDto timingTaskDto) { return R.ok(timingTaskService.addOrEditTimingTask(timingTaskDto)); } src/main/java/com/ruoyi/inspectiontask/pojo/TimingTask.java
@@ -58,7 +58,7 @@ private LocalDateTime lastExecutionTime; @ApiModelProperty(value = "æ¯å¦æ¿æ´»") private boolean isActive; private Integer isActive; @ApiModelProperty(value = "夿³¨") @Excel(name = "夿³¨") src/main/java/com/ruoyi/inspectiontask/service/TimingTaskService.java
@@ -15,7 +15,7 @@ IPage<TimingTaskDto> selectTimingTaskList(Page<TimingTask> page, TimingTask timingTask); int addOrEditTimingTask(TimingTaskDto timingTaskDto) throws SchedulerException; int addOrEditTimingTask(TimingTaskDto timingTaskDto); int delByIds(Long[] ids); src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
@@ -111,7 +111,7 @@ inspectionTask.setTaskId(timingTask.getTaskId()); inspectionTask.setInspectorId(timingTask.getInspectorIds()); inspectionTask.setInspectionLocation(timingTask.getInspectionLocation()); inspectionTask.setRemarks("èªå¨çæèªå®æ¶ä»»å¡ID: " + timingTask.getId()); inspectionTask.setRemarks(timingTask.getRemarks()); inspectionTask.setRegistrantId(timingTask.getRegistrantId()); inspectionTask.setFrequencyType(timingTask.getFrequencyType()); inspectionTask.setFrequencyDetail(timingTask.getFrequencyDetail()); src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -4,6 +4,7 @@ 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; @@ -14,7 +15,6 @@ import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import lombok.extern.slf4j.Slf4j; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -122,42 +122,59 @@ @Override @Transactional public int addOrEditTimingTask(TimingTaskDto timingTaskDto) throws SchedulerException { public int addOrEditTimingTask(TimingTaskDto timingTaskDto) { TimingTask timingTask = new TimingTask(); BeanUtils.copyProperties(timingTaskDto, timingTask); // 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ï¼å 嫿¶åç§ï¼ LocalTime currentTime = LocalTime.now(); // 3. åå¹¶ LocalDate åå½å LocalTime 为 LocalDateTime LocalDateTime localDateTime = LocalDateTime.of(localDate, currentTime); timingTask.setCreateTime(localDateTime); // 设置å建人信æ¯åé»è®¤å¼ if (Objects.isNull(timingTaskDto.getId())) { timingTask.setRegistrationDate(LocalDate.now()); timingTask.setActive(true); // 计ç®é¦æ¬¡æ§è¡æ¶é´ LocalDateTime firstExecutionTime = calculateFirstExecutionTime(timingTask); timingTask.setNextExecutionTime(firstExecutionTime); int result = timingTaskMapper.insert(timingTask); if (result > 0) { // æ°å¢æååæ·»å å°è°åº¦å¨ timingTaskScheduler.scheduleTimingTask(timingTask); // æ°å¢æååä¸å¯ç¨ç¶æææ·»å å°è°åº¦å¨ if (result > 0 && Integer.valueOf(1).equals(timingTask.getIsActive())) { try { timingTaskScheduler.scheduleTimingTask(timingTask); } catch (Exception e) { log.error("æ·»å å·¡æ£ä»»å¡å¤±è´¥ : {}", e.getMessage(), e); throw new ServiceException("æ·»å å·¡æ£ä»»å¡å¤±è´¥"); } } return result; } else { // ç¼è¾æ¶ï¼ä¿åæ§çç¶æ TimingTask oldTask = timingTaskMapper.selectById(timingTaskDto.getId()); Integer oldIsActive = oldTask != null ? oldTask.getIsActive() : 0; Integer newIsActive = timingTask.getIsActive(); int result = timingTaskMapper.updateById(timingTask); if (result > 0) { // æ´æ°æååéæ°è°åº¦ä»»å¡ timingTaskScheduler.rescheduleTimingTask(timingTask); // ä»å¯ç¨å为åç¨ï¼ç§»é¤ä»»å¡ if (Integer.valueOf(1).equals(oldIsActive) && !Integer.valueOf(1).equals(newIsActive)) { timingTaskScheduler.unscheduleTimingTask(timingTask.getId()); } // ä»åç¨å为å¯ç¨ï¼æ·»å ä»»å¡ else if (!Integer.valueOf(1).equals(oldIsActive) && Integer.valueOf(1).equals(newIsActive)) { // 计ç®é¦æ¬¡æ§è¡æ¶é´ LocalDateTime firstExecutionTime = calculateFirstExecutionTime(timingTask); timingTask.setNextExecutionTime(firstExecutionTime); try { timingTaskScheduler.scheduleTimingTask(timingTask); } catch (Exception e) { log.error("æ·»å å·¡æ£ä»»å¡å¤±è´¥ : {}", e.getMessage(), e); throw new ServiceException("æ·»å å·¡æ£ä»»å¡å¤±è´¥"); } } } return result; } @@ -195,6 +212,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); @@ -445,14 +463,29 @@ 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; default: throw new IllegalArgumentException("æ æçææå : " + 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; default: throw new IllegalArgumentException("æ æçææå : " + dayStr); } } @@ -460,11 +493,10 @@ } @Override public int delByIds(Long[] ids) { int i = timingTaskMapper.deleteBatchIds(Arrays.asList(ids)); if(i > 0){ if (i > 0) { for (Long id : ids) { timingTaskScheduler.unscheduleTimingTask(id); } src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
@@ -20,6 +20,7 @@ dm.maintenance_actually_name, dm.maintenance_person, dm.maintenance_location, dm.maintenance_items, dl.device_name, dl.device_model, su.nick_name as create_user_name @@ -43,6 +44,9 @@ <if test="deviceMaintenanceDto.maintenanceLocation != null and deviceMaintenanceDto.maintenanceLocation != ''"> and dm.maintenance_location like concat('%',#{deviceMaintenanceDto.maintenanceLocation},'%') </if> <if test="deviceMaintenanceDto.maintenanceItems != null and deviceMaintenanceDto.maintenanceItems != ''"> and dm.maintenance_items like concat('%',#{deviceMaintenanceDto.maintenanceItems},'%') </if> <if test="deviceMaintenanceDto.maintenancePlanTime != null"> and dm.maintenance_plan_time like concat('%',#{deviceMaintenanceDto.maintenancePlanTime},'%') </if> @@ -54,6 +58,7 @@ and dm.maintenance_actually_time < date_add(str_to_date(#{deviceMaintenanceDto.maintenanceActuallyTime}, '%Y-%m-%d'), interval 1 day) </if> </where> order by dm.create_time desc </select> <select id="detailById" resultType="com.ruoyi.device.dto.DeviceMaintenanceDto"> select dm.id, @@ -70,6 +75,7 @@ dm.maintenance_actually_name, dm.maintenance_person, dm.maintenance_location, dm.maintenance_items, dl.device_name, dl.device_model, su.user_name as create_user_name