Kaynağa Gözat

工单扣分重做

ouyj 3 ay önce
ebeveyn
işleme
7b98ffaa3d

+ 13 - 6
ygtx-gxt/src/main/java/com/ygtx/gxt/mapper/GxtRepairOrderMapper.java

@@ -112,11 +112,18 @@ public interface GxtRepairOrderMapper
      * @return 维修工单集合
      */
     public List<GxtRepairOrder> selectLatestGxtRepairOrderByDeviceId(@Param("pcsDeviceId") Long pcsDeviceId, @Param("limit") Integer limit);
-    
-    public List<GxtRepairOrder> selectGxtRepairOrderByDeviceIdWithCondition(@Param("pcsDeviceId") Long pcsDeviceId, 
-        @Param("workOrderStatus") String workOrderStatus, 
-        @Param("excludeStatus") boolean excludeStatus, 
-        @Param("orderByField") String orderByField, 
+
+    public List<GxtRepairOrder> selectGxtRepairOrderByDeviceIdWithCondition(@Param("pcsDeviceId") Long pcsDeviceId,
+        @Param("workOrderStatus") String workOrderStatus,
+        @Param("excludeStatus") boolean excludeStatus,
+        @Param("orderByField") String orderByField,
         @Param("limit") Integer limit,
         @Param("excludeRepairMethod2") Boolean excludeRepairMethod2);
-}
+
+    /**
+     * 查询需要扣分的维修工单列表(已完成或已归档,复运时间不为空,且未被扣过分的工单)
+     *
+     * @return 维修工单集合
+     */
+    public List<GxtRepairOrder> selectGxtRepairOrderListForDeduction();
+}

+ 13 - 6
ygtx-gxt/src/main/java/com/ygtx/gxt/mapper/GxtWorkOrderMapper.java

@@ -103,7 +103,7 @@ public interface GxtWorkOrderMapper {
     
     /**
      * 根据ID查询维保工单及人员信息
-     * 
+     *
      * @param id 维保工单主键
      * @return 维保工单
      */
@@ -125,10 +125,17 @@ public interface GxtWorkOrderMapper {
      * @return 维保工单集合
      */
     public List<GxtWorkOrder> selectLatestGxtWorkOrderByDeviceId(@Param("pcsDeviceId") Long pcsDeviceId, @Param("limit") Integer limit);
-    
-    public List<GxtWorkOrder> selectGxtWorkOrderByDeviceIdWithCondition(@Param("pcsDeviceId") Long pcsDeviceId, 
-        @Param("workOrderStatus") String workOrderStatus, 
-        @Param("excludeStatus") boolean excludeStatus, 
-        @Param("orderByField") String orderByField, 
+
+    public List<GxtWorkOrder> selectGxtWorkOrderByDeviceIdWithCondition(@Param("pcsDeviceId") Long pcsDeviceId,
+        @Param("workOrderStatus") String workOrderStatus,
+        @Param("excludeStatus") boolean excludeStatus,
+        @Param("orderByField") String orderByField,
         @Param("limit") Integer limit);
+
+    /**
+     * 查询需要扣分的维保工单列表(已完成或已归档,复运时间不为空,且未被扣过分的工单)
+     *
+     * @return 维保工单集合
+     */
+    public List<GxtWorkOrder> selectGxtWorkOrderListForDeduction();
 }

+ 9 - 2
ygtx-gxt/src/main/java/com/ygtx/gxt/service/IGxtRepairOrderService.java

@@ -9,11 +9,11 @@ import com.ygtx.common.core.page.PageDomain;
 
 /**
  * 维修工单Service接口
- * 
+ *
  * @author ouyj
  * @date 2025-10-30
  */
-public interface IGxtRepairOrderService 
+public interface IGxtRepairOrderService
 {
     /**
      * 查询维修工单
@@ -239,4 +239,11 @@ public interface IGxtRepairOrderService
      * @return 维修工单集合
      */
     public List<GxtRepairOrder> selectGxtRepairOrderByDeviceIdWithCondition(Long pcsDeviceId, String workOrderStatus, boolean excludeStatus, String orderByField, Integer limit, Boolean excludeRepairMethod2);
+
+    /**
+     * 查询需要扣分的维修工单列表(已完成或已归档,复运时间不为空,且未被扣过分的工单)
+     *
+     * @return 维修工单集合
+     */
+    public List<GxtRepairOrder> selectGxtRepairOrderListForDeduction();
 }

+ 8 - 1
ygtx-gxt/src/main/java/com/ygtx/gxt/service/IGxtWorkOrderService.java

@@ -267,4 +267,11 @@ public interface IGxtWorkOrderService {
      * @return 维保工单集合
      */
     public List<GxtWorkOrder> selectGxtWorkOrderByDeviceIdWithCondition(Long pcsDeviceId, String workOrderStatus, boolean excludeStatus, String orderByField, Integer limit);
-}
+    
+    /**
+     * 查询需要扣分的维保工单列表(已完成或已归档,复运时间不为空,且未被扣过分的工单)
+     *
+     * @return 维保工单集合
+     */
+    public List<GxtWorkOrder> selectGxtWorkOrderListForDeduction();
+}

+ 3 - 1
ygtx-gxt/src/main/java/com/ygtx/gxt/service/impl/GxtOrderScoreDetailServiceImpl.java

@@ -53,7 +53,9 @@ public class GxtOrderScoreDetailServiceImpl implements IGxtOrderScoreDetailServi
     @Override
     public int insertGxtOrderScoreDetail(GxtOrderScoreDetail gxtOrderScoreDetail)
     {
-        gxtOrderScoreDetail.setCreateTime(DateUtils.getNowDate());
+        if(gxtOrderScoreDetail.getCreateTime() == null){
+            gxtOrderScoreDetail.setCreateTime(DateUtils.getNowDate());
+        }
         return gxtOrderScoreDetailMapper.insertGxtOrderScoreDetail(gxtOrderScoreDetail);
     }
 

+ 6 - 1
ygtx-gxt/src/main/java/com/ygtx/gxt/service/impl/GxtRepairOrderServiceImpl.java

@@ -2230,9 +2230,14 @@ public class GxtRepairOrderServiceImpl implements IGxtRepairOrderService
     public List<GxtRepairOrder> selectLatestGxtRepairOrderByDeviceId(Long pcsDeviceId, Integer limit) {
         return gxtRepairOrderMapper.selectLatestGxtRepairOrderByDeviceId(pcsDeviceId, limit);
     }
-    
+
     @Override
     public List<GxtRepairOrder> selectGxtRepairOrderByDeviceIdWithCondition(Long pcsDeviceId, String workOrderStatus, boolean excludeStatus, String orderByField, Integer limit, Boolean excludeRepairMethod2) {
         return gxtRepairOrderMapper.selectGxtRepairOrderByDeviceIdWithCondition(pcsDeviceId, workOrderStatus, excludeStatus, orderByField, limit, excludeRepairMethod2);
     }
+
+    @Override
+    public List<GxtRepairOrder> selectGxtRepairOrderListForDeduction() {
+        return gxtRepairOrderMapper.selectGxtRepairOrderListForDeduction();
+    }
 }

