From d6c07c838abeabdd23c4fdcfc69e08a9aaa9725f Mon Sep 17 00:00:00 2001
From: maven <2163098428@qq.com>
Date: 星期一, 02 三月 2026 17:52:04 +0800
Subject: [PATCH] yys 劳保报表开发

---
 src/main/java/com/ruoyi/lavorissue/service/LavorIssueService.java              |    6 
 src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java |    2 
 src/main/java/com/ruoyi/device/pojo/DeviceRepair.java                          |    5 
 src/main/java/com/ruoyi/device/mapper/MaintenanceTaskMapper.java               |   11 
 src/main/java/com/ruoyi/lavorissue/controller/LavorIssueController.java        |   21 +
 src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java       |   60 +++
 src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java                       |  113 ++++++
 src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java      |  278 ++++++++++++++++
 src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java    |  119 +++++++
 src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java             |   22 +
 src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java       |    1 
 src/main/java/com/ruoyi/lavorissue/service/impl/LavorIssueServiceImpl.java     |   96 +++++
 src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java            |  243 ++++++++++++++
 src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java                     |   15 
 14 files changed, 990 insertions(+), 2 deletions(-)

diff --git a/src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java b/src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java
new file mode 100644
index 0000000..fd8398c
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java
@@ -0,0 +1,60 @@
+package com.ruoyi.device.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.device.pojo.MaintenanceTask;
+import com.ruoyi.device.service.MaintenanceTaskService;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author :yys
+ * @date : 2025/12/22 14:58
+ */
+@Api(tags = "璁惧淇濆吇瀹氭椂浠诲姟绠$悊")
+@RestController
+@RequestMapping("/deviceMaintenanceTask")
+public class MaintenanceTaskController extends BaseController {
+
+
+    @Autowired
+    private MaintenanceTaskService maintenanceTaskService;
+
+
+    @GetMapping("/listPage")
+    @ApiOperation(value = "璁惧淇濆吇瀹氭椂浠诲姟鍒楄〃")
+    public AjaxResult listPage(Page page, MaintenanceTask maintenanceTask) {
+        return maintenanceTaskService.listPage(page,maintenanceTask);
+    }
+
+
+    @PostMapping("/add")
+    @ApiOperation(value = "娣诲姞璁惧淇濆吇瀹氭椂浠诲姟")
+    @Log(title = "璁惧淇濆吇瀹氭椂浠诲姟", businessType = BusinessType.INSERT)
+    public AjaxResult add(@RequestBody MaintenanceTask maintenanceTask) {
+        return maintenanceTaskService.add(maintenanceTask);
+    }
+
+    @PostMapping("/update")
+    @ApiOperation(value = "淇敼璁惧淇濆吇瀹氭椂浠诲姟")
+    @Log(title = "璁惧淇濆吇瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
+    public AjaxResult update(@RequestBody MaintenanceTask maintenanceTask) {
+        return maintenanceTaskService.updateByMaintenanceTaskId(maintenanceTask);
+    }
+
+    @DeleteMapping("/delete")
+    @ApiOperation(value = "鍒犻櫎璁惧淇濆吇瀹氭椂浠诲姟")
+    @Log(title = "璁惧淇濆吇瀹氭椂浠诲姟", businessType = BusinessType.DELETE)
+    public AjaxResult delete(@RequestBody List<Long> ids) {
+        return maintenanceTaskService.delete(ids);
+    }
+
+
+}
diff --git a/src/main/java/com/ruoyi/device/mapper/MaintenanceTaskMapper.java b/src/main/java/com/ruoyi/device/mapper/MaintenanceTaskMapper.java
new file mode 100644
index 0000000..b7cc18a
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/mapper/MaintenanceTaskMapper.java
@@ -0,0 +1,11 @@
+package com.ruoyi.device.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.device.pojo.MaintenanceTask;
+
+/**
+ * @author :yys
+ * @date : 2025/12/22 14:56
+ */
+public interface MaintenanceTaskMapper extends BaseMapper<MaintenanceTask> {
+}
diff --git a/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java b/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
index 4b7a971..dd5fbd4 100644
--- a/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
+++ b/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
@@ -26,6 +26,21 @@
     @ApiModelProperty("璁惧淇濆吇閲戦")
     private BigDecimal maintenancePrice;
 
+    @ApiModelProperty("淇濆吇浠诲姟id")
+    private Long maintenanceTaskId;
+
+    @ApiModelProperty(value = "棰戞")
+    private String frequencyType;
+
+    @ApiModelProperty(value = "棰戞璇︽儏")
+    private String frequencyDetail;
+
+    @ApiModelProperty(value = "涓嬫鎵ц鏃堕棿")
+    private LocalDateTime nextExecutionTime;
+
+    @ApiModelProperty(value = "鏈�鍚庢墽琛屾椂闂�")
+    private LocalDateTime lastExecutionTime;
+
 
     private String deviceName;
 
diff --git a/src/main/java/com/ruoyi/device/pojo/DeviceRepair.java b/src/main/java/com/ruoyi/device/pojo/DeviceRepair.java
index 06b672c..ee92be3 100644
--- a/src/main/java/com/ruoyi/device/pojo/DeviceRepair.java
+++ b/src/main/java/com/ruoyi/device/pojo/DeviceRepair.java
@@ -52,9 +52,12 @@
     @ApiModelProperty("缁翠慨缁撴灉")
     private String maintenanceResult;
 
-    @ApiModelProperty("鐘舵�� 0 寰呯淮淇� 1瀹岀粨")
+    @ApiModelProperty("鐘舵�� 0 寰呯淮淇� 1瀹岀粨 2寰呭鏍� 3瀹℃牳涓嶉�氳繃")
     private Integer status;
 
+    @ApiModelProperty("瀹℃牳浜�")
+    private String auditName;
+
     @ApiModelProperty("鍒涘缓鏃堕棿")
     @TableField(fill = FieldFill.INSERT)
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
diff --git a/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
new file mode 100644
index 0000000..1f7b3f2
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
@@ -0,0 +1,113 @@
+package com.ruoyi.device.pojo;
+
+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 com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * @author :yys
+ * @date : 2025/9/19 10:27
+ */
+@Data
+@ApiModel
+@TableName("maintenance_task")
+public class MaintenanceTask {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "瑙勬牸鍨嬪彿")
+    private String deviceModel;
+
+    /**
+     * 涓婚敭ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "璁惧鍚嶇О")
+    @Excel(name = "淇濆吇浠诲姟鍚嶇О")
+    private String taskName;
+
+    @ApiModelProperty(value = "璁惧id")
+    private Long taskId;
+
+    @ApiModelProperty(value = "棰戞")
+    @Excel(name = "棰戞")
+    private String frequencyType;
+
+    @ApiModelProperty(value = "棰戞璇︽儏")
+    @Excel(name = "寮�濮嬫棩鏈熶笌鏃堕棿")
+    private String frequencyDetail;
+
+    @ApiModelProperty(value = "涓嬫鎵ц鏃堕棿")
+    private LocalDateTime nextExecutionTime;
+
+    @ApiModelProperty(value = "鏈�鍚庢墽琛屾椂闂�")
+    private LocalDateTime lastExecutionTime;
+
+    @ApiModelProperty(value = "鏄惁婵�娲�")
+    private boolean isActive;
+
+    @ApiModelProperty(value = "澶囨敞")
+    @Excel(name = "澶囨敞")
+    private String remarks;
+
+    @ApiModelProperty(value = "褰曞叆浜篿d")
+    private Long registrantId;
+
+    @ApiModelProperty(value = "褰曞叆浜�")
+    @Excel(name = "褰曞叆浜�")
+    private String registrant;
+
+    @ApiModelProperty(value = "褰曞叆鏃ユ湡")
+    @Excel(name = "褰曞叆鏃ユ湡", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate registrationDate;
+
+    @ApiModelProperty(value = "鐘舵�� 寰呭鏍� 瀹℃牳涓嶉�氳繃 瀹℃牳閫氳繃")
+    private String status;
+
+    @ApiModelProperty(value = "瀹℃牳浜�")
+    @Excel(name = "瀹℃牳浜�")
+    private String auditName;
+
+    @ApiModelProperty(value = "杞垹闄ゆ爣蹇楋紝0=鏈垹闄わ紝1=宸插垹闄�")
+    private Integer deleted;
+
+    @TableField(exist = false)
+    private String dateStr;
+
+    @ApiModelProperty(value = "鍒涘缓璇ヨ褰曠殑鐢ㄦ埛")
+    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
+    private Integer createUser;
+
+    @ApiModelProperty(value = "璁板綍鍒涘缓鏃堕棿")
+    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
+//    @JsonFormat(pattern = "yyyy-MM-dd")
+//    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "鏈�鍚庝慨鏀硅璁板綍鐨勭敤鎴�")
+    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    @ApiModelProperty(value = "璁板綍鏈�鍚庢洿鏂版椂闂�")
+    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "绉熸埛ID")
+    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
+    private Long tenantId;
+
+}
diff --git a/src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java b/src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java
new file mode 100644
index 0000000..19cb6ed
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java
@@ -0,0 +1,22 @@
+package com.ruoyi.device.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.device.pojo.MaintenanceTask;
+import com.ruoyi.framework.web.domain.AjaxResult;
+
+import java.util.List;
+
+/**
+ * @author :yys
+ * @date : 2025/12/22 14:56
+ */
+public interface MaintenanceTaskService extends IService<MaintenanceTask> {
+    AjaxResult listPage(Page page, MaintenanceTask maintenanceTask);
+
+    AjaxResult add(MaintenanceTask maintenanceTask);
+
+    AjaxResult updateByMaintenanceTaskId(MaintenanceTask maintenanceTask);
+
+    AjaxResult delete(List<Long> ids);
+}
diff --git a/src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java b/src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java
index c771b47..391201e 100644
--- a/src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java
+++ b/src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java
@@ -54,6 +54,7 @@
         DeviceLedger byId = deviceLedgerService.getById(deviceRepair.getDeviceLedgerId());
         deviceRepair.setDeviceName(byId.getDeviceName());
         deviceRepair.setDeviceModel(byId.getDeviceModel());
+        deviceRepair.setStatus(2);
         boolean save = this.save(deviceRepair);
         if (save){
             return AjaxResult.success();
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
new file mode 100644
index 0000000..3367050
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
@@ -0,0 +1,243 @@
+package com.ruoyi.device.service.impl;
+
+import com.ruoyi.device.pojo.DeviceMaintenance;
+import com.ruoyi.device.pojo.MaintenanceTask;
+import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+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.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Component
+@DisallowConcurrentExecution // 绂佹骞跺彂鎵ц鍚屼竴涓狫ob
+public class MaintenanceTaskJob implements Job, Serializable {
+    private static final long serialVersionUID = 1L; // 蹇呴』瀹氫箟搴忓垪鍖朓D
+
+    @Autowired
+    private DeviceMaintenanceServiceImpl deviceMaintenanceService;
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Override
+    public void execute(JobExecutionContext context) throws JobExecutionException {
+        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
+        // 淇绫诲瀷杞崲閿欒锛屾纭幏鍙杢askId
+        Long taskId = jobDataMap.getLong("maintenanceTaskId");
+
+        try {
+            // 3. 灏濊瘯鏌ヨ浣犵殑涓氬姟鏁版嵁
+            // 閫氳繃JDBC妯℃澘鏌ヨ瀹氭椂浠诲姟淇℃伅锛屼娇鐢ㄥ弬鏁板寲鏌ヨ闃叉SQL娉ㄥ叆
+            String yourSql = "SELECT * FROM maintenance_task where id = ? and status = '瀹℃牳閫氳繃'";
+            List<MaintenanceTask> tasks = jdbcTemplate.query(
+                    yourSql,
+                    new BeanPropertyRowMapper<>(MaintenanceTask.class),
+                    taskId
+            );
+            MaintenanceTask timingTask = tasks.isEmpty() ? null : tasks.get(0);
+            if (timingTask == null) {
+                throw new JobExecutionException("MaintenanceTaskJob鎵句笉鍒板畾鏃朵换鍔�: " + taskId);
+            }
+
+            // 2. 鍒涘缓骞朵繚瀛樺贰妫�浠诲姟璁板綍 - 杩欏氨鏄偍鎻愪緵鐨勪唬鐮佸簲璇ユ斁鐨勪綅缃�
+            DeviceMaintenance deviceMaintenance = createInspectionTask(timingTask);
+            deviceMaintenanceService.save(deviceMaintenance);
+
+            // 3. 鏇存柊瀹氭椂浠诲姟鐨勬墽琛屾椂闂�
+            if (!tasks.isEmpty()) {
+                MaintenanceTask task = tasks.get(0);
+
+                // 鏇存柊鏈�鍚庢墽琛屾椂闂翠负褰撳墠鏃堕棿
+                LocalDateTime lastExecutionTime = LocalDateTime.now();
+
+                // 璁$畻涓嬫鎵ц鏃堕棿
+                LocalDateTime nextExecutionTime = calculateNextExecutionTime(
+                        task.getFrequencyType(),
+                        task.getFrequencyDetail(),
+                        lastExecutionTime
+                );
+
+                // 鎵ц鏇存柊鎿嶄綔
+                String updateSql = "UPDATE maintenance_task " +
+                        "SET last_execution_time = ?, next_execution_time = ? " +
+                        "WHERE id = ?";
+
+                jdbcTemplate.update(
+                        updateSql,
+                        lastExecutionTime,
+                        nextExecutionTime,
+                        taskId
+                );
+            }
+        } catch (Exception e) {
+            throw new JobExecutionException(e);
+        }
+    }
+
+    // 杩欏氨鏄偍鎻愪緵鐨勪唬鐮佸皝瑁呮垚鐨勬柟娉�
+    private DeviceMaintenance createInspectionTask(MaintenanceTask timingTask) {
+        DeviceMaintenance inspectionTask = new DeviceMaintenance();
+
+        // 澶嶅埗鍩烘湰灞炴��
+        inspectionTask.setDeviceName(timingTask.getTaskName());
+        inspectionTask.setMaintenanceTaskId(timingTask.getId());
+        inspectionTask.setDeviceLedgerId(timingTask.getTaskId());
+        inspectionTask.setMaintenancePlanTime(LocalDateTime.now());
+        inspectionTask.setFrequencyType(timingTask.getFrequencyType());
+        inspectionTask.setFrequencyDetail(timingTask.getFrequencyDetail());
+        inspectionTask.setTenantId(timingTask.getTenantId());
+        inspectionTask.setStatus(0);
+        inspectionTask.setDeviceModel(timingTask.getDeviceModel());
+        inspectionTask.setCreateUser(Integer.parseInt(timingTask.getRegistrantId().toString()));
+        inspectionTask.setUpdateTime(LocalDateTime.now());
+        inspectionTask.setCreateTime(LocalDateTime.now());
+        inspectionTask.setUpdateUser(Integer.parseInt(timingTask.getRegistrantId().toString()));
+        return inspectionTask;
+    }
+
+
+    /**
+     * 璁$畻涓嬫鎵ц鏃堕棿
+     */
+    private LocalDateTime calculateNextExecutionTime(String frequencyType,
+                                                     String frequencyDetail,
+                                                     LocalDateTime currentTime) {
+        try {
+            switch (frequencyType) {
+                case "DAILY":
+                    return calculateDailyNextTime(frequencyDetail, currentTime);
+                case "WEEKLY":
+                    return calculateWeeklyNextTime(frequencyDetail, currentTime);
+                case "MONTHLY":
+                    return calculateMonthlyNextTime(frequencyDetail, currentTime);
+                case "QUARTERLY":
+                    return calculateQuarterlyNextTime(frequencyDetail, currentTime);
+                default:
+                    throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("璁$畻涓嬫鎵ц鏃堕棿澶辫触: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 璁$畻姣忔棩浠诲姟鐨勪笅娆℃墽琛屾椂闂�
+     */
+    private LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime current) {
+        LocalTime executionTime = LocalTime.parse(timeStr); // 瑙f瀽鏍煎紡 "HH:mm"
+        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(",");
+        String dayOfWeekStr = parts[0];  // 濡� "MON" 鎴� "MON|WED|FRI"
+        LocalTime time = LocalTime.parse(parts[1]); // 鏃堕棿閮ㄥ垎
+
+        // 瑙f瀽鏄熸湡鍑�(鏀寔澶氫釜鏄熸湡)
+        Set<DayOfWeek> targetDays = parseDayOfWeeks(dayOfWeekStr);
+
+        // 浠庡綋鍓嶆椂闂村紑濮嬫壘涓嬩竴涓鍚堟潯浠剁殑鏄熸湡鍑�
+        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]);
+        LocalTime time = LocalTime.parse(parts[1]);
+
+        // 浠庝笅涓湀寮�濮嬭绠�
+        LocalDateTime nextTime = current.plusMonths(1)
+                .withDayOfMonth(Math.min(dayOfMonth, current.plusMonths(1).toLocalDate().lengthOfMonth()))
+                .with(time);
+
+        return nextTime;
+    }
+
+    /**
+     * 璁$畻姣忓搴︿换鍔$殑涓嬫鎵ц鏃堕棿
+     */
+    private LocalDateTime calculateQuarterlyNextTime(String detail, LocalDateTime current) {
+        String[] parts = detail.split(",");
+        int quarterMonth = Integer.parseInt(parts[0]); // 1=绗�1涓湀锛�2=绗�2涓湀锛�3=绗�3涓湀
+        int dayOfMonth = Integer.parseInt(parts[1]);
+        LocalTime time = LocalTime.parse(parts[2]);
+
+        // 璁$畻褰撳墠瀛e害
+        int currentQuarter = (current.getMonthValue() - 1) / 3 + 1;
+        int currentMonthInQuarter = (current.getMonthValue() - 1) % 3 + 1;
+
+        YearMonth targetYearMonth;
+        if (currentMonthInQuarter < quarterMonth) {
+            // 鏈搴﹀唴杩樻湁鎵ц鏈轰細
+            targetYearMonth = YearMonth.from(current)
+                    .plusMonths(quarterMonth - currentMonthInQuarter);
+        } else {
+            // 闇�瑕佸埌涓嬩釜瀛e害
+            targetYearMonth = YearMonth.from(current)
+                    .plusMonths(3 - currentMonthInQuarter + quarterMonth);
+        }
+
+        // 澶勭悊鏈堟湯鏃ユ湡
+        int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth());
+
+        return LocalDateTime.of(
+                targetYearMonth.getYear(),
+                targetYearMonth.getMonthValue(),
+                adjustedDay,
+                time.getHour(),
+                time.getMinute()
+        );
+    }
+
+    /**
+     * 瑙f瀽鏄熸湡鍑犲瓧绗︿覆
+     */
+    private Set<DayOfWeek> parseDayOfWeeks(String dayOfWeekStr) {
+        Set<DayOfWeek> days = new HashSet<>();
+        String[] dayStrs = dayOfWeekStr.split("\\|");
+
+        for (String dayStr : dayStrs) {
+            switch (dayStr) {
+                case "MON": days.add(DayOfWeek.MONDAY); break;
+                case "TUE": days.add(DayOfWeek.TUESDAY); break;
+                case "WED": days.add(DayOfWeek.WEDNESDAY); break;
+                case "THU": days.add(DayOfWeek.THURSDAY); break;
+                case "FRI": days.add(DayOfWeek.FRIDAY); break;
+                case "SAT": days.add(DayOfWeek.SATURDAY); break;
+                case "SUN": days.add(DayOfWeek.SUNDAY); break;
+                default: throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈熷嚑: " + dayStr);
+            }
+        }
+
+        return days;
+    }
+}
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
new file mode 100644
index 0000000..384862b
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
@@ -0,0 +1,278 @@
+package com.ruoyi.device.service.impl;
+
+import com.ruoyi.device.pojo.MaintenanceTask;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
+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;
+
+/**
+ * @author :yys
+ * @date : 2025/12/22 15:16
+ */
+@Service
+@Slf4j
+public class MaintenanceTaskScheduler {
+
+    @Autowired
+    private Scheduler scheduler;
+
+    /**
+     * 娣诲姞鏂颁换鍔″埌璋冨害鍣�
+     */
+    public void scheduleMaintenanceTask(MaintenanceTask task){
+        try {
+            JobDetail jobDetail = buildJobDetail(task);
+            Trigger trigger = buildJobTrigger(task, jobDetail);
+            scheduler.scheduleJob(jobDetail, trigger);
+        }catch (SchedulerException e){
+            log.error("SchedulerException scheduleMaintenanceTask ERROR",e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 鏇存柊宸叉湁浠诲姟
+     */
+    public void rescheduleMaintenanceTask(MaintenanceTask task){
+       try{
+           TriggerKey triggerKey = new TriggerKey("triggerMaintenanceTask_" + task.getId());
+
+           // 鑾峰彇鐜版湁瑙﹀彂鍣ㄥ苟杞崲涓� CronTrigger
+           Trigger oldTrigger = scheduler.getTrigger(triggerKey);
+           if (!(oldTrigger instanceof CronTrigger)) {
+               throw new SchedulerException("Existing trigger is not a CronTrigger");
+           }
+
+           // 3. 鏋勫缓CronTrigger锛岀‘淇濇寔涔呭寲閰嶇疆
+           CronTrigger newTrigger = TriggerBuilder.newTrigger()
+                   .withIdentity(triggerKey)                // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
+                   .withDescription(task.getTaskName() + "_TRIGGER") // 瑙﹀彂鍣ㄦ弿杩�
+                   .forJob(oldTrigger.getJobKey())                       // 鍏宠仈瀵瑰簲鐨凧ob
+                   .withSchedule(CronScheduleBuilder
+                           .cronSchedule(convertToCronExpression(task)) // 閿欒繃鎵ц鏃剁殑绛栫暐锛堟牴鎹笟鍔¤皟鏁达級
+                   )
+                   // 4. 璁剧疆寮�濮嬫椂闂达紙鑻ヤ负null鍒欑珛鍗崇敓鏁堬級
+                   .startAt(task.getNextExecutionTime() != null
+                           ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
+                           : new Date())
+                   .build();
+           scheduler.rescheduleJob(triggerKey, newTrigger);
+       }catch (SchedulerException e){
+           log.error("SchedulerException rescheduleMaintenanceTask ERROR",e);
+           throw new RuntimeException(e);
+       }
+    }
+
+    /**
+     * 鏆傚仠浠诲姟
+     */
+    public void pauseMaintenanceTask(Long taskId) throws SchedulerException {
+        JobKey jobKey = new JobKey("MaintenanceTask_" + taskId);
+        scheduler.pauseJob(jobKey);
+    }
+
+    /**
+     * 鎭㈠浠诲姟
+     */
+    public void resumeMaintenanceTask(Long taskId) throws SchedulerException {
+        JobKey jobKey = new JobKey("MaintenanceTask_" + taskId);
+        scheduler.resumeJob(jobKey);
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟
+     */
+    public void unscheduleMaintenanceTask(Long taskId){
+        try {
+            JobKey jobKey = new JobKey("MaintenanceTask_" + taskId);
+            scheduler.deleteJob(jobKey);
+        }catch (SchedulerException e){
+            log.error("SchedulerException unscheduleMaintenanceTask ERROR",e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    private JobDetail buildJobDetail(MaintenanceTask task) {
+        // 1. 鏋勫缓鍞竴JobKey锛堝熀浜庝换鍔D锛岀‘淇濋噸鍚悗鑳借瘑鍒級
+        JobKey jobKey = new JobKey("MaintenanceTask_" + task.getId());
+
+        // 2. 灏佽浠诲姟鏁版嵁锛堜粎浣跨敤鍩烘湰绫诲瀷锛岀‘淇濆彲搴忓垪鍖栵級
+        JobDataMap jobDataMap = new JobDataMap();
+        jobDataMap.put("maintenanceTaskId", task.getId());           // 浠诲姟ID锛圠ong锛屽彲搴忓垪鍖栵級
+        jobDataMap.put("taskName", task.getTaskName());   // 浠诲姟鍚嶇О锛圫tring锛屽彲搴忓垪鍖栵級
+        jobDataMap.put("taskType", task.getFrequencyType()); // 浠诲姟绫诲瀷锛圫tring锛�
+        // 鎸夐渶娣诲姞鍏朵粬蹇呰鐨勫熀鏈被鍨嬪弬鏁�
+
+        // 3. 鏋勫缓JobDetail锛岃缃寔涔呭寲鐩稿叧灞炴��
+        return JobBuilder.newJob(MaintenanceTaskJob.class)
+                .withIdentity(jobKey)                    // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
+                .withDescription(task.getTaskName())     // 浠诲姟鎻忚堪锛屽瓨鍏ユ暟鎹簱
+                .usingJobData(jobDataMap)                // 缁戝畾浠诲姟鏁版嵁
+                .storeDurably(true)                          // 鍗充娇娌℃湁瑙﹀彂鍣ㄥ叧鑱斾篃鎸佷箙鍖栦繚瀛�
+                .requestRecovery(true)                   // 褰撹皟搴﹀櫒宕╂簝鍚庢仮澶嶆椂锛岄噸鏂版墽琛屾湭瀹屾垚鐨勪换鍔�
+                .build();
+    }
+
+    private Trigger buildJobTrigger(MaintenanceTask task, JobDetail jobDetail) {
+        // 1. 鏋勫缓鍞竴TriggerKey锛堝熀浜庝换鍔D锛�
+        TriggerKey triggerKey = new TriggerKey("triggerMaintenanceTask_" + task.getId());
+
+        // 2. 鐢熸垚Cron琛ㄨ揪寮忥紙鍘熼�昏緫涓嶅彉锛�
+        String cronExpression = convertToCronExpression(task);
+
+        // 3. 鏋勫缓CronTrigger锛岀‘淇濇寔涔呭寲閰嶇疆
+        return TriggerBuilder.newTrigger()
+                .withIdentity(triggerKey)                // 鍞竴鏍囪瘑锛岀敤浜庢寔涔呭寲瀛樺偍
+                .withDescription(task.getTaskName() + "_TRIGGER") // 瑙﹀彂鍣ㄦ弿杩�
+                .forJob(jobDetail)                       // 鍏宠仈瀵瑰簲鐨凧ob
+                .withSchedule(CronScheduleBuilder
+                        .cronSchedule(cronExpression)
+                        .withMisfireHandlingInstructionDoNothing() // 閿欒繃鎵ц鏃剁殑绛栫暐锛堟牴鎹笟鍔¤皟鏁达級
+                )
+                // 4. 璁剧疆寮�濮嬫椂闂达紙鑻ヤ负null鍒欑珛鍗崇敓鏁堬級
+                .startAt(task.getNextExecutionTime() != null
+                        ? Date.from(task.getNextExecutionTime().atZone(ZoneId.systemDefault()).toInstant())
+                        : new Date())
+                .build();
+    }
+    private String convertToCronExpression(MaintenanceTask task) {
+        // 鍙傛暟鏍¢獙
+        if (task == null || task.getFrequencyType() == null || task.getFrequencyDetail() == null) {
+            throw new IllegalArgumentException("浠诲姟鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        // 浣跨敤switch纭繚鏉′欢浜掓枼
+        String frequencyType = task.getFrequencyType().toUpperCase(); // 缁熶竴杞负澶у啓姣旇緝
+        switch (frequencyType) {
+            case "DAILY":
+                return convertDailyToCron(task.getFrequencyDetail());
+            case "WEEKLY":
+                return convertWeeklyToCron(task.getFrequencyDetail());
+            case "MONTHLY":
+                return convertMonthlyToCron(task.getFrequencyDetail());
+            case "QUARTERLY":
+                return convertQuarterlyToCron(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 = convertDayNamesToCron(parts[0]);
+        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 convertQuarterlyToCron(String frequencyDetail) {
+        String[] parts = validateAndSplit(frequencyDetail, ",", 3);
+        int month = validateMonth(parts[0]);  // 楠岃瘉鏈堜唤(1-12)
+        int day = validateDayOfMonth(parts[1]);  // 楠岃瘉鏃ユ湡
+        LocalTime time = parseTime(parts[2]);  // 瑙f瀽鏃堕棿
+
+        // 璁$畻瀛e害璧峰鏈堜唤(1鏈�=1, 4鏈�=4, 7鏈�=7, 10鏈�=10)
+        int quarterStartMonth = ((month - 1) / 3) * 3 + 1;
+
+        return String.format("0 %d %d %d %d/3 ?",
+                time.getMinute(),
+                time.getHour(),
+                day,
+                quarterStartMonth);
+    }
+
+    // 鏂板楠岃瘉鏈堜唤鐨勬柟娉�(1-12)
+    private int validateMonth(String monthStr) {
+        try {
+            int month = Integer.parseInt(monthStr);
+            if (month < 1 || month > 12) {
+                throw new IllegalArgumentException("鏈堜唤蹇呴』鍦�1-12涔嬮棿");
+            }
+            return month;
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("鏃犳晥鐨勬湀浠芥牸寮�");
+        }
+    }
+
+    // 杈呭姪鏂规硶锛氳В鏋愭椂闂�
+    private LocalTime parseTime(String timeStr) {
+        try {
+            return LocalTime.parse(timeStr);
+        } catch (DateTimeParseException e) {
+            throw new IllegalArgumentException("鏃堕棿鏍煎紡蹇呴』涓篐H:mm", e);
+        }
+    }
+
+    // 杈呭姪鏂规硶锛氶獙璇佸苟鍒嗗壊瀛楃涓�
+    private String[] validateAndSplit(String input, String delimiter, int expectedParts) {
+        String[] parts = input.split(delimiter);
+        if (parts.length != expectedParts) {
+            throw new IllegalArgumentException(
+                    String.format("鏍煎紡閿欒锛屽簲涓�%d閮ㄥ垎鐢�'%s'鍒嗛殧", expectedParts, delimiter));
+        }
+        return parts;
+    }
+
+    // 杈呭姪鏂规硶锛氶獙璇佹湀浠戒腑鐨勬棩
+    private int validateDayOfMonth(String dayStr) {
+        int day = Integer.parseInt(dayStr);
+        if (day < 1 || day > 31) {
+            throw new IllegalArgumentException("鏃ユ湡蹇呴』鍦�1-31涔嬮棿");
+        }
+        return day;
+    }
+
+    // 杈呭姪鏂规硶锛氶獙璇佸搴︿腑鐨勬湀
+    private int validateMonthInQuarter(String monthStr) {
+        int month = Integer.parseInt(monthStr);
+        if (month < 1 || month > 3) {
+            throw new IllegalArgumentException("瀛e害鏈堜唤蹇呴』鏄�1銆�2鎴�3");
+        }
+        return month;
+    }
+
+    // 杞崲鏄熸湡鍑犲悕绉�
+    private String convertDayNamesToCron(String dayNames) {
+        return Arrays.stream(dayNames.split("\\|"))
+                .map(this::convertSingleDayName)
+                .collect(Collectors.joining(","));
+    }
+
+    // 杞崲鍗曚釜鏄熸湡鍑犲悕绉�
+    private String convertSingleDayName(String dayName) {
+        switch (dayName.toUpperCase()) {
+            case "MON": return "MON";
+            case "TUE": return "TUE";
+            case "WED": return "WED";
+            case "THU": return "THU";
+            case "FRI": return "FRI";
+            case "SAT": return "SAT";
+            case "SUN": return "SUN";
+            default: throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈熷嚑: " + dayName);
+        }
+    }
+    
+}
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
new file mode 100644
index 0000000..96e3eca
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
@@ -0,0 +1,119 @@
+package com.ruoyi.device.service.impl;
+
+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.common.utils.bean.BeanUtils;
+import com.ruoyi.device.mapper.MaintenanceTaskMapper;
+import com.ruoyi.device.pojo.MaintenanceTask;
+import com.ruoyi.device.service.MaintenanceTaskService;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.inspectiontask.pojo.TimingTask;
+import com.ruoyi.inspectiontask.service.impl.TimingTaskServiceImpl;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.mapper.SysUserMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+ * @author :yys
+ * @date : 2025/12/22 14:57
+ */
+@Service
+@Slf4j
+public class MaintenanceTaskServiceImpl extends ServiceImpl<MaintenanceTaskMapper, MaintenanceTask> implements MaintenanceTaskService {
+
+    @Autowired
+    private MaintenanceTaskMapper maintenanceTaskMapper;
+
+    @Autowired
+    private SysUserMapper sysUserMapper;
+
+    @Autowired
+    private TimingTaskServiceImpl timingTaskService;
+
+    @Autowired
+    private MaintenanceTaskScheduler maintenanceTaskScheduler;
+
+    @Override
+    public AjaxResult listPage(Page page, MaintenanceTask maintenanceTask) {
+        Page<MaintenanceTask> taskPage = maintenanceTaskMapper.selectPage(page, null);
+        // 2. 濡傛灉娌℃湁鏁版嵁锛岀洿鎺ヨ繑鍥炵┖鍒嗛〉
+        if (taskPage.getRecords().isEmpty()) {
+            return AjaxResult.success(taskPage);
+        }
+
+        // 3. 鏀堕泦鎵�鏈夐渶瑕佹煡璇㈢殑鐢ㄦ埛ID
+        Set<Long> userIds = new HashSet<>();
+
+        // 鏀堕泦鐧昏浜篒D
+        taskPage.getRecords().forEach(task -> {
+            if (task.getRegistrantId() != null) {
+                userIds.add(task.getRegistrantId());
+            }
+        });
+
+        // 4. 鎵归噺鏌ヨ鐢ㄦ埛淇℃伅
+        Map<Long, String> userNickNameMap = new HashMap<>();
+        if (!userIds.isEmpty()) {
+            List<SysUser> users = sysUserMapper.selectUserByIds((new ArrayList<>(userIds)));
+            users.forEach(user -> userNickNameMap.put(user.getUserId(), user.getNickName()));
+        }
+        taskPage.getRecords().forEach(task -> {
+            // 璁剧疆鐧昏浜烘樀绉�
+            if (task.getRegistrantId() != null) {
+                task.setRegistrant(userNickNameMap.getOrDefault(task.getRegistrantId(), "鏈煡鐢ㄦ埛"));
+            }
+        });
+        return AjaxResult.success(taskPage);
+    }
+
+    @Override
+    public AjaxResult add(MaintenanceTask maintenanceTask) {
+        if(StringUtils.isEmpty(maintenanceTask.getAuditName())) {
+            return AjaxResult.warn("璇峰~鍐欏鏍镐汉");
+        }
+        maintenanceTask.setActive(true);
+        // 璁$畻棣栨鎵ц鏃堕棿
+        TimingTask task = new TimingTask();
+        task.setFrequencyType(maintenanceTask.getFrequencyType());
+        task.setFrequencyDetail(maintenanceTask.getFrequencyDetail());
+        LocalDateTime firstExecutionTime = timingTaskService.calculateFirstExecutionTime(task);
+        maintenanceTask.setNextExecutionTime(firstExecutionTime);
+        maintenanceTask.setStatus("寰呭鏍�");
+        int insert = maintenanceTaskMapper.insert(maintenanceTask);
+        if (insert > 0) {
+            maintenanceTaskScheduler.scheduleMaintenanceTask(maintenanceTask);
+        }
+        return AjaxResult.success("娣诲姞鎴愬姛");
+    }
+
+    @Override
+    public AjaxResult updateByMaintenanceTaskId(MaintenanceTask maintenanceTask) {
+        MaintenanceTask maintenanceTask1 = maintenanceTaskMapper.selectById(maintenanceTask.getId());
+        if (maintenanceTask1 == null) {
+            return AjaxResult.warn("娌℃湁姝ゆ暟鎹�");
+        }
+        BeanUtils.copyProperties(maintenanceTask, maintenanceTask1);
+        int update = maintenanceTaskMapper.updateById(maintenanceTask1);
+        if (update > 0) {
+            maintenanceTaskScheduler.rescheduleMaintenanceTask(maintenanceTask1);
+        }
+        return AjaxResult.success("鏇存柊鎴愬姛");
+    }
+
+    @Override
+    public AjaxResult delete(List<Long> ids) {
+        int delete = maintenanceTaskMapper.deleteBatchIds(ids);
+        if (delete > 0) {
+            ids.forEach(id -> {
+                maintenanceTaskScheduler.unscheduleMaintenanceTask(id);
+            });
+        }
+        return AjaxResult.success("鍒犻櫎鎴愬姛");
+    }
+}
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
index c2797d4..db65f78 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -144,7 +144,7 @@
         }
     }
 
-    private LocalDateTime calculateFirstExecutionTime(TimingTask task) {
+    public LocalDateTime calculateFirstExecutionTime(TimingTask task) {
         // 鏍规嵁棰戠巼绫诲瀷鍜岃鎯呰绠楅娆℃墽琛屾椂闂�
         String frequencyType = task.getFrequencyType();
         if ("DAILY".equals(frequencyType)) {
diff --git a/src/main/java/com/ruoyi/lavorissue/controller/LavorIssueController.java b/src/main/java/com/ruoyi/lavorissue/controller/LavorIssueController.java
index ffaed68..2fbb16f 100644
--- a/src/main/java/com/ruoyi/lavorissue/controller/LavorIssueController.java
+++ b/src/main/java/com/ruoyi/lavorissue/controller/LavorIssueController.java
@@ -130,6 +130,27 @@
         return AjaxResult.success(statisticsLaborIssue);
     }
 
+    @ApiOperation("鍙戞斁杩涘害-鎬昏")
+    @GetMapping("/progressTotal")
+    public AjaxResult progressTotal(LaborIssue laborIssue) throws Exception {
+        Map<String, Object> list = laborIssueService.progressTotal(laborIssue);
+        return AjaxResult.success(list);
+    }
+
+    @ApiOperation("棰嗗彇杩涘害鍗犳瘮")
+    @GetMapping("/progressPercent")
+    public AjaxResult progressPercent(LaborIssue laborIssue) throws Exception {
+        Map<String, Object> list = laborIssueService.progressPercent(laborIssue);
+        return AjaxResult.success(list);
+    }
+
+    @ApiOperation("杩涘害鍒嗗竷")
+    @GetMapping("/progressDistribution")
+    public AjaxResult progressDistribution(LaborIssue laborIssue) throws Exception {
+        Map<String, Object> list = laborIssueService.progressDistribution(laborIssue);
+        return AjaxResult.success(list);
+    }
+
 
 
     /**
diff --git a/src/main/java/com/ruoyi/lavorissue/service/LavorIssueService.java b/src/main/java/com/ruoyi/lavorissue/service/LavorIssueService.java
index a0fd247..7ffbdcd 100644
--- a/src/main/java/com/ruoyi/lavorissue/service/LavorIssueService.java
+++ b/src/main/java/com/ruoyi/lavorissue/service/LavorIssueService.java
@@ -31,4 +31,10 @@
     void exportCopy(HttpServletResponse response, LaborIssue laborIssue) throws UnsupportedEncodingException;
 
     List<Map<String, Object>> statisticsList(LaborIssue laborIssue);
+
+    Map<String, Object> progressTotal(LaborIssue laborIssue);
+
+    Map<String, Object> progressPercent(LaborIssue laborIssue);
+
+    Map<String, Object> progressDistribution(LaborIssue laborIssue);
 }
diff --git a/src/main/java/com/ruoyi/lavorissue/service/impl/LavorIssueServiceImpl.java b/src/main/java/com/ruoyi/lavorissue/service/impl/LavorIssueServiceImpl.java
index 9e66121..ef94325 100644
--- a/src/main/java/com/ruoyi/lavorissue/service/impl/LavorIssueServiceImpl.java
+++ b/src/main/java/com/ruoyi/lavorissue/service/impl/LavorIssueServiceImpl.java
@@ -93,6 +93,102 @@
         return records;
     }
 
+    @Override
+    public Map<String, Object> progressTotal(LaborIssue req) {
+        StartAndEndDateDto startAndEndDateDto = getStartAndEndDateDto(req.getSeason(), req.getIssueDate());
+        req.setStartDate(startAndEndDateDto.getStartDate());
+        req.setEndDate(startAndEndDateDto.getEndDate());
+        List<LaborIssue> laborIssueIPage = lavorIssueMapper.list(req);
+        Map<String, Object> map = new HashMap<>();
+        map.put("total", 0); // 鍙戞斁鎬绘暟閲�
+        // 棰嗗彇鏁伴噺
+        map.put("adopted", 0);
+        // 鏈鍙栨暟閲�
+        map.put("notAdopted", 0);
+        // 棰嗗彇瀹屾垚鐜�
+        map.put("adoptedPercent", 0);
+        if(!CollectionUtils.isEmpty(laborIssueIPage)){
+            long sum = laborIssueIPage.stream().mapToLong(LaborIssue::getNum).sum();
+            map.put("total", sum);
+            long sum1 = laborIssueIPage
+                    .stream()
+                    .filter(laborIssue -> laborIssue.getAdoptedDate() != null)
+                    .mapToLong(LaborIssue::getNum)
+                    .sum();
+            map.put("adopted", sum1);
+            map.put("notAdopted", sum - sum1);
+            map.put("adoptedPercent", sum1 * 100.0 / sum);
+        }
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> progressPercent(LaborIssue req) {
+        StartAndEndDateDto startAndEndDateDto = getStartAndEndDateDto(req.getSeason(), req.getIssueDate());
+        req.setStartDate(startAndEndDateDto.getStartDate());
+        req.setEndDate(startAndEndDateDto.getEndDate());
+        List<LaborIssue> laborIssueIPage = lavorIssueMapper.list(req);
+        Map<String, Object> map = new HashMap<>();
+        // 棰嗗彇鏁伴噺
+        map.put("adopted", 0);
+        // 鏈鍙栨暟閲�
+        map.put("notAdopted", 0);
+        if(!CollectionUtils.isEmpty(laborIssueIPage)){
+            long sum = laborIssueIPage.stream().mapToLong(LaborIssue::getNum).sum();
+            long sum1 = laborIssueIPage
+                    .stream()
+                    .filter(laborIssue -> laborIssue.getAdoptedDate() != null)
+                    .mapToLong(LaborIssue::getNum)
+                    .sum();
+            map.put("adopted", sum1);
+            map.put("notAdopted", sum - sum1);
+        }
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> progressDistribution(LaborIssue req) {
+        StartAndEndDateDto startAndEndDateDto = getStartAndEndDateDto(req.getSeason(), req.getIssueDate());
+        req.setStartDate(startAndEndDateDto.getStartDate());
+        req.setEndDate(startAndEndDateDto.getEndDate());
+        List<LaborIssue> laborIssueIPage = lavorIssueMapper.list(req);
+        Map<String, Object> map = new HashMap<>();
+        if(!CollectionUtils.isEmpty(laborIssueIPage)){
+            // 鏍规嵁鍙戞斁鏃ユ湡锛岄鐢ㄦ棩鏈熻绠楀強鏃跺凡棰嗗彇锛屽強鏃舵湭棰嗗彇锛岃秴鏃跺凡棰嗗彇锛岃秴鏃舵湭棰嗗彇鏁版嵁
+            // 鍙婃椂宸查鍙�
+            List<List<Long>> list = new ArrayList<>();
+            List<Long> sumList = new ArrayList<>();
+            long sum = laborIssueIPage.stream()
+                    .filter(laborIssue -> laborIssue.getAdoptedDate() != null && laborIssue.getAdoptedDate().getTime() <= laborIssue.getIssueDate().getTime())
+                    .mapToLong(LaborIssue::getNum)
+                    .sum();
+            // 鍙婃椂鏈鍙�
+            long sum1 = laborIssueIPage.stream()
+                    .filter(laborIssue -> laborIssue.getAdoptedDate() == null && laborIssue.getIssueDate().getTime() <= new Date().getTime())
+                    .mapToLong(LaborIssue::getNum)
+                    .sum();
+            sumList.add(sum);
+            sumList.add(sum1);
+            list.add(sumList);
+            List<Long> sumList1 = new ArrayList<>();
+            // 瓒呮椂宸查鍙�
+            long sum2 = laborIssueIPage.stream()
+                    .filter(laborIssue -> laborIssue.getAdoptedDate() != null && laborIssue.getAdoptedDate().getTime() > laborIssue.getIssueDate().getTime())
+                    .mapToLong(LaborIssue::getNum)
+                    .sum();
+            // 瓒呮椂鏈鍙�
+            long sum3 = laborIssueIPage.stream()
+                    .filter(laborIssue -> laborIssue.getAdoptedDate() == null && laborIssue.getIssueDate().getTime() > new Date().getTime())
+                    .mapToLong(LaborIssue::getNum)
+                    .sum();
+            sumList1.add(sum2);
+            sumList1.add(sum3);
+            list.add(sumList1);
+            map.put("series", list);
+        }
+        return map;
+    }
+
     public StartAndEndDateDto getStartAndEndDateDto(Integer season,Date payDate){
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         StartAndEndDateDto startAndEndDateDto = new StartAndEndDateDto();

--
Gitblit v1.9.3