From b0e0ffde60a0ae902cc23f08826db61576cd6e3f Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期四, 12 二月 2026 13:44:04 +0800
Subject: [PATCH] 下班打卡正常但是上班迟到

---
 src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java |  116 ++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 77 insertions(+), 39 deletions(-)

diff --git a/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java b/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java
index 5e0b5df..1d35848 100644
--- a/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java
+++ b/src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.exception.base.BaseException;
@@ -12,12 +13,16 @@
 import com.ruoyi.project.system.service.ISysDictDataService;
 import com.ruoyi.staff.dto.PersonalAttendanceRecordsDto;
 import com.ruoyi.staff.dto.StaffOnJobDto;
+import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
 import com.ruoyi.staff.mapper.StaffOnJobMapper;
+import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
 import com.ruoyi.staff.pojo.PersonalAttendanceRecords;
 import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
 import com.ruoyi.staff.pojo.StaffOnJob;
 import com.ruoyi.staff.service.PersonalAttendanceRecordsService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.staff.task.PersonalAttendanceRecordsTask;
+import com.ruoyi.staff.utils.LocationUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -28,6 +33,7 @@
 import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
 import java.util.List;
 
@@ -40,6 +46,7 @@
  * @since 2026-02-09 01:20:07
  */
 @Service
+@Transactional(rollbackFor = Exception.class)
 public class PersonalAttendanceRecordsServiceImpl extends ServiceImpl<PersonalAttendanceRecordsMapper, PersonalAttendanceRecords> implements PersonalAttendanceRecordsService {
     @Autowired
     private PersonalAttendanceRecordsMapper personalAttendanceRecordsMapper;
@@ -48,45 +55,81 @@
     private StaffOnJobMapper staffOnJobMapper;
 
     @Autowired
+    private PersonalAttendanceLocationConfigMapper personalAttendanceLocationConfigMapper;
+
+    @Autowired
     private ISysDictDataService dictDataService;
 
     @Autowired
     private SysDeptMapper sysDeptMapper;
 
     @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int add(PersonalAttendanceRecords personalAttendanceRecords) {
+    public int add(PersonalAttendanceRecordsDto personalAttendanceRecordsDto) {
         // 褰撳墠鏃堕棿
         LocalDate currentDate = LocalDate.now();
-
-        // 棣栧厛鏍规嵁鐢ㄦ埛ID鏌ヨ鍛樺伐淇℃伅
+        LocalDateTime currentDateTime = LocalDateTime.now();
+        /*鏌ヨ鍛樺伐淇℃伅*/
         QueryWrapper<StaffOnJob> staffQueryWrapper = new QueryWrapper<>();
         staffQueryWrapper.eq("staff_no", SecurityUtils.getUsername());
         StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
         if (staffOnJob == null) {
             throw new BaseException("褰撳墠鐢ㄦ埛娌℃湁瀵瑰簲鐨勫憳宸ヤ俊鎭�");
         }
-
+        /*鍒ゆ柇鎵撳崱浣嶇疆鏄惁鍦ㄨ鍒欒寖鍥村唴*/
+        List<PersonalAttendanceLocationConfig> personalAttendanceLocationConfigs = personalAttendanceLocationConfigMapper.selectList(Wrappers.<PersonalAttendanceLocationConfig>lambdaQuery()
+                .eq(PersonalAttendanceLocationConfig::getSysDeptId, staffOnJob.getSysDeptId())
+                .orderByDesc(PersonalAttendanceLocationConfig::getId));
+        if (personalAttendanceLocationConfigs == null || personalAttendanceLocationConfigs.isEmpty()) {
+            throw new BaseException("褰撳墠閮ㄩ棬娌℃湁璁剧疆鎵撳崱瑙勫垯");
+        }
+        Double punchLongitude = personalAttendanceRecordsDto.getLongitude(); //鎵撳崱鐨勭粡搴�
+        Double punchLatitude = personalAttendanceRecordsDto.getLatitude(); // 鎵撳崱鐨勭含搴�
+        if (punchLongitude == null || punchLatitude == null) {
+            throw new BaseException("鎵撳崱澶辫触锛氭湭鑾峰彇鍒版偍鐨勪綅缃俊鎭紝璇峰紑鍚畾浣嶆潈闄�");
+        }
+        //璁$畻鎵撳崱浣嶇疆涓庤�冨嫟鐐圭殑璺濈
+        PersonalAttendanceLocationConfig locationConfig = personalAttendanceLocationConfigs.get(0);//鑾峰彇鏈�鏂扮殑涓�鏉℃暟鎹�
+        double allowedRadius = locationConfig.getRadius(); // 鍏佽鐨勮寖鍥达紙绫筹級
+        double actualDistance = LocationUtils.calculateDistance(
+                punchLatitude, punchLongitude, // 鍛樺伐鎵撳崱鐨勭粡绾害
+                locationConfig.getLatitude(), locationConfig.getLongitude() // 鑰冨嫟鐐圭殑缁忕含搴�
+        );
+        //鍒ゆ柇鏄惁鍦ㄨ寖鍥村唴
+        if (actualDistance > allowedRadius) {
+            throw new BaseException(String.format("鎵撳崱澶辫触锛氭偍褰撳墠浣嶇疆璺濈鑰冨嫟鐐�%.2f绫筹紝瓒呭嚭鍏佽鑼冨洿锛�%s绫筹級", actualDistance, allowedRadius));
+        }
+        /*鍒ゆ柇鎵撳崱鏃堕棿*/
+        LocalTime   endAt = locationConfig.getEndAt(); //涓嬬彮鏃堕棿
+        // 鑾峰彇鑰冨嫟涓嬬彮鏃堕棿鐐�
+        int standardHour = endAt.getHour();
+        int standardMinute = endAt.getMinute();
+        // 褰撳墠鏃堕棿
+        int actualHour = currentDateTime.getHour();
+        int actualMinute = currentDateTime.getMinute();
+        // 鍒ゆ柇鎵撳崱鏃堕棿鏄惁鏅氫簬褰撳墠鏃堕棿
+        if (actualHour > standardHour || (actualHour == standardHour && actualMinute > standardMinute)) {
+            throw new BaseException(String.format("鎵撳崱澶辫触锛氭墦鍗℃椂闂翠笉鑳芥櫄浜庝笅鐝椂闂达紙%02d:%02d锛�", standardHour, standardMinute));
+        }
         // 鏍规嵁鍛樺伐ID鍜屽綋鍓嶆棩鏈熸煡璇㈡墦鍗¤褰�
         QueryWrapper<PersonalAttendanceRecords> attendanceQueryWrapper = new QueryWrapper<>();
         attendanceQueryWrapper.eq("staff_on_job_id", staffOnJob.getId())
                 .eq("date", currentDate);
         PersonalAttendanceRecords attendanceRecord = personalAttendanceRecordsMapper.selectOne(attendanceQueryWrapper);
-        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
         // 鏍规嵁瀛楀吀璁剧疆鐨勮�冨嫟鏃堕棿鍒ゆ柇杩熷埌鏃╅��
         if (attendanceRecord == null) {
             // 涓嶅瓨鍦ㄦ墦鍗¤褰曪紝鍒涘缓鏂拌褰�
+            PersonalAttendanceRecords personalAttendanceRecords = new PersonalAttendanceRecords();
             personalAttendanceRecords.setStaffOnJobId(staffOnJob.getId());
             personalAttendanceRecords.setDate(currentDate);
-            personalAttendanceRecords.setWorkStartAt(LocalDateTime.now());
-            personalAttendanceRecords.setStatus(determineAttendanceStatus(personalAttendanceRecords.getWorkStartAt(), true));
+            personalAttendanceRecords.setWorkStartAt(currentDateTime);
+            personalAttendanceRecords.setStatus(determineAttendanceStatus(personalAttendanceRecords, true,locationConfig));
             personalAttendanceRecords.setRemark(personalAttendanceRecords.getRemark());
             personalAttendanceRecords.setTenantId(staffOnJob.getTenantId());
             return personalAttendanceRecordsMapper.insert(personalAttendanceRecords);
         } else {
             if (attendanceRecord.getWorkEndAt() == null) {
                 // 鏇存柊宸ヤ綔缁撴潫鏃堕棿鍜屽伐浣滄椂闀�
-                attendanceRecord.setWorkEndAt(LocalDateTime.now());
+                attendanceRecord.setWorkEndAt(currentDateTime);
                 // 璁$畻宸ヤ綔鏃堕暱锛堢簿纭埌鍒嗛挓锛屼繚鐣�2浣嶅皬鏁帮級
                 LocalDateTime startTime = attendanceRecord.getWorkStartAt();
                 LocalDateTime endTime = attendanceRecord.getWorkEndAt();
@@ -96,7 +139,7 @@
                         .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
                 attendanceRecord.setWorkHours(workHours);
                 // 鏇存柊鑰冨嫟鐘舵��
-                attendanceRecord.setStatus(determineAttendanceStatus(attendanceRecord.getWorkEndAt(), false));
+                attendanceRecord.setStatus(determineAttendanceStatus(attendanceRecord, false,locationConfig));
                 return personalAttendanceRecordsMapper.updateById(attendanceRecord);
             } else {
                 throw new BaseException("鎮ㄥ凡缁忔墦杩囧崱浜�,鏃犻渶閲嶅鎵撳崱!!!");
@@ -105,36 +148,21 @@
     }
 
     // 鏍规嵁瀹為檯鏃堕棿鍜屾槸鍚︿笂鐝椂闂村垽鏂�冨嫟鐘舵��
-    // 0 姝e父 1 杩熷埌 2 鏃╅��
-    private byte determineAttendanceStatus(LocalDateTime actualTime, boolean isStart) {
+    // 0 姝e父 1 杩熷埌 2 鏃╅�� 3 杩熷埌鏃╅�� 4 缂哄嫟
+    private Integer determineAttendanceStatus(PersonalAttendanceRecords attendanceRecord, boolean isStart,PersonalAttendanceLocationConfig locationConfig) {
+        //鍒ゆ柇鏄笂鐝墦鍗¤繕鏄笅鐝墦鍗�
+        LocalDateTime actualTime = isStart ? attendanceRecord.getWorkStartAt() : attendanceRecord.getWorkEndAt();
         try {
             // 鑾峰彇鑰冨嫟鏃堕棿閰嶇疆
-            String dictType = "sys_work_time"; // 鑰冨嫟鏃堕棿瀛楀吀绫诲瀷
-            String timeConfig;
-
-            if (isStart) {
-                // 涓婄彮鏃堕棿閰嶇疆锛岄粯璁や负09:00
-                timeConfig = dictDataService.selectDictLabel(dictType, "work_start_time");
-                if (timeConfig == null || timeConfig.trim().isEmpty()) {
-                    timeConfig = "09:00";
-                }
-            } else {
-                // 涓嬬彮鏃堕棿閰嶇疆锛岄粯璁や负18:00
-                timeConfig = dictDataService.selectDictLabel(dictType, "work_end_time");
-                if (timeConfig == null || timeConfig.trim().isEmpty()) {
-                    timeConfig = "18:00";
-                }
-            }
-
-            // 瑙f瀽鏍囧噯鏃堕棿
-            String[] timeParts = timeConfig.split(":");
-            int standardHour = Integer.parseInt(timeParts[0]);
-            int standardMinute = Integer.parseInt(timeParts[1]);
-
+            LocalTime startAt = locationConfig.getStartAt();//涓婄彮鏃堕棿
+            LocalTime  endAt = locationConfig.getEndAt();//涓嬬彮鏃堕棿
+            LocalTime  timeConfig = isStart ? startAt : endAt;
+            // 瑙f瀽灏忔椂鍜屽垎閽�
+            int standardHour = timeConfig.getHour();
+            int standardMinute = timeConfig.getMinute();
             // 鑾峰彇瀹為檯鏃堕棿鐨勬椂鍒�
             int actualHour = actualTime.getHour();
             int actualMinute = actualTime.getMinute();
-
             // 鍒ゆ柇鐘舵��
             if (isStart) {
                 // 涓婄彮鎵撳崱锛氳秴杩囨爣鍑嗘椂闂寸畻杩熷埌
@@ -144,12 +172,15 @@
             } else {
                 // 涓嬬彮鎵撳崱锛氭棭浜庢爣鍑嗘椂闂寸畻鏃╅��
                 if (actualHour < standardHour || (actualHour == standardHour && actualMinute < standardMinute)) {
+                    if (attendanceRecord.getStatus() == 1) {
+                        return 3; // 杩熷埌鏃╅��
+                    }
                     return 2; // 鏃╅��
+                }else if (attendanceRecord.getStatus() == 1) {
+                    return 1; // 涓嬬彮鎵撳崱姝e父浣嗘槸涓婄彮杩熷埌
                 }
             }
-
             return 0; // 姝e父
-
         } catch (Exception e) {
             // 濡傛灉鑾峰彇閰嶇疆澶辫触锛岄粯璁よ繑鍥炴甯哥姸鎬�
             log.warn("鑾峰彇鑰冨嫟鏃堕棿閰嶇疆澶辫触锛屼娇鐢ㄩ粯璁ょ姸鎬侊細" + e.getMessage());
@@ -184,7 +215,7 @@
         StaffOnJob staffOnJob = staffOnJobMapper.selectOne(staffQueryWrapper);
 
         if (staffOnJob == null) {
-            return null; // 褰撳墠鐢ㄦ埛娌℃湁瀵瑰簲鐨勫憳宸ヤ俊鎭�
+            throw new BaseException("褰撳墠鐢ㄦ埛娌℃湁瀵瑰簲鐨勫憳宸ヤ俊鎭�");
         }
 
         // 鏍规嵁鍛樺伐ID鍜屽綋鍓嶆棩鏈熸煡璇㈡墦鍗¤褰�
@@ -207,7 +238,14 @@
         resultDto.setDeptId(staffOnJob.getSysDeptId() != null ? staffOnJob.getSysDeptId() : null);
         SysDept dept = sysDeptMapper.selectDeptById(staffOnJob.getSysDeptId());
         resultDto.setDeptName(dept != null ? dept.getDeptName() : null);
-
+        //鑾峰彇璇ュ憳宸ュ搴旂殑鎵撳崱瑙勫垯
+        List<PersonalAttendanceLocationConfig> personalAttendanceLocationConfigs = personalAttendanceLocationConfigMapper.selectList(Wrappers.<PersonalAttendanceLocationConfig>lambdaQuery()
+                .eq(PersonalAttendanceLocationConfig::getSysDeptId, staffOnJob.getSysDeptId())
+                .orderByDesc(PersonalAttendanceLocationConfig::getId));
+        if (personalAttendanceLocationConfigs.size()>0){
+            resultDto.setStartAt(personalAttendanceLocationConfigs.get(0).getStartAt());
+            resultDto.setEndAt(personalAttendanceLocationConfigs.get(0).getEndAt());
+        }
         return resultDto;
     }
 

--
Gitblit v1.9.3