+ 6 - 1
ygtx-gxt/src/main/java/com/ygtx/gxt/service/impl/GxtWorkOrderServiceImpl.java

@@ -2228,9 +2228,14 @@ public class GxtWorkOrderServiceImpl implements IGxtWorkOrderService
     public List<GxtWorkOrder> selectLatestGxtWorkOrderByDeviceId(Long pcsDeviceId, Integer limit) {
         return gxtWorkOrderMapper.selectLatestGxtWorkOrderByDeviceId(pcsDeviceId, limit);
     }
-    
+
     @Override
     public List<GxtWorkOrder> selectGxtWorkOrderByDeviceIdWithCondition(Long pcsDeviceId, String workOrderStatus, boolean excludeStatus, String orderByField, Integer limit) {
         return gxtWorkOrderMapper.selectGxtWorkOrderByDeviceIdWithCondition(pcsDeviceId, workOrderStatus, excludeStatus, orderByField, limit);
     }
+
+    @Override
+    public List<GxtWorkOrder> selectGxtWorkOrderListForDeduction() {
+        return gxtWorkOrderMapper.selectGxtWorkOrderListForDeduction();
+    }
 }

+ 263 - 102
ygtx-gxt/src/main/java/com/ygtx/gxt/task/EquipmentSafeOperationRewardTask.java

@@ -4,18 +4,14 @@ import com.ygtx.common.core.domain.entity.SysUser;
 import com.ygtx.common.core.domain.model.LoginUser;
 import com.ygtx.common.utils.DateUtils;
 import com.ygtx.common.utils.SecurityUtils;
-import com.ygtx.common.utils.spring.SpringUtils;
 import com.ygtx.framework.web.service.SysPermissionService;
 import com.ygtx.gxt.domain.*;
-import com.ygtx.gxt.mapper.GxtRepairOrderMapper;
-import com.ygtx.gxt.mapper.GxtWorkOrderMapper;
 import com.ygtx.gxt.service.*;
 import com.ygtx.system.mapper.SysUserMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.EnableScheduling;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Component;
