doc/20260729_safe_line_inspection_task.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,37 @@ CREATE TABLE IF NOT EXISTS `safe_line_inspection_task` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ä»»å¡ID', `inspection_name` varchar(100) DEFAULT NULL COMMENT 'å·¡æ£ä»»å¡åç§°', `line_name` varchar(100) DEFAULT NULL COMMENT '线路åç§°', `inspection_project` varchar(1000) DEFAULT NULL COMMENT 'å·¡æ£é¡¹ç®', `inspector_id` varchar(255) DEFAULT NULL COMMENT 'å·¡æ£äººIDï¼å¤ä¸ªç¨éå·åé', `frequency_type` varchar(20) DEFAULT NULL COMMENT 'é¢çç±»å DAILY/WEEKLY/MONTHLY', `frequency_detail` varchar(50) DEFAULT NULL COMMENT 'é¢ç详æ ï¼æ¯æ¥HH:mmï¼æ¯å¨MON,HH:mmï¼æ¯æDD,HH:mm', `next_execution_time` datetime DEFAULT NULL COMMENT '䏿¬¡æ§è¡æ¶é´', `last_execution_time` datetime DEFAULT NULL COMMENT 'æåæ§è¡æ¶é´', `is_enabled` tinyint DEFAULT '1' COMMENT 'æ¯å¦å¯ç¨ 0å¦ 1æ¯', `remark` varchar(500) DEFAULT NULL COMMENT '夿³¨', `create_time` datetime DEFAULT NULL COMMENT 'å建æ¶é´', `create_user` int DEFAULT NULL COMMENT 'å建人ID', `update_time` datetime DEFAULT NULL COMMENT 'æ´æ°æ¶é´', `update_user` int DEFAULT NULL COMMENT 'æ´æ°äººID', `tenant_id` bigint DEFAULT NULL COMMENT 'ç§æ·ID', `dept_id` bigint DEFAULT NULL COMMENT 'é¨é¨ID', PRIMARY KEY (`id`) USING BTREE, KEY `idx_safe_line_inspection_task_enabled` (`is_enabled`, `next_execution_time`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='å®å ¨ç产-çº¿è·¯å®æ¶å·¡æ£ä»»å¡'; ALTER TABLE `safe_line_inspection` ADD COLUMN `schedule_task_id` bigint DEFAULT NULL COMMENT '宿¶å·¡æ£ä»»å¡ID' AFTER `id`, ADD COLUMN `inspection_project` varchar(1000) DEFAULT NULL COMMENT 'å·¡æ£é¡¹ç®' AFTER `inspection_type`, ADD KEY `idx_safe_line_inspection_schedule_task` (`schedule_task_id`) USING BTREE; ALTER TABLE `safe_line_inspection` ADD COLUMN `inspection_result` varchar(20) DEFAULT NULL COMMENT 'å·¡æ£ç»æï¼æ£å¸¸/å¼å¸¸' AFTER `status`, ADD COLUMN `actual_inspection_time` datetime DEFAULT NULL COMMENT 'å®é å·¡æ£æ¶é´' AFTER `inspection_result`, ADD COLUMN `hidden_id` int DEFAULT NULL COMMENT 'å ³èéæ£ææ¥ä¸æ¥ID' AFTER `actual_inspection_time`, ADD KEY `idx_safe_line_inspection_hidden` (`hidden_id`) USING BTREE; ALTER TABLE `safe_line_inspection_hazard` ADD COLUMN `safe_hidden_id` int DEFAULT NULL COMMENT 'å ³èéæ£ææ¥ä¸æ¥ID' AFTER `record_id`, ADD COLUMN `rectify_deadline` date DEFAULT NULL COMMENT 'æ´æ¹æé' AFTER `rectify_user_id`, ADD KEY `idx_safe_line_inspection_hazard_hidden` (`safe_hidden_id`) USING BTREE; src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
@@ -68,6 +68,7 @@ SAFE_TRAINING("safe_training"), SAFE_HIDDEN_FILE("safe_hidden_file"), SAFE_LINE_INSPECTION_RECORD("safe_line_inspection_record"), SAFE_LINE_INSPECTION_HAZARD("safe_line_inspection_hazard"), SAFE_FACILITY_INSPECTION("safe_facility_inspection"), SPECIAL_EQUIPMENT_RECORD("special_equipment_record"), SPECIAL_EQUIPMENT_RECTIFICATION("special_equipment_rectification"), src/main/java/com/ruoyi/safe/controller/SafeLineInspectionController.java
@@ -5,6 +5,7 @@ import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.domain.R; import com.ruoyi.safe.dto.SafeLineInspectionExecuteDto; import com.ruoyi.safe.pojo.SafeLineInspection; import com.ruoyi.safe.pojo.SafeLineInspectionHazard; import com.ruoyi.safe.pojo.SafeLineInspectionRecord; @@ -16,7 +17,6 @@ import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.util.List; /** @@ -86,7 +86,7 @@ .count() > 0; } @Operation(summary = "宿巡æ£") @Operation(summary = "åºå¼æ§å·¡æ£å®ææ¥å£") @Log(title = "线路巡æ£", businessType = BusinessType.UPDATE) @PutMapping("/complete/{id}") public R complete(@PathVariable Integer id) { @@ -97,21 +97,18 @@ if ("已宿".equals(inspection.getStatus())) { return R.fail("å·¡æ£ä»»å¡å·²å®æï¼è¯·å¿é夿ä½"); } return R.fail("请éè¿æ§è¡å·¡æ£æäº¤æ£å¸¸ç»æï¼å¼å¸¸è®°å½è¯·å¨æ´æ¹è·è¸ªä¸ç±æ´æ¹è´£ä»»äººå®ææ´æ¹"); } // æ ¡éªæ¯å¦ææªæ´æ¹ç鿣 List<SafeLineInspectionHazard> hazards = safeLineInspectionHazardService.listByInspectionId(id); boolean hasUnrectified = hazards.stream() .anyMatch(h -> !"å·²æ´æ¹".equals(h.getStatus())); if (hasUnrectified) { return R.fail("å卿ªæ´æ¹ç鿣ï¼è¯·å å®æéæ£æ´æ¹"); @Operation(summary = "æ§è¡å·¡æ£") @Log(title = "线路巡æ£", businessType = BusinessType.UPDATE) @PutMapping("/execute") public R execute(@RequestBody SafeLineInspectionExecuteDto executeDto) { try { return R.ok(safeLineInspectionService.executeInspection(executeDto)); } catch (IllegalArgumentException e) { return R.fail(e.getMessage()); } Long currentUserId = SecurityUtils.getUserId(); inspection.setStatus("已宿"); inspection.setUpdateTime(LocalDateTime.now()); inspection.setUpdateUser(currentUserId.intValue()); return R.ok(safeLineInspectionService.updateById(inspection)); } @Operation(summary = "å é¤çº¿è·¯å·¡æ£ä»»å¡") src/main/java/com/ruoyi/safe/controller/SafeLineInspectionHazardController.java
@@ -58,7 +58,11 @@ @Log(title = "线路巡æ£éæ£", businessType = BusinessType.UPDATE) @PutMapping() public R update(@RequestBody SafeLineInspectionHazard safeLineInspectionHazard) { return R.ok(safeLineInspectionHazardService.updateById(safeLineInspectionHazard)); try { return R.ok(safeLineInspectionHazardService.updateById(safeLineInspectionHazard)); } catch (IllegalArgumentException e) { return R.fail(e.getMessage()); } } @Operation(summary = "å é¤çº¿è·¯å·¡æ£éæ£") src/main/java/com/ruoyi/safe/controller/SafeLineInspectionTaskController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,69 @@ package com.ruoyi.safe.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.domain.R; import com.ruoyi.safe.pojo.SafeLineInspectionTask; import com.ruoyi.safe.service.SafeLineInspectionTaskService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import org.quartz.SchedulerException; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * <p> * å®å ¨ç产--çº¿è·¯å®æ¶å·¡æ£ä»»å¡ å端æ§å¶å¨ * </p> */ @RestController @RequestMapping("/safeLineInspectionTask") @AllArgsConstructor @Tag(name = "å®å ¨ç产--çº¿è·¯å®æ¶å·¡æ£ä»»å¡") public class SafeLineInspectionTaskController { private SafeLineInspectionTaskService safeLineInspectionTaskService; @GetMapping("/page") @Operation(summary = "å页æ¥è¯¢") public R page(Page<SafeLineInspectionTask> page, SafeLineInspectionTask task) { return R.ok(safeLineInspectionTaskService.pageSafeLineInspectionTask(page, task)); } @GetMapping("/{id}") @Operation(summary = "æ ¹æ®IDæ¥è¯¢") public R getById(@PathVariable Long id) { return R.ok(safeLineInspectionTaskService.getById(id)); } @Operation(summary = "æ°å¢çº¿è·¯å®æ¶å·¡æ£ä»»å¡") @Log(title = "çº¿è·¯å®æ¶å·¡æ£ä»»å¡", businessType = BusinessType.INSERT) @PostMapping() public R add(@RequestBody SafeLineInspectionTask task) throws SchedulerException { return R.ok(safeLineInspectionTaskService.saveOrUpdateTask(task)); } @Operation(summary = "ä¿®æ¹çº¿è·¯å®æ¶å·¡æ£ä»»å¡") @Log(title = "çº¿è·¯å®æ¶å·¡æ£ä»»å¡", businessType = BusinessType.UPDATE) @PutMapping() public R update(@RequestBody SafeLineInspectionTask task) throws SchedulerException { return R.ok(safeLineInspectionTaskService.saveOrUpdateTask(task)); } @Operation(summary = "å é¤çº¿è·¯å®æ¶å·¡æ£ä»»å¡") @Log(title = "çº¿è·¯å®æ¶å·¡æ£ä»»å¡", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public R delete(@PathVariable List<Long> ids) { return R.ok(safeLineInspectionTaskService.removeTaskByIds(ids)); } } src/main/java/com/ruoyi/safe/dto/SafeLineInspectionExecuteDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,56 @@ package com.ruoyi.safe.dto; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.basic.dto.StorageBlobDTO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; @Data @Schema(name = "SafeLineInspectionExecuteDto", description = "çº¿è·¯å·¡æ£æ§è¡å ¥å") public class SafeLineInspectionExecuteDto { @Schema(description = "å·¡æ£è®°å½å®ä¾ID") private Integer inspectionId; @Schema(description = "å·¡æ£ç»æ(æ£å¸¸/å¼å¸¸)") private String checkResult; @Schema(description = "å·¡æ£è¯´æ") private String checkDesc; @Schema(description = "å·¡æ£æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime checkTime; @Schema(description = "ç°åºç §ç") private List<StorageBlobDTO> storageBlobDTOs; @Schema(description = "éæ£ç±»å") private String hiddenType; @Schema(description = "鿣é£é©ç级") private String riskLevel; @Schema(description = "鿣ä½ç½®") private String hazardLocation; @Schema(description = "å¼å¸¸æè¿°/æ´æ¹è¦æ±") private String hazardDesc; @Schema(description = "æ´æ¹è´£ä»»äººID") private Integer rectifyUserId; @Schema(description = "æ´æ¹è´£ä»»äººææºå·") private String rectifyUserMobile; @Schema(description = "æ´æ¹å®ææé") @JsonFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate rectifyTime; } src/main/java/com/ruoyi/safe/mapper/SafeLineInspectionTaskMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,14 @@ package com.ruoyi.safe.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.safe.pojo.SafeLineInspectionTask; import org.apache.ibatis.annotations.Mapper; /** * <p> * å®å ¨ç产--çº¿è·¯å®æ¶å·¡æ£ä»»å¡ Mapper æ¥å£ * </p> */ @Mapper public interface SafeLineInspectionTaskMapper extends BaseMapper<SafeLineInspectionTask> { } src/main/java/com/ruoyi/safe/pojo/SafeLineInspection.java
@@ -33,6 +33,9 @@ @TableId(value = "id", type = IdType.AUTO) private Integer id; @Schema(description = "宿¶å·¡æ£ä»»å¡ID") private Long scheduleTaskId; @Schema(description = "å·¡æ£ç¼å·") private String inspectionCode; @@ -44,6 +47,9 @@ @Schema(description = "å·¡æ£ç±»å") private String inspectionType; @Schema(description = "å·¡æ£é¡¹ç®") private String inspectionProject; @Schema(description = "计åå·¡æ£æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @@ -59,6 +65,17 @@ @Schema(description = "ç¶æ(å¾ å·¡æ£/å·¡æ£ä¸/已宿)") private String status; @Schema(description = "å·¡æ£ç»æ(æ£å¸¸/å¼å¸¸)") private String inspectionResult; @Schema(description = "å®é å·¡æ£æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime actualInspectionTime; @Schema(description = "å ³èéæ£ææ¥ä¸æ¥ID") private Integer hiddenId; @Schema(description = "夿³¨") private String remark; src/main/java/com/ruoyi/safe/pojo/SafeLineInspectionHazard.java
@@ -5,8 +5,12 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.ruoyi.basic.dto.StorageBlobDTO; import com.ruoyi.basic.dto.StorageBlobVO; import java.io.Serializable; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; @@ -39,6 +43,9 @@ @Schema(description = "å·¡æ£è®°å½ID") private Integer recordId; @Schema(description = "å ³èéæ£ææ¥ä¸æ¥ID") private Integer safeHiddenId; @Schema(description = "鿣ç¼å·") private String hazardCode; @@ -59,6 +66,11 @@ @Schema(description = "æ´æ¹è´£ä»»äººID") private Integer rectifyUserId; @Schema(description = "æ´æ¹æé") @JsonFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate rectifyDeadline; @Schema(description = "æ´æ¹æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @@ -86,4 +98,19 @@ @TableField(exist = false) private String rectifyUserName; @TableField(exist = false) private String inspectionCode; @TableField(exist = false) private String inspectionName; @TableField(exist = false) private String lineName; @TableField(exist = false) private List<StorageBlobDTO> storageBlobDTOs; @TableField(exist = false) private List<StorageBlobVO> storageBlobVOs; } src/main/java/com/ruoyi/safe/pojo/SafeLineInspectionTask.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,99 @@ package com.ruoyi.safe.pojo; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; /** * <p> * å®å ¨ç产--çº¿è·¯å®æ¶å·¡æ£ä»»å¡ * </p> */ @Data @TableName("safe_line_inspection_task") @Schema(name = "SafeLineInspectionTask对象", description = "å®å ¨ç产--çº¿è·¯å®æ¶å·¡æ£ä»»å¡") public class SafeLineInspectionTask implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Long id; @Schema(description = "å·¡æ£ä»»å¡åç§°") private String inspectionName; @Schema(description = "线路åç§°") private String lineName; @Schema(description = "å·¡æ£é¡¹ç®") private String inspectionProject; @Schema(description = "å·¡æ£äººIDï¼å¤ä¸ªç¨éå·åéï¼") private String inspectorId; @Schema(description = "é¢çç±»å DAILY/WEEKLY/MONTHLY") private String frequencyType; @Schema(description = "é¢ç详æ ") private String frequencyDetail; @Schema(description = "䏿¬¡æ§è¡æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime nextExecutionTime; @Schema(description = "æåæ§è¡æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime lastExecutionTime; @Schema(description = "æ¯å¦å¯ç¨ 0å¦ 1æ¯") private Integer isEnabled; @Schema(description = "夿³¨") private String remark; @Schema(description = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; @Schema(description = "å建人ID") @TableField(fill = FieldFill.INSERT) private Integer createUser; @Schema(description = "æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime; @Schema(description = "æ´æ°äººID") @TableField(fill = FieldFill.INSERT_UPDATE) private Integer updateUser; @Schema(description = "ç§æ·ID") @TableField(fill = FieldFill.INSERT) private Long tenantId; @Schema(description = "é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; @TableField(exist = false) private String inspectorName; @TableField(exist = false) private List<String> inspector; } src/main/java/com/ruoyi/safe/service/SafeLineInspectionService.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.safe.dto.SafeLineInspectionExecuteDto; import com.ruoyi.safe.pojo.SafeLineInspection; import com.baomidou.mybatisplus.extension.service.IService; @@ -16,4 +17,6 @@ public interface SafeLineInspectionService extends IService<SafeLineInspection> { IPage<SafeLineInspection> pageSafeLineInspection(Page page, SafeLineInspection safeLineInspection); boolean executeInspection(SafeLineInspectionExecuteDto executeDto); } src/main/java/com/ruoyi/safe/service/SafeLineInspectionTaskService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,28 @@ package com.ruoyi.safe.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.safe.pojo.SafeLineInspectionTask; import org.quartz.SchedulerException; import java.time.LocalDateTime; import java.util.List; /** * <p> * å®å ¨ç产--çº¿è·¯å®æ¶å·¡æ£ä»»å¡ æå¡ç±» * </p> */ public interface SafeLineInspectionTaskService extends IService<SafeLineInspectionTask> { IPage<SafeLineInspectionTask> pageSafeLineInspectionTask(Page<SafeLineInspectionTask> page, SafeLineInspectionTask task); boolean saveOrUpdateTask(SafeLineInspectionTask task) throws SchedulerException; boolean removeTaskByIds(List<Long> ids); LocalDateTime calculateFirstExecutionTime(String frequencyType, String frequencyDetail); LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime); } src/main/java/com/ruoyi/safe/service/impl/SafeHiddenServiceImpl.java
@@ -63,6 +63,9 @@ safeHiddenMapper.updateById(safeHidden); String type = sysDictDataService.selectDictLabel("hidden_danger_type", safeHidden.getType()); if (!StringUtils.hasText(type)) { type = safeHidden.getType(); } sysNoticeService.simpleNoticeByUser("éæ£ææ¥ä¸æ¥æ´æ¹", "éæ£ç±»åï¼" + type + "\t" + "鿣é£é©ç级ï¼" + safeHidden.getRiskLevel() + "\t" + src/main/java/com/ruoyi/safe/service/impl/SafeLineInspectionHazardServiceImpl.java
@@ -2,16 +2,27 @@ 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.basic.dto.StorageBlobVO; import com.ruoyi.basic.enums.ApplicationTypeEnum; import com.ruoyi.basic.enums.RecordTypeEnum; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.safe.mapper.SafeLineInspectionHazardMapper; import com.ruoyi.safe.mapper.SafeLineInspectionMapper; import com.ruoyi.safe.pojo.SafeHidden; import com.ruoyi.safe.pojo.SafeLineInspection; import com.ruoyi.safe.pojo.SafeLineInspectionHazard; import com.ruoyi.safe.service.SafeHiddenService; import com.ruoyi.safe.service.SafeLineInspectionHazardService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.Serializable; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @@ -29,17 +40,37 @@ @Autowired private SysUserMapper sysUserMapper; @Autowired private SafeHiddenService safeHiddenService; @Autowired private SafeLineInspectionMapper safeLineInspectionMapper; @Autowired private FileUtil fileUtil; @Override public IPage<SafeLineInspectionHazard> pageSafeLineInspectionHazard(Page page, SafeLineInspectionHazard safeLineInspectionHazard) { IPage<SafeLineInspectionHazard> result = this.lambdaQuery() .eq(safeLineInspectionHazard.getInspectionId() != null, SafeLineInspectionHazard::getInspectionId, safeLineInspectionHazard.getInspectionId()) .like(safeLineInspectionHazard.getHazardCode() != null, SafeLineInspectionHazard::getHazardCode, safeLineInspectionHazard.getHazardCode()) .eq(safeLineInspectionHazard.getStatus() != null, SafeLineInspectionHazard::getStatus, safeLineInspectionHazard.getStatus()) .like(StringUtils.isNotBlank(safeLineInspectionHazard.getHazardCode()), SafeLineInspectionHazard::getHazardCode, safeLineInspectionHazard.getHazardCode()) .like(StringUtils.isNotBlank(safeLineInspectionHazard.getHazardDesc()), SafeLineInspectionHazard::getHazardDesc, safeLineInspectionHazard.getHazardDesc()) .eq(StringUtils.isNotBlank(safeLineInspectionHazard.getStatus()), SafeLineInspectionHazard::getStatus, safeLineInspectionHazard.getStatus()) .orderByDesc(SafeLineInspectionHazard::getCreateTime) .page(page); fillRectifyUserName(result.getRecords()); fillInspectionInfo(result.getRecords()); fillRectifyAttachments(result.getRecords()); return result; } @Override public SafeLineInspectionHazard getById(Serializable id) { SafeLineInspectionHazard record = super.getById(id); if (record != null) { fillRectifyUserName(Collections.singletonList(record)); fillInspectionInfo(Collections.singletonList(record)); fillRectifyAttachments(Collections.singletonList(record)); } return record; } @Override @@ -49,6 +80,8 @@ .orderByDesc(SafeLineInspectionHazard::getCreateTime) .list(); fillRectifyUserName(records); fillInspectionInfo(records); fillRectifyAttachments(records); return records; } @@ -62,12 +95,65 @@ @Override public boolean updateById(SafeLineInspectionHazard entity) { SafeLineInspectionHazard oldRecord = entity.getId() == null ? null : this.getById(entity.getId()); if (oldRecord == null) { throw new IllegalArgumentException("æ´æ¹è®°å½ä¸åå¨"); } Integer safeHiddenId = entity.getSafeHiddenId() != null ? entity.getSafeHiddenId() : oldRecord.getSafeHiddenId(); if ("å·²æ´æ¹".equals(entity.getStatus())) { Long currentUserId = SecurityUtils.getUserId(); entity.setRectifyUserId(currentUserId.intValue()); validateRectify(entity, oldRecord); entity.setRectifyUserId(oldRecord.getRectifyUserId()); entity.setRectifyTime(LocalDateTime.now()); } return super.updateById(entity); boolean updated = super.updateById(entity); if (updated && "å·²æ´æ¹".equals(entity.getStatus())) { syncRectifyAttachments(entity); } if (updated && "å·²æ´æ¹".equals(entity.getStatus()) && safeHiddenId != null) { SafeHidden hidden = new SafeHidden(); hidden.setId(safeHiddenId); hidden.setRectifyMeasures(entity.getRectifyDesc()); hidden.setRectifyActualTime(LocalDate.now()); safeHiddenService.updateById(hidden); } if (updated && "å·²æ´æ¹".equals(entity.getStatus())) { Integer inspectionId = entity.getInspectionId() != null ? entity.getInspectionId() : oldRecord.getInspectionId(); completeInspectionIfAllRectified(inspectionId); } return updated; } private void validateRectify(SafeLineInspectionHazard entity, SafeLineInspectionHazard oldRecord) { if ("å·²æ´æ¹".equals(oldRecord.getStatus())) { throw new IllegalArgumentException("è¯¥éæ£å·²æ´æ¹ï¼è¯·å¿é夿ä½"); } Long currentUserId = SecurityUtils.getUserId(); if (oldRecord.getRectifyUserId() == null || currentUserId == null || !oldRecord.getRectifyUserId().equals(currentUserId.intValue())) { throw new IllegalArgumentException("åªææ´æ¹è´£ä»»äººå¯ä»¥è¿è¡æ´æ¹"); } if (StringUtils.isBlank(entity.getRectifyDesc())) { throw new IllegalArgumentException("请è¾å ¥æ´æ¹è¯´æ"); } if (entity.getStorageBlobDTOs() == null || entity.getStorageBlobDTOs().isEmpty()) { throw new IllegalArgumentException("请ä¸ä¼ æ´æ¹åç §ç"); } } private void syncRectifyAttachments(SafeLineInspectionHazard entity) { if (entity.getId() == null || entity.getStorageBlobDTOs() == null) { return; } fileUtil.saveStorageAttachment( ApplicationTypeEnum.IMAGE, RecordTypeEnum.SAFE_LINE_INSPECTION_HAZARD, entity.getId().longValue(), entity.getStorageBlobDTOs() ); } private String generateHazardCode() { @@ -96,4 +182,66 @@ } }); } private void fillInspectionInfo(List<SafeLineInspectionHazard> records) { if (records == null || records.isEmpty()) { return; } List<Integer> inspectionIds = records.stream() .map(SafeLineInspectionHazard::getInspectionId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); if (inspectionIds.isEmpty()) { return; } Map<Integer, SafeLineInspection> inspectionMap = safeLineInspectionMapper.selectBatchIds(inspectionIds).stream() .collect(Collectors.toMap(SafeLineInspection::getId, item -> item, (v1, v2) -> v1)); records.forEach(record -> { SafeLineInspection inspection = inspectionMap.get(record.getInspectionId()); if (inspection != null) { record.setInspectionCode(inspection.getInspectionCode()); record.setInspectionName(inspection.getInspectionName()); record.setLineName(inspection.getLineName()); } }); } private void fillRectifyAttachments(List<SafeLineInspectionHazard> records) { if (records == null || records.isEmpty()) { return; } records.forEach(record -> { if (record.getId() == null) { return; } List<StorageBlobVO> attachments = fileUtil.getStorageBlobVOsByRecordTypeAndRecordId( RecordTypeEnum.SAFE_LINE_INSPECTION_HAZARD, record.getId().longValue() ); record.setStorageBlobVOs(attachments == null ? Collections.emptyList() : attachments); }); } private void completeInspectionIfAllRectified(Integer inspectionId) { if (inspectionId == null) { return; } long unrectifiedCount = this.lambdaQuery() .eq(SafeLineInspectionHazard::getInspectionId, inspectionId) .ne(SafeLineInspectionHazard::getStatus, "å·²æ´æ¹") .count(); if (unrectifiedCount > 0) { return; } SafeLineInspection inspection = safeLineInspectionMapper.selectById(inspectionId); if (inspection == null || "已宿".equals(inspection.getStatus())) { return; } Long currentUserId = SecurityUtils.getUserId(); inspection.setStatus("已宿"); inspection.setUpdateTime(LocalDateTime.now()); inspection.setUpdateUser(currentUserId == null ? null : currentUserId.intValue()); safeLineInspectionMapper.updateById(inspection); } } src/main/java/com/ruoyi/safe/service/impl/SafeLineInspectionServiceImpl.java
@@ -2,15 +2,29 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.basic.enums.ApplicationTypeEnum; import com.ruoyi.basic.enums.RecordTypeEnum; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.safe.dto.SafeLineInspectionExecuteDto; import com.ruoyi.safe.pojo.SafeLineInspection; import com.ruoyi.safe.mapper.SafeLineInspectionMapper; import com.ruoyi.safe.pojo.SafeLineInspectionHazard; import com.ruoyi.safe.pojo.SafeLineInspectionRecord; import com.ruoyi.safe.pojo.SafeHidden; import com.ruoyi.safe.service.SafeHiddenService; import com.ruoyi.safe.service.SafeLineInspectionHazardService; import com.ruoyi.safe.service.SafeLineInspectionRecordService; import com.ruoyi.safe.service.SafeLineInspectionService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.project.system.mapper.SysUserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -29,14 +43,24 @@ @Autowired private SysUserMapper sysUserMapper; @Autowired private SafeLineInspectionRecordService safeLineInspectionRecordService; @Autowired private SafeLineInspectionHazardService safeLineInspectionHazardService; @Autowired private SafeHiddenService safeHiddenService; @Autowired private FileUtil fileUtil; @Override public IPage<SafeLineInspection> pageSafeLineInspection(Page page, SafeLineInspection safeLineInspection) { IPage<SafeLineInspection> result = this.lambdaQuery() .like(safeLineInspection.getInspectionCode() != null, SafeLineInspection::getInspectionCode, safeLineInspection.getInspectionCode()) .like(safeLineInspection.getInspectionName() != null, SafeLineInspection::getInspectionName, safeLineInspection.getInspectionName()) .like(safeLineInspection.getLineName() != null, SafeLineInspection::getLineName, safeLineInspection.getLineName()) .eq(safeLineInspection.getStatus() != null, SafeLineInspection::getStatus, safeLineInspection.getStatus()) .eq(safeLineInspection.getScheduleTaskId() != null, SafeLineInspection::getScheduleTaskId, safeLineInspection.getScheduleTaskId()) .like(StringUtils.isNotBlank(safeLineInspection.getInspectionCode()), SafeLineInspection::getInspectionCode, safeLineInspection.getInspectionCode()) .like(StringUtils.isNotBlank(safeLineInspection.getInspectionName()), SafeLineInspection::getInspectionName, safeLineInspection.getInspectionName()) .like(StringUtils.isNotBlank(safeLineInspection.getLineName()), SafeLineInspection::getLineName, safeLineInspection.getLineName()) .like(StringUtils.isNotBlank(safeLineInspection.getInspectionProject()), SafeLineInspection::getInspectionProject, safeLineInspection.getInspectionProject()) .eq(StringUtils.isNotBlank(safeLineInspection.getStatus()), SafeLineInspection::getStatus, safeLineInspection.getStatus()) .orderByDesc(SafeLineInspection::getCreateTime) .page(page); @@ -46,6 +70,144 @@ return result; } @Override @Transactional(rollbackFor = Exception.class) public boolean executeInspection(SafeLineInspectionExecuteDto executeDto) { if (executeDto == null || executeDto.getInspectionId() == null) { throw new IllegalArgumentException("å·¡æ£è®°å½ä¸è½ä¸ºç©º"); } SafeLineInspection inspection = this.getById(executeDto.getInspectionId()); if (inspection == null) { throw new IllegalArgumentException("å·¡æ£è®°å½ä¸åå¨"); } if ("已宿".equals(inspection.getStatus())) { throw new IllegalArgumentException("å·¡æ£è®°å½å·²å®æï¼è¯·å¿é夿§è¡"); } if (!"æ£å¸¸".equals(executeDto.getCheckResult()) && !"å¼å¸¸".equals(executeDto.getCheckResult())) { throw new IllegalArgumentException("è¯·éæ©å·¡æ£ç»æ"); } LocalDateTime checkTime = executeDto.getCheckTime() == null ? LocalDateTime.now() : executeDto.getCheckTime(); SafeLineInspectionRecord record = buildInspectionRecord(inspection, executeDto, checkTime); safeLineInspectionRecordService.save(record); inspection.setInspectionResult(executeDto.getCheckResult()); inspection.setActualInspectionTime(checkTime); inspection.setUpdateTime(LocalDateTime.now()); inspection.setUpdateUser(SecurityUtils.getUserId().intValue()); appendCurrentInspector(inspection); if ("å¼å¸¸".equals(executeDto.getCheckResult())) { validateHazard(executeDto); SafeHidden hidden = createSafeHidden(executeDto); safeHiddenService.add(hidden); fileUtil.saveStorageAttachment( ApplicationTypeEnum.IMAGE, RecordTypeEnum.SAFE_HIDDEN, hidden.getId().longValue(), executeDto.getStorageBlobDTOs() ); SafeLineInspectionHazard hazard = buildLineHazard(inspection, record, hidden, executeDto); safeLineInspectionHazardService.save(hazard); inspection.setHiddenId(hidden.getId()); inspection.setStatus("å¾ æ´æ¹"); } else { inspection.setHiddenId(null); inspection.setStatus("已宿"); } return this.updateById(inspection); } private SafeLineInspectionRecord buildInspectionRecord(SafeLineInspection inspection, SafeLineInspectionExecuteDto executeDto, LocalDateTime checkTime) { SafeLineInspectionRecord record = new SafeLineInspectionRecord(); record.setInspectionId(inspection.getId()); record.setCheckPoint(inspection.getLineName()); record.setCheckContent(inspection.getInspectionProject()); record.setCheckResult(executeDto.getCheckResult()); record.setCheckDesc("å¼å¸¸".equals(executeDto.getCheckResult()) ? null : executeDto.getCheckDesc()); record.setCheckTime(checkTime); record.setStorageBlobDTOs(executeDto.getStorageBlobDTOs()); return record; } private void validateHazard(SafeLineInspectionExecuteDto executeDto) { if (executeDto.getStorageBlobDTOs() == null || executeDto.getStorageBlobDTOs().isEmpty()) { throw new IllegalArgumentException("å·¡æ£å¼å¸¸æ¶è¯·ä¸ä¼ å¼å¸¸ç §ç"); } if (StringUtils.isBlank(executeDto.getHiddenType())) { throw new IllegalArgumentException("è¯·éæ©éæ£ç±»å"); } if (StringUtils.isBlank(executeDto.getRiskLevel())) { throw new IllegalArgumentException("è¯·éæ©éæ£é£é©ç级"); } if (StringUtils.isBlank(executeDto.getHazardLocation())) { throw new IllegalArgumentException("请è¾å ¥éæ£ä½ç½®"); } if (StringUtils.isBlank(executeDto.getHazardDesc())) { throw new IllegalArgumentException("请è¾å ¥å¼å¸¸æè¿°/æ´æ¹è¦æ±"); } if (executeDto.getRectifyUserId() == null) { throw new IllegalArgumentException("è¯·éæ©æ´æ¹è´£ä»»äºº"); } if (executeDto.getRectifyTime() == null) { throw new IllegalArgumentException("è¯·éæ©æ´æ¹å®ææé"); } } private SafeHidden createSafeHidden(SafeLineInspectionExecuteDto executeDto) { SafeHidden hidden = new SafeHidden(); hidden.setType(executeDto.getHiddenType()); hidden.setRiskLevel(executeDto.getRiskLevel()); hidden.setLocation(executeDto.getHazardLocation()); hidden.setHiddenDesc(executeDto.getHazardDesc()); hidden.setRectifyUserId(executeDto.getRectifyUserId()); hidden.setRectifyUserMobile(executeDto.getRectifyUserMobile()); hidden.setRectifyTime(executeDto.getRectifyTime()); return hidden; } private SafeLineInspectionHazard buildLineHazard(SafeLineInspection inspection, SafeLineInspectionRecord record, SafeHidden hidden, SafeLineInspectionExecuteDto executeDto) { SafeLineInspectionHazard hazard = new SafeLineInspectionHazard(); hazard.setInspectionId(inspection.getId()); hazard.setRecordId(record.getId()); hazard.setSafeHiddenId(hidden.getId()); hazard.setHazardCode(hidden.getHiddenCode()); hazard.setHazardDesc(executeDto.getHazardDesc()); hazard.setHazardLevel(executeDto.getRiskLevel()); hazard.setHazardLocation(executeDto.getHazardLocation()); hazard.setStatus("å¾ æ´æ¹"); hazard.setRectifyUserId(executeDto.getRectifyUserId()); hazard.setRectifyDeadline(executeDto.getRectifyTime()); return hazard; } private void appendCurrentInspector(SafeLineInspection inspection) { Long currentUserId = SecurityUtils.getUserId(); if (currentUserId == null) { return; } String currentUserIdStr = String.valueOf(currentUserId); String inspectorId = inspection.getInspectorId(); if (StringUtils.isBlank(inspectorId)) { inspection.setInspectorId(currentUserIdStr); return; } boolean exists = Arrays.stream(inspectorId.split(",")) .map(String::trim) .anyMatch(currentUserIdStr::equals); if (!exists) { inspection.setInspectorId(inspectorId + "," + currentUserIdStr); } } /** * å¡«å å·¡æ£äººåç§°ï¼æ¯æå¤å·¡æ£äººï¼éå·åéï¼ */ src/main/java/com/ruoyi/safe/service/impl/SafeLineInspectionTaskJob.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,171 @@ package com.ruoyi.safe.service.impl; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.safe.mapper.SafeLineInspectionMapper; import com.ruoyi.safe.mapper.SafeLineInspectionTaskMapper; import com.ruoyi.safe.pojo.SafeLineInspection; import com.ruoyi.safe.pojo.SafeLineInspectionTask; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.Serializable; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.HashSet; import java.util.Set; @Component @DisallowConcurrentExecution public class SafeLineInspectionTaskJob implements Job, Serializable { private static final long serialVersionUID = 1L; private static final DateTimeFormatter CODE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); @Autowired private SafeLineInspectionTaskMapper safeLineInspectionTaskMapper; @Autowired private SafeLineInspectionMapper safeLineInspectionMapper; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); Long taskId = jobDataMap.getLong("taskId"); try { SafeLineInspectionTask task = safeLineInspectionTaskMapper.selectById(taskId); if (task == null || Integer.valueOf(0).equals(task.getIsEnabled())) { return; } LocalDateTime executionTime = LocalDateTime.now(); SafeLineInspection inspection = createLineInspection(task, executionTime); safeLineInspectionMapper.insert(inspection); task.setLastExecutionTime(executionTime); task.setNextExecutionTime(calculateNextExecutionTime( task.getFrequencyType(), task.getFrequencyDetail(), executionTime )); safeLineInspectionTaskMapper.updateById(task); } catch (Exception e) { throw new JobExecutionException(e); } } private SafeLineInspection createLineInspection(SafeLineInspectionTask task, LocalDateTime executionTime) { SafeLineInspection inspection = new SafeLineInspection(); inspection.setScheduleTaskId(task.getId()); inspection.setInspectionCode("XLXJ-" + executionTime.format(CODE_FORMATTER) + "-" + task.getId()); inspection.setInspectionName(task.getInspectionName()); inspection.setLineName(task.getLineName()); inspection.setInspectionType("宿巡æ£"); inspection.setInspectionProject(task.getInspectionProject()); inspection.setPlanTime(task.getNextExecutionTime() != null ? task.getNextExecutionTime() : executionTime); inspection.setAssignUserId(task.getCreateUser()); inspection.setInspectorId(task.getInspectorId()); inspection.setStatus("å¾ å·¡æ£"); inspection.setRemark(buildRemark(task)); inspection.setCreateUser(task.getCreateUser()); inspection.setUpdateUser(task.getCreateUser()); inspection.setCreateTime(executionTime); inspection.setUpdateTime(executionTime); inspection.setTenantId(task.getTenantId() == null ? null : task.getTenantId().intValue()); inspection.setDeptId(task.getDeptId()); return inspection; } private String buildRemark(SafeLineInspectionTask task) { String remark = "èªå¨çæèªå®æ¶ä»»å¡ID: " + task.getId(); if (StringUtils.isNotBlank(task.getRemark())) { remark = remark + "ï¼" + task.getRemark(); } return remark; } private LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime) { return switch (frequencyType) { case "DAILY" -> calculateDailyNextTime(frequencyDetail, currentTime); case "WEEKLY" -> calculateWeeklyNextTime(frequencyDetail, currentTime); case "MONTHLY" -> calculateMonthlyNextTime(frequencyDetail, currentTime); default -> throw new IllegalArgumentException("䏿¯æçé¢çç±»å: " + frequencyType); }; } private LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime current) { LocalTime executionTime = LocalTime.parse(timeStr); LocalDateTime nextTime = LocalDateTime.of(current.toLocalDate(), executionTime); return current.isBefore(nextTime) ? nextTime : nextTime.plusDays(1); } private LocalDateTime calculateWeeklyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); LocalTime time = LocalTime.parse(parts[1].trim()); Set<DayOfWeek> targetDays = parseDayOfWeeks(parts[0]); LocalDateTime nextTime = current; while (true) { nextTime = nextTime.plusDays(1); if (targetDays.contains(nextTime.getDayOfWeek())) { return LocalDateTime.of(nextTime.toLocalDate(), time); } if (nextTime.isAfter(current.plusYears(1))) { throw new RuntimeException("æ æ³æ¾å°ä¸æ¬¡æ§è¡æ¶é´"); } } } private LocalDateTime calculateMonthlyNextTime(String detail, LocalDateTime current) { String[] parts = detail.split(","); int dayOfMonth = Integer.parseInt(parts[0].trim()); LocalTime time = LocalTime.parse(parts[1].trim()); YearMonth currentMonth = YearMonth.from(current); for (int i = 0; i < 24; i++) { YearMonth targetMonth = currentMonth.plusMonths(i); if (dayOfMonth > targetMonth.lengthOfMonth()) { continue; } LocalDateTime candidate = LocalDateTime.of( targetMonth.getYear(), targetMonth.getMonthValue(), dayOfMonth, time.getHour(), time.getMinute() ); if (current.isBefore(candidate)) { return candidate; } } throw new IllegalArgumentException("æ æ³è®¡ç®ä¸æ¬¡æ§è¡æ¶é´"); } private Set<DayOfWeek> parseDayOfWeeks(String dayOfWeekStr) { Set<DayOfWeek> days = new HashSet<>(); String[] dayStrs = dayOfWeekStr.split("\\|"); for (String dayStr : dayStrs) { switch (dayStr.trim()) { case "MON" -> days.add(DayOfWeek.MONDAY); case "TUE" -> days.add(DayOfWeek.TUESDAY); case "WED" -> days.add(DayOfWeek.WEDNESDAY); case "THU" -> days.add(DayOfWeek.THURSDAY); case "FRI" -> days.add(DayOfWeek.FRIDAY); case "SAT" -> days.add(DayOfWeek.SATURDAY); case "SUN" -> days.add(DayOfWeek.SUNDAY); default -> throw new IllegalArgumentException("æ æçææå : " + dayStr); } } return days; } } src/main/java/com/ruoyi/safe/service/impl/SafeLineInspectionTaskScheduler.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,170 @@ package com.ruoyi.safe.service.impl; import com.ruoyi.safe.pojo.SafeLineInspectionTask; import lombok.RequiredArgsConstructor; import org.quartz.CronScheduleBuilder; import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; import org.springframework.stereotype.Service; import java.time.LocalTime; import java.time.ZoneId; import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.Date; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class SafeLineInspectionTaskScheduler { private static final String JOB_GROUP = "safeLineInspectionTask"; private static final String TRIGGER_GROUP = "safeLineInspectionTaskTrigger"; private final Scheduler scheduler; public void scheduleTask(SafeLineInspectionTask task) throws SchedulerException { JobDetail jobDetail = buildJobDetail(task); if (scheduler.checkExists(jobDetail.getKey())) { scheduler.deleteJob(jobDetail.getKey()); } scheduler.scheduleJob(jobDetail, buildJobTrigger(task, jobDetail)); } public void rescheduleTask(SafeLineInspectionTask task) throws SchedulerException { TriggerKey triggerKey = getTriggerKey(task.getId()); Trigger oldTrigger = scheduler.getTrigger(triggerKey); if (oldTrigger == null) { scheduleTask(task); return; } JobDetail jobDetail = scheduler.getJobDetail(oldTrigger.getJobKey()); if (jobDetail == null) { scheduleTask(task); return; } scheduler.rescheduleJob(triggerKey, buildJobTrigger(task, jobDetail)); } public void unscheduleTask(Long taskId) { try { scheduler.deleteJob(getJobKey(taskId)); } catch (SchedulerException e) { throw new RuntimeException(e); } } private JobDetail buildJobDetail(SafeLineInspectionTask task) { JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("taskId", task.getId()); jobDataMap.put("taskName", task.getInspectionName()); jobDataMap.put("frequencyType", task.getFrequencyType()); return JobBuilder.newJob(SafeLineInspectionTaskJob.class) .withIdentity(getJobKey(task.getId())) .withDescription(task.getInspectionName()) .usingJobData(jobDataMap) .storeDurably(true) .requestRecovery(true) .build(); } private Trigger buildJobTrigger(SafeLineInspectionTask task, JobDetail jobDetail) { return TriggerBuilder.newTrigger() .withIdentity(getTriggerKey(task.getId())) .withDescription(task.getInspectionName() + "_TRIGGER") .forJob(jobDetail) .withSchedule(CronScheduleBuilder .cronSchedule(convertToCronExpression(task)) .withMisfireHandlingInstructionDoNothing()) .startAt(task.getNextExecutionTime() != null ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant()) : new Date()) .build(); } private JobKey getJobKey(Long taskId) { return new JobKey("safeLineInspectionTask_" + taskId, JOB_GROUP); } private TriggerKey getTriggerKey(Long taskId) { return new TriggerKey("safeLineInspectionTaskTrigger_" + taskId, TRIGGER_GROUP); } private String convertToCronExpression(SafeLineInspectionTask task) { if (task == null || task.getFrequencyType() == null || task.getFrequencyDetail() == null) { throw new IllegalArgumentException("ä»»å¡é¢çä¸è½ä¸ºç©º"); } return switch (task.getFrequencyType().toUpperCase()) { case "DAILY" -> convertDailyToCron(task.getFrequencyDetail()); case "WEEKLY" -> convertWeeklyToCron(task.getFrequencyDetail()); case "MONTHLY" -> convertMonthlyToCron(task.getFrequencyDetail()); default -> throw new IllegalArgumentException("䏿¯æçé¢çç±»å: " + task.getFrequencyType()); }; } private String convertDailyToCron(String frequencyDetail) { LocalTime time = parseTime(frequencyDetail); return String.format("0 %d %d * * ?", time.getMinute(), time.getHour()); } private String convertWeeklyToCron(String frequencyDetail) { String[] parts = validateAndSplit(frequencyDetail, 2); String daysOfWeek = Arrays.stream(parts[0].split("\\|")) .map(this::convertSingleDayName) .collect(Collectors.joining(",")); LocalTime time = parseTime(parts[1]); return String.format("0 %d %d ? * %s", time.getMinute(), time.getHour(), daysOfWeek); } private String convertMonthlyToCron(String frequencyDetail) { String[] parts = validateAndSplit(frequencyDetail, 2); int day = validateDayOfMonth(parts[0]); LocalTime time = parseTime(parts[1]); return String.format("0 %d %d %d * ?", time.getMinute(), time.getHour(), day); } private String[] validateAndSplit(String input, int expectedParts) { String[] parts = input.split(","); if (parts.length != expectedParts) { throw new IllegalArgumentException("ä»»å¡é¢çè¯¦æ æ ¼å¼é误"); } return Arrays.stream(parts).map(String::trim).toArray(String[]::new); } private LocalTime parseTime(String timeStr) { try { return LocalTime.parse(timeStr); } catch (DateTimeParseException e) { throw new IllegalArgumentException("æ¶é´æ ¼å¼å¿ 须为HH:mm", e); } } private int validateDayOfMonth(String dayStr) { int day = Integer.parseInt(dayStr); if (day < 1 || day > 31) { throw new IllegalArgumentException("æ¥æå¿ é¡»å¨1-31ä¹é´"); } return day; } private String convertSingleDayName(String dayName) { return switch (dayName.toUpperCase()) { case "MON" -> "MON"; case "TUE" -> "TUE"; case "WED" -> "WED"; case "THU" -> "THU"; case "FRI" -> "FRI"; case "SAT" -> "SAT"; case "SUN" -> "SUN"; default -> throw new IllegalArgumentException("æ æçææå : " + dayName); }; } } src/main/java/com/ruoyi/safe/service/impl/SafeLineInspectionTaskServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,312 @@ package com.ruoyi.safe.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 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.utils.StringUtils; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.safe.mapper.SafeLineInspectionTaskMapper; import com.ruoyi.safe.pojo.SafeLineInspectionTask; import com.ruoyi.safe.service.SafeLineInspectionTaskService; import lombok.RequiredArgsConstructor; import org.quartz.SchedulerException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; /** * <p> * å®å ¨ç产--çº¿è·¯å®æ¶å·¡æ£ä»»å¡ æå¡å®ç°ç±» * </p> */ @Service @RequiredArgsConstructor public class SafeLineInspectionTaskServiceImpl extends ServiceImpl<SafeLineInspectionTaskMapper, SafeLineInspectionTask> implements SafeLineInspectionTaskService { private static final int ENABLED = 1; private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); 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); WEEK_DAY_MAP.put("WED", DayOfWeek.WEDNESDAY); WEEK_DAY_MAP.put("THU", DayOfWeek.THURSDAY); WEEK_DAY_MAP.put("FRI", DayOfWeek.FRIDAY); WEEK_DAY_MAP.put("SAT", DayOfWeek.SATURDAY); WEEK_DAY_MAP.put("SUN", DayOfWeek.SUNDAY); } private final SafeLineInspectionTaskMapper safeLineInspectionTaskMapper; private final SafeLineInspectionTaskScheduler safeLineInspectionTaskScheduler; private final SysUserMapper sysUserMapper; @Override public IPage<SafeLineInspectionTask> pageSafeLineInspectionTask(Page<SafeLineInspectionTask> page, SafeLineInspectionTask task) { LambdaQueryWrapper<SafeLineInspectionTask> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(StringUtils.isNotBlank(task.getInspectionName()), SafeLineInspectionTask::getInspectionName, task.getInspectionName()) .like(StringUtils.isNotBlank(task.getLineName()), SafeLineInspectionTask::getLineName, task.getLineName()) .like(StringUtils.isNotBlank(task.getInspectionProject()), SafeLineInspectionTask::getInspectionProject, task.getInspectionProject()) .eq(task.getIsEnabled() != null, SafeLineInspectionTask::getIsEnabled, task.getIsEnabled()) .orderByDesc(SafeLineInspectionTask::getId); IPage<SafeLineInspectionTask> result = safeLineInspectionTaskMapper.selectPage(page, queryWrapper); fillInspectorName(result.getRecords()); return result; } @Override @Transactional public boolean saveOrUpdateTask(SafeLineInspectionTask task) throws SchedulerException { SafeLineInspectionTask oldTask = null; if (task.getId() != null) { oldTask = safeLineInspectionTaskMapper.selectById(task.getId()); if (oldTask == null) { throw new IllegalArgumentException("宿¶å·¡æ£ä»»å¡ä¸åå¨"); } } normalizeTask(task, oldTask); task.setNextExecutionTime(calculateFirstExecutionTime(task.getFrequencyType(), task.getFrequencyDetail())); boolean result; if (task.getId() == null) { result = safeLineInspectionTaskMapper.insert(task) > 0; if (result && isEnabled(task.getIsEnabled())) { safeLineInspectionTaskScheduler.scheduleTask(task); } return result; } result = safeLineInspectionTaskMapper.updateById(task) > 0; if (result) { boolean oldEnabled = oldTask != null && isEnabled(oldTask.getIsEnabled()); boolean newEnabled = isEnabled(task.getIsEnabled()); if (!newEnabled) { safeLineInspectionTaskScheduler.unscheduleTask(task.getId()); } else if (oldEnabled) { safeLineInspectionTaskScheduler.rescheduleTask(task); } else { safeLineInspectionTaskScheduler.scheduleTask(task); } } return result; } @Override @Transactional public boolean removeTaskByIds(List<Long> ids) { boolean removed = removeBatchByIds(ids); if (removed) { for (Long id : ids) { safeLineInspectionTaskScheduler.unscheduleTask(id); } } return removed; } @Override public LocalDateTime calculateFirstExecutionTime(String frequencyType, String frequencyDetail) { LocalDateTime now = LocalDateTime.now(); return calculateNextExecutionTime(frequencyType, frequencyDetail, now); } @Override public LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime) { validateFrequency(frequencyType, frequencyDetail); return switch (frequencyType) { case "DAILY" -> calculateDailyNextTime(frequencyDetail, currentTime); case "WEEKLY" -> calculateWeeklyNextTime(frequencyDetail, currentTime); case "MONTHLY" -> calculateMonthlyNextTime(frequencyDetail, currentTime); default -> throw new IllegalArgumentException("䏿¯æçé¢çç±»å: " + frequencyType); }; } private void normalizeTask(SafeLineInspectionTask task, SafeLineInspectionTask oldTask) { if (StringUtils.isBlank(task.getInspectionName())) { throw new IllegalArgumentException("å·¡æ£ä»»å¡åç§°ä¸è½ä¸ºç©º"); } if (StringUtils.isBlank(task.getLineName())) { throw new IllegalArgumentException("线路åç§°ä¸è½ä¸ºç©º"); } if (StringUtils.isBlank(task.getInspectionProject())) { throw new IllegalArgumentException("å·¡æ£é¡¹ç®ä¸è½ä¸ºç©º"); } if (StringUtils.isBlank(task.getInspectorId())) { throw new IllegalArgumentException("å·¡æ£äººä¸è½ä¸ºç©º"); } task.setIsEnabled(resolveEnabledValue(task.getIsEnabled(), oldTask)); task.setFrequencyType(task.getFrequencyType() == null ? null : task.getFrequencyType().trim().toUpperCase()); task.setFrequencyDetail(task.getFrequencyDetail() == null ? null : task.getFrequencyDetail().trim()); validateFrequency(task.getFrequencyType(), task.getFrequencyDetail()); } private void validateFrequency(String frequencyType, String frequencyDetail) { if (StringUtils.isBlank(frequencyType) || StringUtils.isBlank(frequencyDetail)) { throw new IllegalArgumentException("ä»»å¡é¢çä¸è½ä¸ºç©º"); } switch (frequencyType) { case "DAILY" -> parseTime(frequencyDetail); case "WEEKLY" -> { String[] parts = splitFrequencyDetail(frequencyDetail); if (!WEEK_DAY_MAP.containsKey(parts[0])) { throw new IllegalArgumentException("æ æçææ: " + parts[0]); } parseTime(parts[1]); } case "MONTHLY" -> { String[] parts = splitFrequencyDetail(frequencyDetail); validateDayOfMonth(parts[0]); parseTime(parts[1]); } default -> throw new IllegalArgumentException("䏿¯æçé¢çç±»å: " + frequencyType); } } private LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime currentTime) { LocalTime executionTime = parseTime(timeStr); LocalDateTime candidate = LocalDateTime.of(currentTime.toLocalDate(), executionTime); return currentTime.isBefore(candidate) ? candidate : candidate.plusDays(1); } private LocalDateTime calculateWeeklyNextTime(String detail, LocalDateTime currentTime) { String[] parts = splitFrequencyDetail(detail); DayOfWeek targetDay = WEEK_DAY_MAP.get(parts[0]); LocalTime targetTime = parseTime(parts[1]); int daysUntil = targetDay.getValue() - currentTime.getDayOfWeek().getValue(); if (daysUntil < 0 || (daysUntil == 0 && !currentTime.toLocalTime().isBefore(targetTime))) { daysUntil += 7; } return LocalDateTime.of(currentTime.toLocalDate().plusDays(daysUntil), targetTime); } private LocalDateTime calculateMonthlyNextTime(String detail, LocalDateTime currentTime) { String[] parts = splitFrequencyDetail(detail); int dayOfMonth = validateDayOfMonth(parts[0]); LocalTime targetTime = parseTime(parts[1]); YearMonth currentMonth = YearMonth.from(currentTime); for (int i = 0; i < 24; i++) { YearMonth targetMonth = currentMonth.plusMonths(i); if (dayOfMonth > targetMonth.lengthOfMonth()) { continue; } LocalDateTime candidate = LocalDateTime.of( targetMonth.getYear(), targetMonth.getMonthValue(), dayOfMonth, targetTime.getHour(), targetTime.getMinute() ); if (currentTime.isBefore(candidate)) { return candidate; } } throw new IllegalArgumentException("æ æ³è®¡ç®ä¸æ¬¡æ§è¡æ¶é´"); } private String[] splitFrequencyDetail(String detail) { String[] parts = detail.split(","); if (parts.length != 2) { throw new IllegalArgumentException("é¢çè¯¦æ æ ¼å¼é误"); } return Arrays.stream(parts).map(String::trim).toArray(String[]::new); } private LocalTime parseTime(String timeStr) { try { return LocalTime.parse(timeStr, TIME_FORMATTER); } catch (DateTimeParseException e) { throw new IllegalArgumentException("æ¶é´æ ¼å¼å¿ 须为HH:mm", e); } } private int validateDayOfMonth(String dayStr) { try { int day = Integer.parseInt(dayStr); if (day < 1 || day > 31) { throw new IllegalArgumentException("æ¥æå¿ é¡»å¨1-31ä¹é´"); } return day; } catch (NumberFormatException e) { throw new IllegalArgumentException("æ¥æå¿ é¡»å¨1-31ä¹é´", e); } } private Integer resolveEnabledValue(Integer requestEnabled, SafeLineInspectionTask oldTask) { if (requestEnabled != null) { return requestEnabled; } if (oldTask != null && oldTask.getIsEnabled() != null) { return oldTask.getIsEnabled(); } return ENABLED; } private boolean isEnabled(Integer enabledValue) { return Objects.equals(enabledValue, ENABLED); } private void fillInspectorName(List<SafeLineInspectionTask> records) { if (records == null || records.isEmpty()) { return; } Set<Long> userIds = records.stream() .map(SafeLineInspectionTask::getInspectorId) .filter(StringUtils::isNotBlank) .flatMap(ids -> Arrays.stream(ids.split(","))) .map(String::trim) .filter(StringUtils::isNotBlank) .map(this::parseUserId) .filter(Objects::nonNull) .collect(Collectors.toSet()); if (userIds.isEmpty()) { return; } Map<Long, String> userNameMap = new HashMap<>(); List<SysUser> users = sysUserMapper.selectUserByIds(new ArrayList<>(userIds)); users.forEach(user -> userNameMap.put(user.getUserId(), user.getNickName())); for (SafeLineInspectionTask record : records) { if (StringUtils.isBlank(record.getInspectorId())) { continue; } List<String> names = Arrays.stream(record.getInspectorId().split(",")) .map(String::trim) .filter(StringUtils::isNotBlank) .map(this::parseUserId) .filter(Objects::nonNull) .map(id -> userNameMap.getOrDefault(id, "æªç¥ç¨æ·")) .collect(Collectors.toList()); record.setInspector(names); record.setInspectorName(String.join(",", names)); } } private Long parseUserId(String idStr) { try { return Long.parseLong(idStr); } catch (NumberFormatException e) { return null; } } } src/main/resources/mapper/safe/SafeLineInspectionHazardMapper.xml
@@ -6,6 +6,7 @@ <id property="id" column="id"/> <result property="inspectionId" column="inspection_id"/> <result property="recordId" column="record_id"/> <result property="safeHiddenId" column="safe_hidden_id"/> <result property="hazardCode" column="hazard_code"/> <result property="hazardDesc" column="hazard_desc"/> <result property="hazardLevel" column="hazard_level"/> @@ -13,6 +14,7 @@ <result property="hazardImage" column="hazard_image"/> <result property="status" column="status"/> <result property="rectifyUserId" column="rectify_user_id"/> <result property="rectifyDeadline" column="rectify_deadline"/> <result property="rectifyTime" column="rectify_time"/> <result property="rectifyDesc" column="rectify_desc"/> <result property="createTime" column="create_time"/> src/main/resources/mapper/safe/SafeLineInspectionMapper.xml
@@ -4,14 +4,19 @@ <resultMap type="com.ruoyi.safe.pojo.SafeLineInspection" id="SafeLineInspectionResult"> <id property="id" column="id"/> <result property="scheduleTaskId" column="schedule_task_id"/> <result property="inspectionCode" column="inspection_code"/> <result property="inspectionName" column="inspection_name"/> <result property="lineName" column="line_name"/> <result property="inspectionType" column="inspection_type"/> <result property="inspectionProject" column="inspection_project"/> <result property="planTime" column="plan_time"/> <result property="assignUserId" column="assign_user_id"/> <result property="inspectorId" column="inspector_id"/> <result property="status" column="status"/> <result property="inspectionResult" column="inspection_result"/> <result property="actualInspectionTime" column="actual_inspection_time"/> <result property="hiddenId" column="hidden_id"/> <result property="remark" column="remark"/> <result property="createTime" column="create_time"/> <result property="createUser" column="create_user"/> src/main/resources/mapper/safe/SafeLineInspectionTaskMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,25 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.safe.mapper.SafeLineInspectionTaskMapper"> <resultMap type="com.ruoyi.safe.pojo.SafeLineInspectionTask" id="SafeLineInspectionTaskResult"> <id property="id" column="id"/> <result property="inspectionName" column="inspection_name"/> <result property="lineName" column="line_name"/> <result property="inspectionProject" column="inspection_project"/> <result property="inspectorId" column="inspector_id"/> <result property="frequencyType" column="frequency_type"/> <result property="frequencyDetail" column="frequency_detail"/> <result property="nextExecutionTime" column="next_execution_time"/> <result property="lastExecutionTime" column="last_execution_time"/> <result property="isEnabled" column="is_enabled"/> <result property="remark" column="remark"/> <result property="createTime" column="create_time"/> <result property="createUser" column="create_user"/> <result property="updateTime" column="update_time"/> <result property="updateUser" column="update_user"/> <result property="tenantId" column="tenant_id"/> <result property="deptId" column="dept_id"/> </resultMap> </mapper>