From 64de92ae028b582b7fbe8d3c84eb568edf0d400f Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期四, 30 七月 2026 13:49:37 +0800
Subject: [PATCH] feat: 安全设施巡检调整
---
doc/20260730_safe_facility_inspection_task.sql | 29 +
src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspection.java | 6
src/main/java/com/ruoyi/safe/controller/SafeFacilityLedgerController.java | 12
src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskJob.java | 169 ++++++++++
src/main/resources/mapper/safe/SafeFacilityInspectionMapper.xml | 2
src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspectionTask.java | 101 ++++++
src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskScheduler.java | 170 ++++++++++
src/main/java/com/ruoyi/safe/mapper/SafeFacilityInspectionTaskMapper.java | 14
src/main/java/com/ruoyi/safe/service/SafeFacilityInspectionTaskService.java | 28 +
src/main/java/com/ruoyi/safe/controller/SafeFacilityInspectionTaskController.java | 69 ++++
src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionServiceImpl.java | 6
src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskServiceImpl.java | 301 ++++++++++++++++++
12 files changed, 905 insertions(+), 2 deletions(-)
diff --git a/doc/20260730_safe_facility_inspection_task.sql b/doc/20260730_safe_facility_inspection_task.sql
new file mode 100644
index 0000000..a72f485
--- /dev/null
+++ b/doc/20260730_safe_facility_inspection_task.sql
@@ -0,0 +1,29 @@
+CREATE TABLE IF NOT EXISTS `safe_facility_inspection_task` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浠诲姟ID',
+ `inspection_name` varchar(100) DEFAULT NULL COMMENT '宸℃浠诲姟鍚嶇О',
+ `facility_id` int DEFAULT NULL COMMENT '璁炬柦ID',
+ `facility_code` varchar(100) DEFAULT NULL COMMENT '璁炬柦缂栧彿',
+ `facility_name` varchar(100) DEFAULT NULL COMMENT '璁炬柦鍚嶇О',
+ `inspection_project` varchar(1000) DEFAULT NULL COMMENT '宸℃椤圭洰',
+ `inspector_id` int DEFAULT NULL COMMENT '宸℃浜篒D',
+ `frequency_type` varchar(20) DEFAULT NULL COMMENT '棰戠巼绫诲瀷 DAILY/WEEKLY/MONTHLY',
+ `frequency_detail` varchar(50) DEFAULT NULL COMMENT '棰戠巼璇︽儏锛氭瘡鏃H:mm锛涙瘡鍛∕ON,HH:mm锛涙瘡鏈圖D,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 '鍒涘缓浜篒D',
+ `update_time` datetime DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+ `update_user` int DEFAULT NULL COMMENT '鏇存柊浜篒D',
+ `tenant_id` int DEFAULT NULL COMMENT '绉熸埛ID',
+ `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_safe_facility_inspection_task_facility` (`facility_id`) USING BTREE,
+ KEY `idx_safe_facility_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_facility_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_facility_inspection_schedule_task` (`schedule_task_id`) USING BTREE;
diff --git a/src/main/java/com/ruoyi/safe/controller/SafeFacilityInspectionTaskController.java b/src/main/java/com/ruoyi/safe/controller/SafeFacilityInspectionTaskController.java
new file mode 100644
index 0000000..d80616f
--- /dev/null
+++ b/src/main/java/com/ruoyi/safe/controller/SafeFacilityInspectionTaskController.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.SafeFacilityInspectionTask;
+import com.ruoyi.safe.service.SafeFacilityInspectionTaskService;
+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("/safeFacilityInspectionTask")
+@AllArgsConstructor
+@Tag(name = "瀹夊叏鐢熶骇--瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟")
+public class SafeFacilityInspectionTaskController {
+
+ private SafeFacilityInspectionTaskService safeFacilityInspectionTaskService;
+
+ @GetMapping("/page")
+ @Operation(summary = "鍒嗛〉鏌ヨ")
+ public R page(Page<SafeFacilityInspectionTask> page, SafeFacilityInspectionTask task) {
+ return R.ok(safeFacilityInspectionTaskService.pageSafeFacilityInspectionTask(page, task));
+ }
+
+ @GetMapping("/{id}")
+ @Operation(summary = "鏍规嵁ID鏌ヨ")
+ public R getById(@PathVariable Long id) {
+ return R.ok(safeFacilityInspectionTaskService.getById(id));
+ }
+
+ @Operation(summary = "鏂板瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟")
+ @Log(title = "瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟", businessType = BusinessType.INSERT)
+ @PostMapping()
+ public R add(@RequestBody SafeFacilityInspectionTask task) throws SchedulerException {
+ return R.ok(safeFacilityInspectionTaskService.saveOrUpdateTask(task));
+ }
+
+ @Operation(summary = "淇敼瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟")
+ @Log(title = "瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟", businessType = BusinessType.UPDATE)
+ @PutMapping()
+ public R update(@RequestBody SafeFacilityInspectionTask task) throws SchedulerException {
+ return R.ok(safeFacilityInspectionTaskService.saveOrUpdateTask(task));
+ }
+
+ @Operation(summary = "鍒犻櫎瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟")
+ @Log(title = "瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R delete(@PathVariable List<Long> ids) {
+ return R.ok(safeFacilityInspectionTaskService.removeTaskByIds(ids));
+ }
+}
diff --git a/src/main/java/com/ruoyi/safe/controller/SafeFacilityLedgerController.java b/src/main/java/com/ruoyi/safe/controller/SafeFacilityLedgerController.java
index a17f0a3..29166ec 100644
--- a/src/main/java/com/ruoyi/safe/controller/SafeFacilityLedgerController.java
+++ b/src/main/java/com/ruoyi/safe/controller/SafeFacilityLedgerController.java
@@ -5,8 +5,10 @@
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.safe.pojo.SafeFacilityInspection;
+import com.ruoyi.safe.pojo.SafeFacilityInspectionTask;
import com.ruoyi.safe.pojo.SafeFacilityLedger;
import com.ruoyi.safe.service.SafeFacilityInspectionService;
+import com.ruoyi.safe.service.SafeFacilityInspectionTaskService;
import com.ruoyi.safe.service.SafeFacilityLedgerService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
@@ -31,6 +33,7 @@
private SafeFacilityLedgerService safeFacilityLedgerService;
private SafeFacilityInspectionService safeFacilityInspectionService;
+ private SafeFacilityInspectionTaskService safeFacilityInspectionTaskService;
@GetMapping("/page")
@Operation(summary = "鍒嗛〉鏌ヨ")
@@ -78,6 +81,15 @@
public R delSafeFacilityLedger(@PathVariable List<Integer> ids) {
// 鏍¢獙璁炬柦鏄惁鏈夊叧鑱旂殑宸℃璁板綍
for (Integer id : ids) {
+ long taskCount = safeFacilityInspectionTaskService.lambdaQuery()
+ .eq(SafeFacilityInspectionTask::getFacilityId, id)
+ .count();
+ if (taskCount > 0) {
+ SafeFacilityLedger ledger = safeFacilityLedgerService.getById(id);
+ String name = ledger != null ? ledger.getFacilityName() : String.valueOf(id);
+ return R.fail("璁炬柦銆�" + name + "銆嶅瓨鍦ㄥ叧鑱旂殑宸℃浠诲姟锛屾棤娉曞垹闄�");
+ }
+
long count = safeFacilityInspectionService.lambdaQuery()
.eq(com.ruoyi.safe.pojo.SafeFacilityInspection::getFacilityId, id)
.count();
diff --git a/src/main/java/com/ruoyi/safe/mapper/SafeFacilityInspectionTaskMapper.java b/src/main/java/com/ruoyi/safe/mapper/SafeFacilityInspectionTaskMapper.java
new file mode 100644
index 0000000..de36117
--- /dev/null
+++ b/src/main/java/com/ruoyi/safe/mapper/SafeFacilityInspectionTaskMapper.java
@@ -0,0 +1,14 @@
+package com.ruoyi.safe.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.safe.pojo.SafeFacilityInspectionTask;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 瀹夊叏鐢熶骇--瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟 Mapper 鎺ュ彛
+ * </p>
+ */
+@Mapper
+public interface SafeFacilityInspectionTaskMapper extends BaseMapper<SafeFacilityInspectionTask> {
+}
diff --git a/src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspection.java b/src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspection.java
index 577163e..b1ad0c6 100644
--- a/src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspection.java
+++ b/src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspection.java
@@ -36,6 +36,9 @@
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
+ @Schema(description = "瀹氭椂宸℃浠诲姟ID")
+ private Long scheduleTaskId;
+
@Schema(description = "宸℃缂栧彿")
private String inspectionCode;
@@ -45,6 +48,9 @@
@Schema(description = "宸℃绫诲瀷(瀹氭湡/涓存椂)")
private String inspectionType;
+ @Schema(description = "宸℃椤圭洰")
+ private String inspectionProject;
+
@Schema(description = "璁″垝宸℃鏃堕棿")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
diff --git a/src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspectionTask.java b/src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspectionTask.java
new file mode 100644
index 0000000..24191b4
--- /dev/null
+++ b/src/main/java/com/ruoyi/safe/pojo/SafeFacilityInspectionTask.java
@@ -0,0 +1,101 @@
+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;
+
+/**
+ * <p>
+ * 瀹夊叏鐢熶骇--瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟
+ * </p>
+ */
+@Data
+@TableName("safe_facility_inspection_task")
+@Schema(name = "SafeFacilityInspectionTask瀵硅薄", description = "瀹夊叏鐢熶骇--瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟")
+public class SafeFacilityInspectionTask implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @Schema(description = "宸℃浠诲姟鍚嶇О")
+ private String inspectionName;
+
+ @Schema(description = "璁炬柦ID")
+ private Integer facilityId;
+
+ @Schema(description = "璁炬柦缂栧彿")
+ private String facilityCode;
+
+ @Schema(description = "璁炬柦鍚嶇О")
+ private String facilityName;
+
+ @Schema(description = "宸℃椤圭洰")
+ private String inspectionProject;
+
+ @Schema(description = "宸℃浜篒D")
+ private Integer 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 = "鍒涘缓浜篒D")
+ @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 = "鏇存柊浜篒D")
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ private Integer updateUser;
+
+ @Schema(description = "绉熸埛ID")
+ @TableField(fill = FieldFill.INSERT)
+ private Integer tenantId;
+
+ @Schema(description = "閮ㄩ棬ID")
+ @TableField(fill = FieldFill.INSERT)
+ private Long deptId;
+
+ @TableField(exist = false)
+ private String inspectorName;
+}
diff --git a/src/main/java/com/ruoyi/safe/service/SafeFacilityInspectionTaskService.java b/src/main/java/com/ruoyi/safe/service/SafeFacilityInspectionTaskService.java
new file mode 100644
index 0000000..6dde30e
--- /dev/null
+++ b/src/main/java/com/ruoyi/safe/service/SafeFacilityInspectionTaskService.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.SafeFacilityInspectionTask;
+import org.quartz.SchedulerException;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * <p>
+ * 瀹夊叏鐢熶骇--瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟 鏈嶅姟绫�
+ * </p>
+ */
+public interface SafeFacilityInspectionTaskService extends IService<SafeFacilityInspectionTask> {
+
+ IPage<SafeFacilityInspectionTask> pageSafeFacilityInspectionTask(Page<SafeFacilityInspectionTask> page, SafeFacilityInspectionTask task);
+
+ boolean saveOrUpdateTask(SafeFacilityInspectionTask task) throws SchedulerException;
+
+ boolean removeTaskByIds(List<Long> ids);
+
+ LocalDateTime calculateFirstExecutionTime(String frequencyType, String frequencyDetail);
+
+ LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime);
+}
diff --git a/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionServiceImpl.java b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionServiceImpl.java
index b5301d6..7ef6490 100644
--- a/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionServiceImpl.java
+++ b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionServiceImpl.java
@@ -6,6 +6,7 @@
import com.ruoyi.basic.enums.ApplicationTypeEnum;
import com.ruoyi.basic.enums.RecordTypeEnum;
import com.ruoyi.basic.utils.FileUtil;
+import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.safe.pojo.SafeFacilityInspection;
@@ -54,9 +55,10 @@
@Override
public IPage<SafeFacilityInspection> pageSafeFacilityInspection(Page page, SafeFacilityInspection safeFacilityInspection) {
IPage<SafeFacilityInspection> result = this.lambdaQuery()
- .like(safeFacilityInspection.getInspectionCode() != null, SafeFacilityInspection::getInspectionCode, safeFacilityInspection.getInspectionCode())
+ .eq(safeFacilityInspection.getScheduleTaskId() != null, SafeFacilityInspection::getScheduleTaskId, safeFacilityInspection.getScheduleTaskId())
+ .like(StringUtils.isNotBlank(safeFacilityInspection.getInspectionCode()), SafeFacilityInspection::getInspectionCode, safeFacilityInspection.getInspectionCode())
.eq(safeFacilityInspection.getFacilityId() != null, SafeFacilityInspection::getFacilityId, safeFacilityInspection.getFacilityId())
- .eq(safeFacilityInspection.getStatus() != null, SafeFacilityInspection::getStatus, safeFacilityInspection.getStatus())
+ .eq(StringUtils.isNotBlank(safeFacilityInspection.getStatus()), SafeFacilityInspection::getStatus, safeFacilityInspection.getStatus())
.orderByDesc(SafeFacilityInspection::getCreateTime)
.page(page);
diff --git a/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskJob.java b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskJob.java
new file mode 100644
index 0000000..a7b5ab7
--- /dev/null
+++ b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskJob.java
@@ -0,0 +1,169 @@
+package com.ruoyi.safe.service.impl;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.safe.mapper.SafeFacilityInspectionMapper;
+import com.ruoyi.safe.mapper.SafeFacilityInspectionTaskMapper;
+import com.ruoyi.safe.pojo.SafeFacilityInspection;
+import com.ruoyi.safe.pojo.SafeFacilityInspectionTask;
+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 SafeFacilityInspectionTaskJob implements Job, Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private static final DateTimeFormatter CODE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
+ @Autowired
+ private SafeFacilityInspectionTaskMapper safeFacilityInspectionTaskMapper;
+ @Autowired
+ private SafeFacilityInspectionMapper safeFacilityInspectionMapper;
+
+ @Override
+ public void execute(JobExecutionContext context) throws JobExecutionException {
+ JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
+ Long taskId = jobDataMap.getLong("taskId");
+
+ try {
+ SafeFacilityInspectionTask task = safeFacilityInspectionTaskMapper.selectById(taskId);
+ if (task == null || Integer.valueOf(0).equals(task.getIsEnabled())) {
+ return;
+ }
+
+ LocalDateTime executionTime = LocalDateTime.now();
+ SafeFacilityInspection inspection = createFacilityInspection(task, executionTime);
+ safeFacilityInspectionMapper.insert(inspection);
+
+ task.setLastExecutionTime(executionTime);
+ task.setNextExecutionTime(calculateNextExecutionTime(
+ task.getFrequencyType(),
+ task.getFrequencyDetail(),
+ executionTime
+ ));
+ safeFacilityInspectionTaskMapper.updateById(task);
+ } catch (Exception e) {
+ throw new JobExecutionException(e);
+ }
+ }
+
+ private SafeFacilityInspection createFacilityInspection(SafeFacilityInspectionTask task, LocalDateTime executionTime) {
+ SafeFacilityInspection inspection = new SafeFacilityInspection();
+ inspection.setScheduleTaskId(task.getId());
+ inspection.setInspectionCode("SSXJ-" + executionTime.format(CODE_FORMATTER) + "-" + task.getId());
+ inspection.setFacilityId(task.getFacilityId());
+ inspection.setInspectionType("瀹氭湡宸℃");
+ inspection.setInspectionProject(task.getInspectionProject());
+ inspection.setPlanTime(task.getNextExecutionTime() != null ? task.getNextExecutionTime() : executionTime);
+ inspection.setInspectorId(task.getInspectorId());
+ inspection.setCheckDesc(buildCheckDesc(task));
+ inspection.setStatus("寰呭贰妫�");
+ inspection.setCreateUser(task.getCreateUser());
+ inspection.setUpdateUser(task.getCreateUser());
+ inspection.setCreateTime(executionTime);
+ inspection.setUpdateTime(executionTime);
+ inspection.setTenantId(task.getTenantId());
+ inspection.setDeptId(task.getDeptId());
+ return inspection;
+ }
+
+ private String buildCheckDesc(SafeFacilityInspectionTask task) {
+ String desc = "鑷姩鐢熸垚鑷畾鏃朵换鍔D: " + task.getId();
+ if (StringUtils.isNotBlank(task.getRemark())) {
+ desc = desc + "锛�" + task.getRemark();
+ }
+ return desc;
+ }
+
+ 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;
+ }
+}
diff --git a/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskScheduler.java b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskScheduler.java
new file mode 100644
index 0000000..da490f4
--- /dev/null
+++ b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskScheduler.java
@@ -0,0 +1,170 @@
+package com.ruoyi.safe.service.impl;
+
+import com.ruoyi.safe.pojo.SafeFacilityInspectionTask;
+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 SafeFacilityInspectionTaskScheduler {
+
+ private static final String JOB_GROUP = "safeFacilityInspectionTask";
+ private static final String TRIGGER_GROUP = "safeFacilityInspectionTaskTrigger";
+
+ private final Scheduler scheduler;
+
+ public void scheduleTask(SafeFacilityInspectionTask 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(SafeFacilityInspectionTask 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(SafeFacilityInspectionTask task) {
+ JobDataMap jobDataMap = new JobDataMap();
+ jobDataMap.put("taskId", task.getId());
+ jobDataMap.put("taskName", task.getInspectionName());
+ jobDataMap.put("frequencyType", task.getFrequencyType());
+
+ return JobBuilder.newJob(SafeFacilityInspectionTaskJob.class)
+ .withIdentity(getJobKey(task.getId()))
+ .withDescription(task.getInspectionName())
+ .usingJobData(jobDataMap)
+ .storeDurably(true)
+ .requestRecovery(true)
+ .build();
+ }
+
+ private Trigger buildJobTrigger(SafeFacilityInspectionTask 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("safeFacilityInspectionTask_" + taskId, JOB_GROUP);
+ }
+
+ private TriggerKey getTriggerKey(Long taskId) {
+ return new TriggerKey("safeFacilityInspectionTaskTrigger_" + taskId, TRIGGER_GROUP);
+ }
+
+ private String convertToCronExpression(SafeFacilityInspectionTask 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("鏃堕棿鏍煎紡蹇呴』涓篐H: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);
+ };
+ }
+}
diff --git a/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskServiceImpl.java b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskServiceImpl.java
new file mode 100644
index 0000000..a5027f9
--- /dev/null
+++ b/src/main/java/com/ruoyi/safe/service/impl/SafeFacilityInspectionTaskServiceImpl.java
@@ -0,0 +1,301 @@
+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.SafeFacilityInspectionTaskMapper;
+import com.ruoyi.safe.pojo.SafeFacilityInspectionTask;
+import com.ruoyi.safe.pojo.SafeFacilityLedger;
+import com.ruoyi.safe.service.SafeFacilityInspectionTaskService;
+import com.ruoyi.safe.service.SafeFacilityLedgerService;
+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.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 瀹夊叏鐢熶骇--瀹夊叏璁炬柦瀹氭椂宸℃浠诲姟 鏈嶅姟瀹炵幇绫�
+ * </p>
+ */
+@Service
+@RequiredArgsConstructor
+public class SafeFacilityInspectionTaskServiceImpl extends ServiceImpl<SafeFacilityInspectionTaskMapper, SafeFacilityInspectionTask> implements SafeFacilityInspectionTaskService {
+
+ 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 SafeFacilityInspectionTaskMapper safeFacilityInspectionTaskMapper;
+ private final SafeFacilityInspectionTaskScheduler safeFacilityInspectionTaskScheduler;
+ private final SafeFacilityLedgerService safeFacilityLedgerService;
+ private final SysUserMapper sysUserMapper;
+
+ @Override
+ public IPage<SafeFacilityInspectionTask> pageSafeFacilityInspectionTask(Page<SafeFacilityInspectionTask> page, SafeFacilityInspectionTask task) {
+ LambdaQueryWrapper<SafeFacilityInspectionTask> queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.like(StringUtils.isNotBlank(task.getInspectionName()), SafeFacilityInspectionTask::getInspectionName, task.getInspectionName())
+ .like(StringUtils.isNotBlank(task.getFacilityName()), SafeFacilityInspectionTask::getFacilityName, task.getFacilityName())
+ .like(StringUtils.isNotBlank(task.getFacilityCode()), SafeFacilityInspectionTask::getFacilityCode, task.getFacilityCode())
+ .eq(task.getFacilityId() != null, SafeFacilityInspectionTask::getFacilityId, task.getFacilityId())
+ .eq(task.getIsEnabled() != null, SafeFacilityInspectionTask::getIsEnabled, task.getIsEnabled())
+ .orderByDesc(SafeFacilityInspectionTask::getId);
+
+ IPage<SafeFacilityInspectionTask> result = safeFacilityInspectionTaskMapper.selectPage(page, queryWrapper);
+ fillInspectorName(result.getRecords());
+ return result;
+ }
+
+ @Override
+ @Transactional
+ public boolean saveOrUpdateTask(SafeFacilityInspectionTask task) throws SchedulerException {
+ SafeFacilityInspectionTask oldTask = null;
+ if (task.getId() != null) {
+ oldTask = safeFacilityInspectionTaskMapper.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 = safeFacilityInspectionTaskMapper.insert(task) > 0;
+ if (result && isEnabled(task.getIsEnabled())) {
+ safeFacilityInspectionTaskScheduler.scheduleTask(task);
+ }
+ return result;
+ }
+
+ result = safeFacilityInspectionTaskMapper.updateById(task) > 0;
+ if (result) {
+ boolean oldEnabled = oldTask != null && isEnabled(oldTask.getIsEnabled());
+ boolean newEnabled = isEnabled(task.getIsEnabled());
+ if (!newEnabled) {
+ safeFacilityInspectionTaskScheduler.unscheduleTask(task.getId());
+ } else if (oldEnabled) {
+ safeFacilityInspectionTaskScheduler.rescheduleTask(task);
+ } else {
+ safeFacilityInspectionTaskScheduler.scheduleTask(task);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ @Transactional
+ public boolean removeTaskByIds(List<Long> ids) {
+ boolean removed = removeBatchByIds(ids);
+ if (removed) {
+ for (Long id : ids) {
+ safeFacilityInspectionTaskScheduler.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(SafeFacilityInspectionTask task, SafeFacilityInspectionTask oldTask) {
+ if (StringUtils.isBlank(task.getInspectionName())) {
+ throw new IllegalArgumentException("宸℃浠诲姟鍚嶇О涓嶈兘涓虹┖");
+ }
+ if (task.getFacilityId() == null) {
+ throw new IllegalArgumentException("璇烽�夋嫨瀹夊叏璁炬柦");
+ }
+ if (StringUtils.isBlank(task.getInspectionProject())) {
+ throw new IllegalArgumentException("宸℃椤圭洰涓嶈兘涓虹┖");
+ }
+ if (task.getInspectorId() == null) {
+ throw new IllegalArgumentException("宸℃浜轰笉鑳戒负绌�");
+ }
+
+ SafeFacilityLedger ledger = safeFacilityLedgerService.getById(task.getFacilityId());
+ if (ledger == null) {
+ throw new IllegalArgumentException("閫夋嫨鐨勫畨鍏ㄨ鏂戒笉瀛樺湪");
+ }
+ if ("鎶ュ簾".equals(ledger.getStatus())) {
+ throw new IllegalArgumentException("鎶ュ簾璁炬柦涓嶈兘鍒涘缓宸℃浠诲姟");
+ }
+ task.setFacilityCode(ledger.getFacilityCode());
+ task.setFacilityName(ledger.getFacilityName());
+ 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("鏃堕棿鏍煎紡蹇呴』涓篐H: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, SafeFacilityInspectionTask 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<SafeFacilityInspectionTask> records) {
+ if (records == null || records.isEmpty()) {
+ return;
+ }
+
+ List<Long> userIds = records.stream()
+ .map(SafeFacilityInspectionTask::getInspectorId)
+ .filter(Objects::nonNull)
+ .map(Integer::longValue)
+ .distinct()
+ .collect(Collectors.toList());
+ if (userIds.isEmpty()) {
+ return;
+ }
+
+ Map<Long, String> userNameMap = sysUserMapper.selectUserByIds(userIds).stream()
+ .collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName, (v1, v2) -> v1));
+ for (SafeFacilityInspectionTask record : records) {
+ if (record.getInspectorId() != null) {
+ record.setInspectorName(userNameMap.getOrDefault(record.getInspectorId().longValue(), "鏈煡鐢ㄦ埛"));
+ }
+ }
+ }
+}
diff --git a/src/main/resources/mapper/safe/SafeFacilityInspectionMapper.xml b/src/main/resources/mapper/safe/SafeFacilityInspectionMapper.xml
index 18955d8..285f71d 100644
--- a/src/main/resources/mapper/safe/SafeFacilityInspectionMapper.xml
+++ b/src/main/resources/mapper/safe/SafeFacilityInspectionMapper.xml
@@ -4,9 +4,11 @@
<resultMap type="com.ruoyi.safe.pojo.SafeFacilityInspection" id="SafeFacilityInspectionResult">
<id property="id" column="id"/>
+ <result property="scheduleTaskId" column="schedule_task_id"/>
<result property="inspectionCode" column="inspection_code"/>
<result property="facilityId" column="facility_id"/>
<result property="inspectionType" column="inspection_type"/>
+ <result property="inspectionProject" column="inspection_project"/>
<result property="planTime" column="plan_time"/>
<result property="inspectorId" column="inspector_id"/>
<result property="actualTime" column="actual_time"/>
--
Gitblit v1.9.3