@@ -64,6 +60,12 @@ public class EquipmentSafeOperationRewardTask {
     @Autowired
     private SysPermissionService permissionService;
 
+    @Autowired
+    private IGxtRepairOrderFlowService repairOrderFlowService;
+
+    @Autowired
+    private IGxtWorkOrderFlowService workOrderFlowService;
+
     // 限制每次查询的最大工单数量,防止数据量过大导致性能问题
     private static final int MAX_ORDERS_PER_QUERY = 1;
 
@@ -101,6 +103,45 @@ public class EquipmentSafeOperationRewardTask {
         }
     }
 
+    public void processDeductionForStoppedOrders() {
+        log.info("开始执行工单扣分任务");
+
+        // 设置系统用户上下文
+        setSystemUserContext();
+
+        try {
+            // 查询满足条件的维修工单(已归档,复运时间不为空,且未被扣过分)
+            List<GxtRepairOrder> repairOrdersToDeduct = repairOrderService.selectGxtRepairOrderListForDeduction();
+            log.info("找到 {} 个需要扣分的维修工单", repairOrdersToDeduct.size());
+
+            // 对维修工单进行扣分处理
+            for (GxtRepairOrder repairOrder : repairOrdersToDeduct) {
+                try {
+                    processRepairOrderDeduction(repairOrder);
+                } catch (Exception e) {
+                    log.error("处理维修工单 {} 扣分时发生异常", repairOrder.getWorkOrderProjectNo(), e);
+                }
+            }
+
+            // 查询满足条件的维保工单(已归档,复运时间不为空,且未被扣过分)
+            List<GxtWorkOrder> workOrdersToDeduct = workOrderService.selectGxtWorkOrderListForDeduction();
+            log.info("找到 {} 个需要扣分的维保工单", workOrdersToDeduct.size());
+
+            // 对维保工单进行扣分处理
+            for (GxtWorkOrder workOrder : workOrdersToDeduct) {
+                try {
+                    processWorkOrderDeduction(workOrder);
+                } catch (Exception e) {
+                    log.error("处理维保工单 {} 扣分时发生异常", workOrder.getWorkOrderProjectNo(), e);
+                }
+            }
+
+            log.info("工单扣分任务执行完成");
+        } catch (Exception e) {
+            log.error("执行工单扣分任务时发生异常", e);
+        }
+    }
+
     /**
      * 处理单个设备的连续安全运行奖励
      * 
@@ -138,71 +179,13 @@ public class EquipmentSafeOperationRewardTask {
             return; // 必须最少能找到任意的GxtRepairOrder或者GxtWorkOrder当中的其中一个,否则数据不完整,不用再继续后面的步骤
         }
 
-        /*if (processedData.latestOccurOrPauseTime == null) {
+        if (processedData.latestOccurOrPauseTime == null) {
             log.debug("设备 {} 未找到任何occurTime或pauseTime数据,跳过处理", equipment.getEquipmentCode());
             return; // 必须最少能找到任意的GxtRepairOrder或者GxtWorkOrder当中的其中一个,否则数据不完整,不用再继续后面的步骤
-        }*/
+        }
 
         // 检查是否在安全运行中
