ソースを参照

fix(risk): submitPunch 防重复打卡

之前 submitPunch 完全没去重,同一 task 可以反复打卡,每次都新建 record,
PC 端打卡记录 dialog 里看到一长串重复的'已打卡'条目。

修复:第 1 步后加防重复判断,按 (taskId, slot) 查 record:
- 单时段/非每日任务:slot 为空,按 taskId 查
- 每日多时段任务:slot='HH:mm-HH:mm',按 (taskId, slot) 查
- 已有 record → throw ServiceException('已打卡,请勿重复打卡')
  (用 ServiceException 而非 IllegalArgumentException,被 RuoYi GlobalExceptionHandler
   统一处理成 500 + msg,前端 request 拦截器把 msg 当 Error.message 抛出,
   check 页 catch 后弹 toast 给用户)
yangjingjing 9 時間 前
コミット
fe21f36ee8

+ 15 - 0
ruoyi-modules/ruoyi-risk/src/main/java/org/dromara/risk/service/impl/RiskInspectionRecordServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -73,6 +74,20 @@ public class RiskInspectionRecordServiceImpl implements IRiskInspectionRecordSer
         RiskInspectionTask task = taskMapper.selectById(bo.getTaskId());
         Assert.notNull(task, "巡检任务不存在: " + bo.getTaskId());
 
+        // 1.5 防重复打卡(按 taskId + slot 唯一,每日多时段任务每个 slot 独立)
+        //    - 单时段/非每日任务:slot 为空,按 taskId 查
+        //    - 每日多时段任务:slot="HH:mm-HH:mm",按 (taskId, slot) 查
+        LambdaQueryWrapper<RiskInspectionRecord> dupLqw = Wrappers.lambdaQuery();
+        dupLqw.eq(RiskInspectionRecord::getTaskId, bo.getTaskId())
+              .eq(StringUtils.isNotBlank(bo.getSlot()), RiskInspectionRecord::getSlot, bo.getSlot());
+        RiskInspectionRecord existing = baseMapper.selectOne(dupLqw);
+        if (existing != null) {
+            String msg = StringUtils.isNotBlank(bo.getSlot())
+                ? "当前时段 [" + bo.getSlot() + "] 已打卡,请勿重复打卡"
+                : "该任务已打卡,请勿重复打卡";
+            throw new ServiceException(msg);
+        }
+
         // 2. 扫码打卡:校验二维码(留宽松,空串通过)
         if ("SCAN".equalsIgnoreCase(bo.getPunchType())
             && StringUtils.isNotBlank(task.getQrCode())