-        if (processedData.latestOccurOrPauseTime != null && 
-            (processedData.latestRestartTime == null || processedData.latestRestartTime.before(processedData.latestOccurOrPauseTime))) {
-            // 执行扣分逻辑
-            log.debug("设备 {} 的最新occurTime/pauseTime({})比restartTime({})晚或restartTime为空,需要进行扣分", 
-                equipment.getEquipmentCode(), processedData.latestOccurOrPauseTime, processedData.latestRestartTime);
-            
-            // 计算从最新故障/暂停时间到现在的天数差
-            int daysSinceFailure = DateUtils.calculateDateDifference(DateUtils.getNowDate(), processedData.latestOccurOrPauseTime);
-            if (daysSinceFailure > 0) {
-                // 获取奖励配置(用于扣分)
-                GxtSafeOperationReward rewardQuery = new GxtSafeOperationReward();
-                rewardQuery.setStatus(0);
-                List<GxtSafeOperationReward> rewardConfigs = safeOperationRewardService.selectGxtSafeOperationRewardList(rewardQuery);
-                if (rewardConfigs.isEmpty()) {
-                    log.warn("未找到任何启用的安全运行奖励配置,无法进行扣分");
-                    return;
-                }
-
-                // 按照safeDuration升序排序
-                rewardConfigs.sort(Comparator.comparingInt(GxtSafeOperationReward::getSafeDuration));
-
-                // 获取适用于扣分的配置
-                GxtSafeOperationReward applicableDeduction = getApplicableRewardConfig(rewardConfigs, daysSinceFailure);
-                if (applicableDeduction != null) {
-                    // 使用预处理的数据进行扣分处理
-                    if (processedData.relatedRepairOrder != null) {
-                        if(!"2".equals(processedData.relatedRepairOrder.getRepairMethod())){
-                            // 如果对应的工单是GxtRepairOrder,则获取的是downtimeScore的值
-                            BigDecimal deductionScore = applicableDeduction.getDowntimeScore();
-                            if (deductionScore != null && deductionScore.compareTo(BigDecimal.ZERO) < 0) { // 确保是负数
-                                log.info("设备 {} 停运 {} 天,扣减维修工单 {} 停机分值 {}",
-                                        equipment.getEquipmentCode(), daysSinceFailure, processedData.relatedRepairOrder.getWorkOrderProjectNo(), deductionScore);
-
-                                // 对相关工单人员进行扣分操作
-                                updatePersonStopScoreForRepairOrder(processedData.relatedRepairOrder, deductionScore);
-                                // 更新月度统计数据
-                                updateMonthlyScoreDataForStopScore(processedData.relatedRepairOrder, deductionScore);
-                            }
-                        }
-                    } else if (processedData.relatedWorkOrder != null) {
-                        // 如果对应的工单是GxtWorkOrder,则获取的是downtimeScore的值
-                        BigDecimal deductionScore = applicableDeduction.getDowntimeScore();
-                        if (deductionScore != null && deductionScore.compareTo(BigDecimal.ZERO) < 0) { // 确保是负数
-                            log.info("设备 {} 停运 {} 天,扣减维保工单 {} 停机分值 {}", 
-                                equipment.getEquipmentCode(), daysSinceFailure, processedData.relatedWorkOrder.getWorkOrderProjectNo(), deductionScore);
-                            
-                            // 对相关工单人员进行扣分操作
-                            updatePersonStopScoreForWorkOrder(processedData.relatedWorkOrder, deductionScore);
-                            // 更新月度统计数据
-                            updateMonthlyScoreDataForStopScore(processedData.relatedWorkOrder, deductionScore);
-                        }
-                    } else {
-                        log.warn("设备 {} 未找到对应的工单信息,无法进行扣分", equipment.getEquipmentCode());
-                    }
-                } else {
-                    log.debug("设备 {} 停运天数 {} 未找到对应的扣分配置", equipment.getEquipmentCode(), daysSinceFailure);
-                }
-            }
-        } else if (processedData.latestRestartTime != null) { // 只有在restartTime不为空时才执行原来的奖励逻辑
+        if (!processedData.latestRestartTime.before(processedData.latestOccurOrPauseTime)) {
             // 计算安全运行天数
             int daysBetween = DateUtils.calculateDateDifference(DateUtils.getNowDate(), processedData.latestRestartTime);
             if (daysBetween <= 0) {
@@ -248,9 +231,9 @@ public class EquipmentSafeOperationRewardTask {
                 // 如果对应的工单是GxtWorkOrder,则获取的是plannedMaintenanceScore的值
                 BigDecimal rewardScore = applicableReward.getPlannedMaintenanceScore();
                 if (rewardScore != null && rewardScore.compareTo(BigDecimal.ZERO) > 0) {
-                    log.info("设备 {} 安全运行 {} 天,奖励维保工单 {} 计划检修奖励分值 {}", 
+                    log.info("设备 {} 安全运行 {} 天,奖励维保工单 {} 计划检修奖励分值 {}",
                         equipment.getEquipmentCode(), daysBetween, processedData.relatedWorkOrder.getWorkOrderProjectNo(), rewardScore);
-                    
+
                     // 然后在获取这个工单所对应的人员数据,对这些人员进行加分操作
                     updatePersonRunScoreForWorkOrder(processedData.relatedWorkOrder, rewardScore);
                     // 更新月度统计数据
@@ -259,8 +242,6 @@ public class EquipmentSafeOperationRewardTask {
             } else {
                 log.warn("设备 {} 未找到对应的工单信息", equipment.getEquipmentCode());
             }
-        } else {
-            log.debug("设备 {} 未找到有效的restartTime,无法进行奖励或扣分", equipment.getEquipmentCode());
         }
     }
 
@@ -706,11 +687,12 @@ public class EquipmentSafeOperationRewardTask {
 
     /**
      * 为维修工单人员更新停机扣分
-     * 
-     * @param repairOrder 维修工单
+     *
+     * @param repairOrder    维修工单
      * @param deductionScore 扣分分数
+     * @param archiveTime
      */
-    private void updatePersonStopScoreForRepairOrder(GxtRepairOrder repairOrder, BigDecimal deductionScore) {
+    private void updatePersonStopScoreForRepairOrder(GxtRepairOrder repairOrder, BigDecimal deductionScore, Date archiveTime) {
         try {
             List<GxtRepairOrderPerson> persons = repairOrder.getRepairOrderPersonList();
             if (persons == null || persons.isEmpty()) {
@@ -746,7 +728,7 @@ public class EquipmentSafeOperationRewardTask {
             log.info("维修工单 {} 共更新 {} 名人员的停机扣分和总得分", repairOrder.getWorkOrderProjectNo(), updatedPersons.size());
             
             // 添加工单个人分数明细数据
-            addOrderScoreDetailsForStopScoreRepair(repairOrder, persons, deductionScore, 3); // 3代表停机扣分
+            addOrderScoreDetailsForStopScoreRepair(repairOrder, persons, deductionScore, 3, archiveTime); // 3代表停机扣分
         } catch (Exception e) {
             log.error("更新维修工单 {} 人员停机扣分时发生异常", repairOrder.getWorkOrderProjectNo(), e);
         }
@@ -758,7 +740,7 @@ public class EquipmentSafeOperationRewardTask {
      * @param workOrder 维保工单
      * @param deductionScore 扣分分数
      */
-    private void updatePersonStopScoreForWorkOrder(GxtWorkOrder workOrder, BigDecimal deductionScore) {
+    private void updatePersonStopScoreForWorkOrder(GxtWorkOrder workOrder, BigDecimal deductionScore, Date archiveTime) {
         try {
             List<GxtWorkOrderPerson> persons = workOrder.getWorkOrderPersonList();
             if (persons == null || persons.isEmpty()) {
@@ -794,23 +776,23 @@ public class EquipmentSafeOperationRewardTask {
             log.info("维保工单 {} 共更新 {} 名人员的停机扣分和总得分", workOrder.getWorkOrderProjectNo(), updatedPersons.size());
             
             // 添加工单个人分数明细数据
-            addOrderScoreDetailsForStopScoreWork(workOrder, persons, deductionScore, 3); // 3代表停机扣分
+            addOrderScoreDetailsForStopScoreWork(workOrder, persons, deductionScore, 3, archiveTime); // 3代表停机扣分
         } catch (Exception e) {
             log.error("更新维保工单 {} 人员停机扣分时发生异常", workOrder.getWorkOrderProjectNo(), e);
         }
     }
 
     /**
-     * 更新月度统计数据以反映停机扣分
-     * 
+     * 更新月度统计数据以反映停机扣分,使用工单归档时间确定月份
+     *
      * @param repairOrder 维修工单
      * @param deductionScore 扣分分数
      */
-    private void updateMonthlyScoreDataForStopScore(GxtRepairOrder repairOrder, BigDecimal deductionScore) {
+    private void updateMonthlyScoreDataForStopScore(GxtRepairOrder repairOrder, BigDecimal deductionScore, Date archiveTime) {
         try {
-            // 使用当前日期所在的月份(因为扣分是在当前时间处理的)
-            SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM");
-            String monthPeriod = sdf.format(new Date());
+            // 使用归档时间所在的月份
+            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM");
+            String monthPeriod = sdf.format(archiveTime);
 
             // 获取场站ID
             Long deptId = repairOrder.getPcsStationPid();
@@ -835,7 +817,7 @@ public class EquipmentSafeOperationRewardTask {
                 monthScore.setCreateBy(SecurityUtils.getUsername());
                 monthScore.setCreateTime(new Date());
                 monthScoreService.insertGxtMonthScore(monthScore);
-                
+
                 // 重新查询刚插入的记录
                 scoreList = monthScoreService.selectGxtMonthScoreList(queryScore);
                 if (!scoreList.isEmpty()) {
@@ -853,16 +835,19 @@ public class EquipmentSafeOperationRewardTask {
     }
 
     /**
-     * 更新月度统计数据以反映停机扣分
-     * 
+     * 更新月度统计数据以反映停机扣分,使用工单归档时间确定月份
+     *
      * @param workOrder 维保工单
      * @param deductionScore 扣分分数
      */
-    private void updateMonthlyScoreDataForStopScore(GxtWorkOrder workOrder, BigDecimal deductionScore) {
+    private void updateMonthlyScoreDataForStopScore(GxtWorkOrder workOrder, BigDecimal deductionScore, Date archiveTime) {
         try {
-            // 使用当前日期所在的月份(因为扣分是在当前时间处理的)
+            // 获取工单归档时间来确定月份
+            //Date archiveTime = getArchiveTimeForWorkOrder(workOrder.getId());
+
+            // 使用归档时间所在的月份
             java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM");
-            String monthPeriod = sdf.format(new Date());
+            String monthPeriod = sdf.format(archiveTime);
 
             // 获取场站ID
             Long deptId = workOrder.getPcsStationPid();
@@ -887,7 +872,7 @@ public class EquipmentSafeOperationRewardTask {
                 monthScore.setCreateBy(SecurityUtils.getUsername());
                 monthScore.setCreateTime(new Date());
                 monthScoreService.insertGxtMonthScore(monthScore);
-                
+
                 // 重新查询刚插入的记录
                 scoreList = monthScoreService.selectGxtMonthScoreList(queryScore);
                 if (!scoreList.isEmpty()) {
@@ -1169,37 +1154,39 @@ public class EquipmentSafeOperationRewardTask {
             log.error("添加维保工单运行得分明细时发生异常", e);
         }
     }
-    
+
     /**
      * 添加停机扣分的工单个人分数明细数据
-     * 
-     * @param repairOrder 维修工单
-     * @param persons 更新的人员列表
+     *
+     * @param repairOrder    维修工单
+     * @param persons        更新的人员列表
      * @param deductionScore 扣分分数
-     * @param scoreType 分数类型
+     * @param scoreType      分数类型
+     * @param archiveTime
      */
-    private void addOrderScoreDetailsForStopScoreRepair(GxtRepairOrder repairOrder, List<GxtRepairOrderPerson> persons, BigDecimal deductionScore, int scoreType) {
+    private void addOrderScoreDetailsForStopScoreRepair(GxtRepairOrder repairOrder, List<GxtRepairOrderPerson> persons, BigDecimal deductionScore, int scoreType, Date archiveTime) {
         try {
+
             for (GxtRepairOrderPerson person : persons) {
                 GxtOrderScoreDetail detail = new GxtOrderScoreDetail();
-                
+
                 // 设置基础信息
                 detail.setUserId(person.getUserId());
                 detail.setNickName(person.getNickName());
                 detail.setOrderType(1); // 维修工单
-                
+
                 // 设置工单相关信息
                 detail.setOrderId(repairOrder.getId());
                 detail.setOrderCode(repairOrder.getWorkOrderProjectNo());
-                
+
                 // 设置分数类型和分数
                 detail.setScoreType(scoreType); // 停机扣分
                 detail.setScore(deductionScore);
                 detail.setStopScore(deductionScore);
 
                 detail.setCreateBy(SecurityUtils.getLoginUser().getUser().getUserName());
-                detail.setCreateTime(new Date());
-                
+                detail.setCreateTime(archiveTime);
+
                 // 保存到数据库
                 orderScoreDetailService.insertGxtOrderScoreDetail(detail);
             }
@@ -1207,7 +1194,7 @@ public class EquipmentSafeOperationRewardTask {
             log.error("添加维修工单停机扣分明细时发生异常", e);
         }
     }
-    
+
     /**
      * 添加停机扣分的工单个人分数明细数据
      * 
@@ -1216,8 +1203,11 @@ public class EquipmentSafeOperationRewardTask {
      * @param deductionScore 扣分分数
      * @param scoreType 分数类型
      */
-    private void addOrderScoreDetailsForStopScoreWork(GxtWorkOrder workOrder, List<GxtWorkOrderPerson> persons, BigDecimal deductionScore, int scoreType) {
+    private void addOrderScoreDetailsForStopScoreWork(GxtWorkOrder workOrder, List<GxtWorkOrderPerson> persons, BigDecimal deductionScore, int scoreType, Date archiveTime) {
         try {
+            // 获取工单归档时间
+            //Date archiveTime = getArchiveTimeForWorkOrder(workOrder.getId());
+            
             for (GxtWorkOrderPerson person : persons) {
                 GxtOrderScoreDetail detail = new GxtOrderScoreDetail();
                 
@@ -1236,7 +1226,7 @@ public class EquipmentSafeOperationRewardTask {
                 detail.setStopScore(deductionScore);
 
                 detail.setCreateBy(SecurityUtils.getLoginUser().getUser().getUserName());
-                detail.setCreateTime(new Date());
+                detail.setCreateTime(archiveTime);
                 
                 // 保存到数据库
                 orderScoreDetailService.insertGxtOrderScoreDetail(detail);
@@ -1245,4 +1235,175 @@ public class EquipmentSafeOperationRewardTask {
             log.error("添加维保工单停机扣分明细时发生异常", e);
         }
     }
+
+    /**
+     * 处理维修工单扣分
+     *
+     * @param repairOrder 维修工单
+     */
+    private void processRepairOrderDeduction(GxtRepairOrder repairOrder) {
+        log.debug("开始处理维修工单 {} 的扣分", repairOrder.getWorkOrderProjectNo());
+
+        // 计算停运天数:复运时间 - 故障时间
+        Date restartTime = repairOrder.getRestartTime();
+        Date occurTime = repairOrder.getOccurTime();
+        if (restartTime == null || occurTime == null) {
+            log.warn("维修工单 {} 的复运时间或故障时间为空,跳过扣分", repairOrder.getWorkOrderProjectNo());
+            return;
+        }
+
+        int daysBetween = DateUtils.calculateDateDifference(restartTime, occurTime);
+        if (daysBetween <= 0) {
+            log.debug("维修工单 {} 的停运天数为 {} 天,无需扣分", repairOrder.getWorkOrderProjectNo(), daysBetween);
+            return;
+        }
+
+        // 获取工单归档时间来确定月份
+        Date archiveTime = getArchiveTimeForRepairOrder(repairOrder.getId());
+        if (archiveTime == null) {
+            log.warn("维修工单 {} 未找到归档时间,使用当前时间", repairOrder.getWorkOrderProjectNo());
+            return;
+        }
+        // 获取扣分配置
+        GxtSafeOperationReward rewardQuery = new GxtSafeOperationReward();
+        rewardQuery.setStatus(0);
+        List<GxtSafeOperationReward> rewardConfigs = safeOperationRewardService.selectGxtSafeOperationRewardList(rewardQuery);
+        if (rewardConfigs.isEmpty()) {
+            log.warn("未找到任何启用的安全运行奖励配置,无法进行扣分");
+            return;
+        }
+
+        // 按照safeDuration升序排序
+        rewardConfigs.sort(Comparator.comparingInt(GxtSafeOperationReward::getSafeDuration));
+
+        // 获取对应的扣分配置
+        GxtSafeOperationReward applicableDeduction = getApplicableRewardConfig(rewardConfigs, daysBetween);
+        if (applicableDeduction == null) {
+            log.debug("维修工单 {} 停运天数 {} 未找到对应的扣分配置", repairOrder.getWorkOrderProjectNo(), daysBetween);
+            return;
+        }
+
+        // 获取停机扣分
+        BigDecimal deductionScore = applicableDeduction.getDowntimeScore();
+        if (deductionScore != null && deductionScore.compareTo(BigDecimal.ZERO) < 0) { // 确保是负数
+            log.info("维修工单 {} 停运 {} 天,扣分 {}", repairOrder.getWorkOrderProjectNo(), daysBetween, deductionScore);
+
+            // 对相关工单人员进行扣分操作
+            updatePersonStopScoreForRepairOrder(repairOrder, deductionScore, archiveTime);
+            // 更新月度统计数据
+            updateMonthlyScoreDataForStopScore(repairOrder, deductionScore, archiveTime);
+        } else {
+            log.debug("维修工单 {} 找到扣分配置但分数无效: {}", repairOrder.getWorkOrderProjectNo(), deductionScore);
+        }
+    }
+
+    /**
+     * 处理维保工单扣分
+     *
+     * @param workOrder 维保工单
+     */
+    private void processWorkOrderDeduction(GxtWorkOrder workOrder) {
+        log.debug("开始处理维保工单 {} 的扣分", workOrder.getWorkOrderProjectNo());
+
+        // 计算停运天数:复运时间 - 停机时间(pauseTime)
+        Date restartTime = workOrder.getRestartTime();
+        Date pauseTime = workOrder.getPauseTime(); // 维保工单使用pauseTime作为停机时间
+        if (restartTime == null || pauseTime == null) {
+            log.warn("维保工单 {} 的复运时间或停机时间为空,跳过扣分", workOrder.getWorkOrderProjectNo());
+            return;
+        }
+
+        int daysBetween = DateUtils.calculateDateDifference(restartTime, pauseTime);
+        if (daysBetween <= 0) {
+            log.debug("维保工单 {} 的停运天数为 {} 天,无需扣分", workOrder.getWorkOrderProjectNo(), daysBetween);
+            return;
+        }
+
+        Date archiveTime = getArchiveTimeForWorkOrder(workOrder.getId());
+        if (archiveTime == null) {
+            log.warn("维保工单 {} 未找到归档时间,使用当前时间", workOrder.getWorkOrderProjectNo());
+            return;
+        }
+        // 获取扣分配置
+        GxtSafeOperationReward rewardQuery = new GxtSafeOperationReward();
+        rewardQuery.setStatus(0);
+        List<GxtSafeOperationReward> rewardConfigs = safeOperationRewardService.selectGxtSafeOperationRewardList(rewardQuery);
+        if (rewardConfigs.isEmpty()) {
+            log.warn("未找到任何启用的安全运行奖励配置,无法进行扣分");
+            return;
+        }
+
+        // 按照safeDuration升序排序
+        rewardConfigs.sort(Comparator.comparingInt(GxtSafeOperationReward::getSafeDuration));
+
+        // 获取对应的扣分配置
+        GxtSafeOperationReward applicableDeduction = getApplicableRewardConfig(rewardConfigs, daysBetween);
+        if (applicableDeduction == null) {
+            log.debug("维保工单 {} 停运天数 {} 未找到对应的扣分配置", workOrder.getWorkOrderProjectNo(), daysBetween);
+            return;
+        }
+
+        // 获取停机扣分
+        BigDecimal deductionScore = applicableDeduction.getDowntimeScore();
+        if (deductionScore != null && deductionScore.compareTo(BigDecimal.ZERO) < 0) { // 确保是负数
+            log.info("维保工单 {} 停运 {} 天,扣分 {}", workOrder.getWorkOrderProjectNo(), daysBetween, deductionScore);
+
+            // 对相关工单人员进行扣分操作
+            updatePersonStopScoreForWorkOrder(workOrder, deductionScore, archiveTime);
+            // 更新月度统计数据
+            updateMonthlyScoreDataForStopScore(workOrder, deductionScore, archiveTime);
+        } else {
+            log.debug("维保工单 {} 找到扣分配置但分数无效: {}", workOrder.getWorkOrderProjectNo(), deductionScore);
+        }
+    }
+
+    /**
+     * 获取维修工单的归档时间
+     *
+     * @param orderId 工单ID
+     * @return 归档时间,如果未找到则返回null
+     */
+    private Date getArchiveTimeForRepairOrder(Long orderId) {
+        try {
+            // 查询工单流转记录,找到actionType为archive的记录
+            GxtRepairOrderFlow queryFlow = new GxtRepairOrderFlow();
+            queryFlow.setOrderId(orderId);
+            queryFlow.setActionType("archive");
+
+            List<GxtRepairOrderFlow> flows = repairOrderFlowService.selectGxtRepairOrderFlowList(queryFlow);
+            if (flows != null && !flows.isEmpty()) {
+                // 返回归档时间
+                return flows.get(0).getActionTime();
+            }
+            return null;
+        } catch (Exception e) {
+            log.error("获取维修工单 {} 归档时间时发生异常", orderId, e);
+            return null;
+        }
+    }
+
+    /**
+     * 获取维保工单的归档时间
+     *
+     * @param orderId 工单ID
+     * @return 归档时间,如果未找到则返回null
+     */
+    private Date getArchiveTimeForWorkOrder(Long orderId) {
+        try {
+            // 查询工单流转记录,找到actionType为archive的记录
+            GxtWorkOrderFlow queryFlow = new GxtWorkOrderFlow();
+            queryFlow.setOrderId(orderId);
+            queryFlow.setActionType("archive");
+
+            List<GxtWorkOrderFlow> flows = workOrderFlowService.selectGxtWorkOrderFlowList(queryFlow);
+            if (flows != null && !flows.isEmpty()) {
+                // 返回归档时间
+                return flows.get(0).getActionTime();
+            }
+            return null;
+        } catch (Exception e) {
+            log.error("获取维保工单 {} 归档时间时发生异常", orderId, e);
+            return null;
+        }
+    }
 }

+ 9 - 0
ygtx-gxt/src/main/resources/mapper/gxt/GxtRepairOrderMapper.xml

@@ -1082,4 +1082,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             LIMIT #{limit}
         </if>
     </select>
+    
+    <select id="selectGxtRepairOrderListForDeduction" resultMap="GxtRepairOrderResult">
+        SELECT DISTINCT t.*
+        FROM gxt_repair_order t
+        LEFT JOIN gxt_order_score_detail osd ON t.id = osd.order_id AND osd.order_type = 1 AND osd.score_type = 3
+        WHERE t.work_order_status = 'archived'
+          AND t.repair_method != '2'
+          AND osd.order_id IS NULL
+    </select>
 </mapper>

+ 8 - 0
ygtx-gxt/src/main/resources/mapper/gxt/GxtWorkOrderMapper.xml

@@ -1044,4 +1044,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             ${params.businessDataScope}
         </if>
     </select>
+
+    <select id="selectGxtWorkOrderListForDeduction" resultMap="GxtWorkOrderResult">
+        SELECT DISTINCT t.*
+        FROM gxt_work_order t
+                 LEFT JOIN gxt_order_score_detail osd ON t.id = osd.order_id AND osd.order_type = 2 AND osd.score_type = 3
+        WHERE t.work_order_status = 'archived'
+          AND osd.order_id IS NULL
+    </select>
 </mapper>