From dc7300e21fe53f74e08eb2fa494a83430e2e54ca Mon Sep 17 00:00:00 2001
From: zouyu <2723363702@qq.com>
Date: 星期四, 26 三月 2026 11:25:58 +0800
Subject: [PATCH] 绩效管理:人员考勤功能模块

---
 inspect-server/src/main/java/com/ruoyi/inspect/task/SyncStaffAttendanceRecordSchedule.java                |   36 +
 ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/SysPostController.java                     |    4 
 inspect-server/src/main/java/com/ruoyi/inspect/service/StaffAttendanceTrackingRecordService.java          |   31 +
 .gitignore                                                                                                |    1 
 inspect-server/src/main/resources/mapper/StaffAttendanceTrackingRecordMapper.xml                          |   58 +
 inspect-server/src/main/java/com/ruoyi/inspect/util/HourDiffCalculator.java                               |   61 ++
 ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageResponse.java                |   89 ++
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Custom.java                                |    3 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/api/IfsApiUtils.java                                    |   10 
 inspect-server/src/main/java/com/ruoyi/inspect/controller/StaffAttendanceController.java                  |   81 ++
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/RawMaterialOrderServiceImpl.java              |   22 
 pom.xml                                                                                                   |    8 
 cnas-device/src/main/java/com/ruoyi/device/utils/DataAcquisition.java                                     |  144 ---
 cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java                            |    3 
 performance-server/src/main/java/com/ruoyi/performance/mapper/PerformanceShiftMapper.java                 |    6 
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/StaffAttendanceTrackingRecordServiceImpl.java |  466 +++++++++++++++
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/IfsPartPropsRecordServiceImpl.java            |    1 
 performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml                                   |   23 
 inspect-server/pom.xml                                                                                    |    2 
 inspect-server/src/main/java/com/ruoyi/inspect/pojo/StaffAttendanceTrackingRecord.java                    |  205 ++++++
 ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/IccApiUtil.java                                 |   40 +
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java                  |    2 
 inspect-server/src/main/java/com/ruoyi/inspect/mapper/StaffAttendanceTrackingRecordMapper.java            |   22 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/EnterOrExitType.java                                    |   26 
 inspect-server/src/main/java/com/ruoyi/inspect/dto/StaffAttendanceDTO.java                                |   87 ++
 ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageRequest.java                 |   68 ++
 cnas-device/src/main/java/com/ruoyi/device/mqtt/MQCallback.java                                           |   20 
 inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffClockInVO.java                                     |   14 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/ClockInState.java                                       |   22 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/PlatformConfig.java                      |   20 
 ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/UserController.java                        |    6 
 performance-server/src/main/java/com/ruoyi/performance/dto/PerformanceShiftMapDto.java                    |   10 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/OauthConfigUtil.java                     |   28 
 inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java                     |    1 
 performance-server/src/main/java/com/ruoyi/performance/mapper/ShiftTimeMapper.java                        |    2 
 inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffAttendanceVO.java                                  |  103 +++
 ruoyi-common/src/main/java/com/ruoyi/common/enums/SyncStatus.java                                         |   19 
 37 files changed, 1,592 insertions(+), 152 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6bb8c15..86d0bf3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@
 
 ### IntelliJ IDEA ###
 .idea
+.vscode
 *.iws
 *.iml
 *.ipr
diff --git a/cnas-device/src/main/java/com/ruoyi/device/mqtt/MQCallback.java b/cnas-device/src/main/java/com/ruoyi/device/mqtt/MQCallback.java
index 599177a..8d4d37b 100644
--- a/cnas-device/src/main/java/com/ruoyi/device/mqtt/MQCallback.java
+++ b/cnas-device/src/main/java/com/ruoyi/device/mqtt/MQCallback.java
@@ -82,26 +82,6 @@
                 case "/aiot/51eaff10-c6b9-11f0-8b13-c14e8310d70b"://杩囩▼璇曢獙瀹�-鐢甸樆
                     mqCallback.collectBridgeService.dcResistanceDataAnalysis(parse);
                     break;
-
-
-
-
-//                case "/ztt/v3/2455220/publish":
-//                    //鑰愪笣锛氱洿娴佺數闃绘暟鎹В鏋怤S-ER02001
-//                    mqCallback.collectBridgeService.dcResistanceDataAnalysis(parse,"NS-ER02001");
-//                    break;
-////                case "/aiot/8fac9fa0-c517-11f0-954c-255ce11213f1":
-////                    //鑰愪笣锛氱洿娴佺數闃绘暟鎹В鏋怤S-ER02002
-////                    mqCallback.collectBridgeService.dcResistanceDataAnalysis(parse,"NS-ER02002");
-////                    break;
-//                case "/ztt/v3/2455221/publish":
-//                    //鑰愪笣锛氫几闀跨巼鏁版嵁瑙f瀽NS-FM05003
-//                    mqCallback.collectBridgeService.elongationDataAnalysis(parse,"NS-FM05003");
-////                    break;
-////                case "/aiot/38568140-c697-11f0-8b13-c14e8310d70b":
-////                    //鑰愪笣锛氫几闀跨巼鏁版嵁瑙f瀽NS-FM05002
-////                    mqCallback.collectBridgeService.elongationDataAnalysis(parse,"NS-FM05002");
-//                    break;
             }
         } catch (Exception e) {
             e.printStackTrace();
diff --git a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java
index 9e786ce..1794195 100644
--- a/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java
+++ b/cnas-device/src/main/java/com/ruoyi/device/service/impl/DeviceServiceImpl.java
@@ -197,9 +197,6 @@
 
     @Override
     public Result<?> dataAcquisition(HttpServletRequest request, DeviceCollectionDto dto) {
-
-
-
         // 鏌ヨ妫�楠岄」
         List<Integer> itemIds = dto.getItemIds();
         if (CollectionUtils.isEmpty(itemIds)) {
diff --git a/cnas-device/src/main/java/com/ruoyi/device/utils/DataAcquisition.java b/cnas-device/src/main/java/com/ruoyi/device/utils/DataAcquisition.java
index ef616a4..8e600f3 100644
--- a/cnas-device/src/main/java/com/ruoyi/device/utils/DataAcquisition.java
+++ b/cnas-device/src/main/java/com/ruoyi/device/utils/DataAcquisition.java
@@ -2,11 +2,13 @@
 
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.ruoyi.common.core.domain.Result;
 import com.ruoyi.common.utils.RedisUtil;
 import com.ruoyi.device.constant.DCResistanceMqttConstants;
@@ -130,16 +132,17 @@
                     break;
                 case ".xls":
                 case ".xlsx":
+                case ".csv":
                     map = analysisList(data, userMap, device, entrustCode, sampleCode);
+                    break;
+                case ".serialPort":
+                    map = analysisSerialPortList(data, userMap, device, entrustCode, sampleCode);
                     break;
                 case ".pngInExcel":
                     map = analysisPngInExcel(data, userMap, device, entrustCode, sampleCode);
                     break;
                 case ".txt":
                     map = analysisTxt(data, userMap, device, entrustCode, sampleCode);
-                    break;
-                case ".csv":
-                    map = analysisList(data, userMap, device, entrustCode, sampleCode);
                     break;
                 case ".mdb":
                     // 鍒ゆ柇鏄惁鏄媺鍔涙満JCZX-ZB-FF01014
@@ -150,10 +153,8 @@
                     }
                     break;
                 case ".db":
-//                    map = analysisDb1(data, userMap, device);
-                    map = analysisDb(data, userMap, device);
-                    break;
                 case ".mysql":
+                case ".sqlserver":
 //                    map = analysisDb1(data, userMap, device);
                     map = analysisDb(data, userMap, device);
                     break;
@@ -499,7 +500,7 @@
      * @return
      */
     public static Object calculationFormula(List<Object> list, DataConfig dataConfig, String insProductItem, Device device) {
-        if (list.size() == 0) {
+        if (list.isEmpty()) {
             Map<String, Object> hashMap = new HashMap<>();
             hashMap.put("equipName", device.getDeviceName());
             hashMap.put("equipValue", device.getManagementNumber());
@@ -666,6 +667,25 @@
         return map;
     }
 
+    /**
+     * 澶勭悊涓插彛鏁版嵁
+     *
+     * @param data       閲囬泦鍒扮殑鏂囦欢瀛楃涓�
+     * @param dataConfig 鐢ㄦ埛閰嶇疆濂界殑x,y杞村畾浣嶆暟鎹笌鍙傜収鐗�
+     * @return
+     */
+    public static Map<String, Object> analysisSerialPortList(String data, Map<String, List<DataConfig>> dataConfig,
+                                                   Device device, String entrustCode, String sampleCode) {
+        Map<String, Object> map = new HashMap<>();
+        dataConfig.forEach((k, v) -> {
+            List<Object> list = JSONObject.parseObject(data,new TypeReference<List<Object>>(){}.getType());
+            // 杩涜鍏紡璁$畻
+            Object resultValue = calculationFormula(list, v.get(0), k, device);
+            map.put(k, resultValue);
+        });
+        return map;
+    }
+
     private static List<Object> analyzeDataEntrustCodAndSampleCode(String data, List<DataConfig> v, String k, String splitIdentifier,
                                                                    Device device, String entrustCodeValue, String sampleCodeValue) {
         entrustCodeValue = entrustCodeValue.replaceAll(" ", "");
@@ -751,117 +771,7 @@
     public static String getRefer(String refer) {
         return ObjectUtils.isNotEmpty(refer) ? refer.replaceAll(" ", "") : "";
     }
-    /**
-     * 濮旀墭缂栧彿涓庢牱鍝佺紪鍙烽兘涓虹┖鎵ц
-     *
-     * @param data  閲囬泦鍒扮殑鏂囦欢瀛楃涓�
-     * @param v     鐢ㄦ埛閰嶇疆濂界殑x,y杞村畾浣嶆暟鎹笌鍙傜収鐗�
-     * @param k     妫�楠岄」鍚嶇О
-     * @param split 鍒嗗壊绗�
-     * @return 鎻愬彇鐨勬暟鎹垪琛�
-     */
-    public static List<Object> analyzeData1(String data, List<DataConfig> v, String k, String split) {
-        List<Object> list = new ArrayList<>();
-        // 棰勫鐞嗘暟鎹細绉婚櫎澶氫綑绌烘牸骞朵繚鐣欏叧閿垎闅旂
-        String processedData = data.replaceAll("\\s+", " ").trim();
-        for (int configIndex = 0; configIndex < v.size(); configIndex++) {
-            // 鍙栦袱涓敤鎴烽厤缃殑鍙傜収鐗�
-            String referx = getRefer(v.get(configIndex).getReferx());
-            String refery = getRefer(v.get(configIndex).getRefery());
-            if (ObjectUtils.isEmpty(refery) && ObjectUtils.isEmpty(referx)) {
-                System.out.println("鍙傜収鐗╀负绌猴紝璺宠繃褰撳墠閰嶇疆锛宬: " + k);
-                continue;
-            }
-            // 鏈�缁堢粨鏋�
-            List<Object> result = new ArrayList<>();
-            // 閫氳繃\n灏嗗瓧绗︿覆鍒嗗壊涓鸿
-            String[] aColumnY = processedData.replaceAll(" ", "").split("\n");
-            Integer end = null;
-            // 閲囬泦鏁版嵁锛歒杞�
-            for (int i = 0; i < aColumnY.length; i++) {
-                String line = aColumnY[i].trim();
-                if (line.isEmpty()) continue; // 璺宠繃绌鸿
 
-                // 濡傛灉Y鍙傜収涓嶄负绌轰笌X鍙傜収涓虹┖鍒欐墽琛岋紝鍚屾椂璇ヨ鍖呭惈Y鍙傜収
-                if (ObjectUtils.isNotEmpty(refery) && ObjectUtils.isEmpty(referx) && line.contains(refery)) {
-                    try {
-                        // 鍙朰鍧愭爣鍊�
-                        int y = getXOrY(v.get(configIndex).getY(), k, "Y");
-                        String[] aLineX = line.split(split);
-                        for (int j = 0; j < aLineX.length; j++) {
-                            if (aLineX[j].contains(refery)) {
-                                if (i + y >= aColumnY.length) {
-                                    System.err.println(k + "锛歒杞村畾浣嶈秴鍑烘暟鎹寖鍥达紝褰撳墠鏁版嵁琛屾暟: " + aColumnY.length + "锛屽皾璇曡闂: " + (i + y));
-                                    continue;
-                                }
-                                String[] split1 = aColumnY[i + y].split(split);
-                                if (j >= split1.length) {
-                                    System.err.println(k + "锛歑杞村畾浣嶈秴鍑烘暟鎹寖鍥达紝褰撳墠琛屽厓绱犱釜鏁�: " + split1.length + "锛屽皾璇曡闂綅缃�: " + j);
-                                    continue;
-                                }
-                                result.add(split1[j]);
-                            }
-                        }
-                    } catch (Exception e) {
-                        System.err.println(k + "锛氬湪澶勭悊浠匶鍙傜収閫昏緫鏃跺嚭鐜板紓甯�: " + e.getMessage());
-                    }
-                }
-                // 濡傛灉Y鍙傜収涓嶄负绌轰笌X鍙傜収涓嶄负绌哄垯鎵ц,姝ゅY瀹氬尯鍩�
-                else if (ObjectUtils.isNotEmpty(refery) && ObjectUtils.isNotEmpty(referx)) {
-                    try {
-                        // 鍙杧鐨勫�硷紝闃叉鎶ラ敊
-                        int x = getXOrY(v.get(configIndex).getX(), k, "X");
-                        // 鍙朰鍧愭爣鍊�
-                        int y = getXOrY(v.get(configIndex).getY(), k, "Y");
-                        // 缂撳瓨Y鐨勭粨鏉熷��
-                        if (ObjectUtils.isEmpty(end) && line.contains(refery)) {
-                            end = i + y;
-                        }
-                        // 鍒ゆ柇鏄惁鍦ㄥ弬鐓х墿涓鸿捣鐐癸紝Y鍧愭爣鍊间负鏈�缁堣寖鍥�
-                        if (ObjectUtils.isNotEmpty(end) && i <= end) {
-                            String[] aLineX = line.split(split);
-                            for (int j = 0; j < aLineX.length; j++) {
-                                if (aLineX[j].contains(referx)) {
-                                    if (j + x >= aLineX.length) {
-                                        System.err.println(k + "锛歑杞村畾浣嶈秴鍑烘暟鎹寖鍥达紝褰撳墠琛屽厓绱犱釜鏁�: " + aLineX.length + "锛屽皾璇曡闂綅缃�: " + (j + x));
-                                        continue;
-                                    }
-                                    result.add(aLineX[j + x]);
-                                    break;
-                                }
-                            }
-                        }
-                    } catch (Exception e) {
-                        System.err.println(k + "锛氬湪澶勭悊XY鍙傜収閫昏緫鏃跺嚭鐜板紓甯�: " + e.getMessage());
-                    }
-                }
-                // 濡傛灉X鍙傜収涓嶄负绌哄悓鏃惰琛屽寘鍚玐鍙傜収锛屽垯鎵ц涓嬮潰鐨勪唬鐮�
-                else if (line.contains(referx) && ObjectUtils.isEmpty(refery)) {
-                    try {
-                        String[] aLineX = line.split(split);
-                        // 鍙杧鐨勫�硷紝闃叉鎶ラ敊
-                        int x = getXOrY(v.get(configIndex).getX(), k, "X");
-                        for (int j = 0; j < aLineX.length; j++) {
-                            if (aLineX[j].contains(referx)) {
-                                if (j + x >= aLineX.length) {
-                                    System.err.println(k + "锛歑杞村畾浣嶈秴鍑烘暟鎹寖鍥达紝褰撳墠琛屽厓绱犱釜鏁�: " + aLineX.length + "锛屽皾璇曡闂綅缃�: " + (j + x));
-                                    continue;
-                                }
-                                result.add(aLineX[j + x]);
-                            }
-                        }
-                    } catch (Exception e) {
-                        System.err.println(k + "锛氬湪澶勭悊浠匵鍙傜収閫昏緫鏃跺嚭鐜板紓甯�: " + e.getMessage());
-                    }
-                }
-            }
-            // 闃叉璁$畻鍏紡鐨勬椂鍊欏嚭鐜帮細[null] 杩欑鏁版嵁
-            if (ObjectUtils.isNotEmpty(result)) {
-                list.addAll(result);
-            }
-        }
-        return list;
-    }
     /**
      * 濮旀墭缂栧彿涓庢牱鍝佺紪鍙烽兘涓虹┖鎵ц
      *
diff --git a/inspect-server/pom.xml b/inspect-server/pom.xml
index 38ae884..6b2519d 100644
--- a/inspect-server/pom.xml
+++ b/inspect-server/pom.xml
@@ -67,8 +67,6 @@
             <artifactId>itextpdf</artifactId>
             <version>5.0.6</version>
         </dependency>
-
-
     </dependencies>
 
     <properties>
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/controller/StaffAttendanceController.java b/inspect-server/src/main/java/com/ruoyi/inspect/controller/StaffAttendanceController.java
new file mode 100644
index 0000000..5ba227c
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/controller/StaffAttendanceController.java
@@ -0,0 +1,81 @@
+package com.ruoyi.inspect.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.inspect.dto.StaffAttendanceDTO;
+import com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord;
+import com.ruoyi.inspect.service.StaffAttendanceTrackingRecordService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+
+/**
+ * 缁╂晥绠$悊-浜哄憳鑰冨嫟鎺ュ彛
+ */
+@Api(value = "缁╂晥绠$悊-浜哄憳鑰冨嫟鎺ュ彛")
+@RestController
+@RequestMapping("/staff/attendance")
+public class StaffAttendanceController {
+
+    @Autowired
+    private StaffAttendanceTrackingRecordService trackingRecordService;
+
+    @ApiOperation("鏌ヨ浜哄憳鎵撳崱璁板綍")
+    @GetMapping("/getClockInRecord")
+    public Result getClockInRecord(StaffAttendanceDTO staffAttendanceDTO){
+        return Result.success(trackingRecordService.getClockInRecord(staffAttendanceDTO));
+    }
+
+    @ApiOperation("鍒嗛〉鏌ヨ鑰冨嫟璁板綍")
+    @GetMapping("/pageAttendanceRecord")
+    public Result pageAttendanceRecord(Page<StaffAttendanceTrackingRecord> page, StaffAttendanceDTO staffAttendanceDTO){
+        return Result.success(trackingRecordService.pageAttendanceRecord(page,staffAttendanceDTO));
+    }
+
+    @ApiOperation("鏍¢獙閫夋嫨鐨勮�冨嫟鏃堕棿鏄惁瀛樺湪鍚屼竴浜哄憳鐨勮�冨嫟璁板綍,娌℃湁鍒欒繑鍥炰汉鍛樺綋澶╃殑鐝淇℃伅")
+    @GetMapping("/checkDutyDate")
+    public Result checkDutyDate(StaffAttendanceDTO staffAttendanceDTO){
+        return Result.success(trackingRecordService.checkDutyDate(staffAttendanceDTO));
+    }
+
+    @ApiOperation("淇濆瓨鎴栨洿鏂拌�冨嫟璁板綍")
+    @PostMapping("/saveOrUpdateStaffAttendanceTrackingRecord")
+    public Result saveStaffAttendanceTrackingRecord(@RequestBody StaffAttendanceDTO staffAttendanceDTO){
+        return Result.success(trackingRecordService.saveOrUpdateRecord(staffAttendanceDTO));
+    }
+
+    @ApiOperation("鍒犻櫎鑰冨嫟璁板綍")
+    @DeleteMapping("/removeStaffAttendanceTrackingRecord")
+    public Result removeStaffAttendanceTrackingRecord(@RequestBody StaffAttendanceDTO staffAttendanceDTO){
+        return Result.success(trackingRecordService.removeByIds(Arrays.asList(staffAttendanceDTO.getWorkDataId(),staffAttendanceDTO.getOffWorkDataId())));
+    }
+
+    @ApiOperation("鍚屾鑰冨嫟璁板綍")
+    @GetMapping("/syncAttendanceRecord")
+    public Result syncAttendanceRecord(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startDate,@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endDate){
+        return Result.success(trackingRecordService.syncAttendanceRecord(startDate,endDate));
+    }
+
+    @ApiOperation("淇敼杩涘嚭璁板綍鐘舵��")
+    @PostMapping("/changeEnableReport")
+    public Result changeEnableReport(@RequestBody StaffAttendanceDTO staffAttendanceDTO){
+        if(ObjectUtils.isEmpty(staffAttendanceDTO.getId())){
+            throw new RuntimeException("浼犲弬寮傚父锛屼富閿甀D涓嶈兘涓虹┖锛�");
+        }
+        StaffAttendanceTrackingRecord trackingRecord = new StaffAttendanceTrackingRecord();
+        trackingRecord.setId(staffAttendanceDTO.getId());
+        trackingRecord.setEnableReport(staffAttendanceDTO.getEnableReport());
+        return Result.success(trackingRecordService.updateById(trackingRecord));
+    }
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/dto/StaffAttendanceDTO.java b/inspect-server/src/main/java/com/ruoyi/inspect/dto/StaffAttendanceDTO.java
new file mode 100644
index 0000000..022dfc6
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/dto/StaffAttendanceDTO.java
@@ -0,0 +1,87 @@
+package com.ruoyi.inspect.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.NonNull;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+@Data
+public class StaffAttendanceDTO extends StaffAttendanceTrackingRecord {
+
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    @ApiModelProperty("寮�濮嬫椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startDate;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    @ApiModelProperty("缁撴潫鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endDate;
+
+    /**
+     * 鍛樺伐鍚嶇О/宸ュ彿
+     */
+    @ApiModelProperty("鍛樺伐鍚嶇О/宸ュ彿")
+    private String keyword;
+
+    /**
+     * 鑰冨嫟鏃堕棿
+     */
+    @ApiModelProperty("鑰冨嫟鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate swingDate;
+
+    /**
+     * 鐝id
+     */
+    @ApiModelProperty("鐝id")
+    private String shiftId;
+
+    /**
+     * 鏄惁绾冲叆鑰冨嫟缁熻
+     */
+    @ApiModelProperty("鏄惁绾冲叆鑰冨嫟缁熻")
+    private Boolean enableReport;
+
+    /**
+     * 涓婄彮鏃堕棿
+     */
+    @JsonFormat(pattern = "HH:mm")
+    @DateTimeFormat(pattern = "HH:mm")
+    @ApiModelProperty("涓婄彮鏃堕棿")
+    private LocalTime workDateTime;
+
+    /**
+     * 涓嬬彮鏃堕棿
+     */
+    @JsonFormat(pattern = "HH:mm")
+    @DateTimeFormat(pattern = "HH:mm")
+    @ApiModelProperty("涓嬬彮鏃堕棿")
+    private LocalTime offWorkDateTime;
+
+    /**
+     * 涓婄彮璁板綍id
+     */
+    @ApiModelProperty("涓婄彮璁板綍id")
+    private Long workDataId;
+
+    /**
+     * 涓嬬彮璁板綍id
+     */
+    @ApiModelProperty("涓嬬彮璁板綍id")
+    private Long offWorkDataId;
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/mapper/StaffAttendanceTrackingRecordMapper.java b/inspect-server/src/main/java/com/ruoyi/inspect/mapper/StaffAttendanceTrackingRecordMapper.java
new file mode 100644
index 0000000..362737e
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/mapper/StaffAttendanceTrackingRecordMapper.java
@@ -0,0 +1,22 @@
+package com.ruoyi.inspect.mapper;
+
+import com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import java.util.List;
+
+/**
+* @author 27233
+* @description 閽堝琛ㄣ�恠taff_attendance_tracking_record(浜哄憳鑰冨嫟-鑰冨嫟璁板綍)銆戠殑鏁版嵁搴撴搷浣淢apper
+* @createDate 2026-03-20 14:42:09
+* @Entity com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord
+*/
+public interface StaffAttendanceTrackingRecordMapper extends BaseMapper<StaffAttendanceTrackingRecord> {
+
+    public List<Long> selectIccIdList();
+
+}
+
+
+
+
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/pojo/StaffAttendanceTrackingRecord.java b/inspect-server/src/main/java/com/ruoyi/inspect/pojo/StaffAttendanceTrackingRecord.java
new file mode 100644
index 0000000..9b1a6dd
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/pojo/StaffAttendanceTrackingRecord.java
@@ -0,0 +1,205 @@
+package com.ruoyi.inspect.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+
+/**
+ * 浜哄憳鑰冨嫟-鑰冨嫟璁板綍
+ * @TableName staff_attendance_tracking_record
+ */
+@TableName(value ="staff_attendance_tracking_record")
+@Data
+public class StaffAttendanceTrackingRecord implements Serializable {
+    /**
+     * 涓婚敭id
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * icc寮�鏀惧钩鍙颁富閿甶d
+     */
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long iccId;
+
+    /**
+     * 鍒峰崱鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime swingTime;
+
+    /**
+     * 鍛樺伐id
+     */
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long personId;
+
+    /**
+     * 鍛樺伐缂栧彿
+     */
+    private String personCode;
+
+    /**
+     * 鍛樺伐濮撳悕
+     */
+    private String personName;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     * 鑰冨嫟缁撴灉:0-寮傚父,1-姝e父
+     */
+    private Integer result;
+
+    /**
+     * 鍗″彿
+     */
+    private String cardNumber;
+
+    /**
+     * 鍗$姸鎬侊紝-1-绌虹櫧鍗★紝0-姝e父鍗★紝1-鎸傚け鍗★紝2-娉ㄩ攢鍗�
+     */
+    private Integer cardStatus;
+
+    /**
+     * 绫诲瀷锛�0-IC鍗�, 1-鏈夋簮RFID, 2-CPU鍗�
+     */
+    private Integer cardType;
+
+    /**
+     * 閫氶亾缂栫爜
+     */
+    private String channelCode;
+
+    /**
+     * 閫氶亾鍚嶇О
+     */
+    private String channelName;
+
+    /**
+     * 璁惧缂栫爜
+     */
+    private String deviceCode;
+
+    /**
+     * 璁惧鍚嶇О
+     */
+    private String deviceName;
+
+    /**
+     * 杩涘嚭闂ㄧ被鍨嬶紝1-杩涢棬, 2鍑洪棬, 3-杩�/鍑洪棬
+     */
+    private Integer enterOrExit;
+
+    /**
+     * 1-鍐呴儴浜哄憳, 2-璁垮锛氬唴閮ㄤ汉鍛樻槸鍦ㄤ汉鍛樼鐞嗕腑娣诲姞鐨勪汉鍛橈紝璁垮鏄湪璁垮瀛愮郴缁熶腑褰曞叆鐨勮瀹�
+     */
+    private Integer imageType;
+
+    /**
+     * 寮�闂ㄧ粨鏋滐紝0-澶辫触锛�1-鎴愬姛
+     */
+    private Integer openResult;
+
+    /**
+     * 寮�闂ㄧ被鍨嬶紝璇﹁ 寮�闂ㄧ被鍨� 瀛楀吀
+     */
+    private Integer openType;
+
+    /**
+     * 璇佷欢鍙风爜锛屼細杩涜鑴辨晱澶勭悊
+     */
+    private String paperNumber;
+
+    /**
+     * 鎶撳浘锛岀浉瀵硅矾寰勶紝瀹屾暣璁块棶璺緞鍙傝�僌SS鏂瑰紡缁勮
+     */
+    private String recordImageUrl;
+
+    /**
+     * 鎶撳浘锛岀粷瀵硅矾寰勶紝鍏煎鍘嗗彶鐗堟湰锛屼笉鎺ㄨ崘浣跨敤
+     */
+    private String recordImage;
+
+    /**
+     * 寮�闂ㄥけ璐ュ師鍥�
+     */
+    private String remark;
+
+    /**
+     * 鍙g僵鐘舵��(3-甯﹀彛缃�,2鈥旀病甯﹀彛缃�,1-鏈瘑鍒�)
+     */
+    private Integer maskState;
+
+    /**
+     * 鏄惁瓒呮俯
+     */
+    private Integer overTemp;
+
+    /**
+     * 浣撴俯
+     */
+    private Double curTemp;
+
+    /**
+     * 鏄惁鍚屾(0锛氬悓姝� 1锛氭墜鍔ㄦ柊澧�)
+     */
+    private Integer isSync;
+
+    /**
+     * 鏄惁绾冲叆鑰冨嫟缁熻
+     */
+    private Boolean enableReport;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Integer createUser;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Integer updateUser;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+
+    public StaffAttendanceTrackingRecord(Long id,LocalDateTime swingTime, String personCode, String personName, String deptName, Integer result, Integer enterOrExit, Integer isSync) {
+        this.id = id;
+        this.swingTime = swingTime;
+        this.personCode = personCode;
+        this.personName = personName;
+        this.deptName = deptName;
+        this.result = result;
+        this.enterOrExit = enterOrExit;
+        this.isSync = isSync;
+    }
+
+    public StaffAttendanceTrackingRecord() {
+    }
+}
\ No newline at end of file
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/StaffAttendanceTrackingRecordService.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/StaffAttendanceTrackingRecordService.java
new file mode 100644
index 0000000..f0476ff
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/StaffAttendanceTrackingRecordService.java
@@ -0,0 +1,31 @@
+package com.ruoyi.inspect.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.inspect.dto.StaffAttendanceDTO;
+import com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord;
+import com.ruoyi.inspect.vo.StaffAttendanceVO;
+import com.ruoyi.inspect.vo.StaffClockInVO;
+import com.ruoyi.performance.dto.PerformanceShiftMapDto;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+* @author 27233
+* @description 閽堝琛ㄣ�恠taff_attendance_tracking_record(浜哄憳鑰冨嫟-鑰冨嫟璁板綍)銆戠殑鏁版嵁搴撴搷浣淪ervice
+* @createDate 2026-03-09 17:42:25
+*/
+public interface StaffAttendanceTrackingRecordService extends IService<StaffAttendanceTrackingRecord> {
+
+    boolean syncAttendanceRecord(LocalDateTime startDate, LocalDateTime endDate);
+
+    IPage<StaffAttendanceVO> pageAttendanceRecord(Page<StaffAttendanceTrackingRecord> page, StaffAttendanceDTO staffAttendanceDTO);
+
+    List<StaffAttendanceTrackingRecord> getClockInRecord(StaffAttendanceDTO staffAttendanceDTO);
+
+    PerformanceShiftMapDto checkDutyDate(StaffAttendanceDTO staffAttendanceDTO);
+
+    boolean saveOrUpdateRecord(StaffAttendanceDTO staffAttendanceDTO);
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/IfsPartPropsRecordServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/IfsPartPropsRecordServiceImpl.java
index 97c3271..d30886e 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/IfsPartPropsRecordServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/IfsPartPropsRecordServiceImpl.java
@@ -18,7 +18,6 @@
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
index 24528ac..9d256d3 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
@@ -811,7 +811,7 @@
                 )
                 .ne(InsProduct::getIsBinding, 1));
         insProducts.addAll(insProductMapper.selectFiberInsProduct(InsSampleIds, laboratory));
-        if (insProducts.size() > 0) {
+        if (!insProducts.isEmpty()) {
             String str = "";
             int count = 0;
             for (InsProduct product : insProducts) {
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
index 816444e..62688d0 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
@@ -860,6 +860,7 @@
                 // 浼佷笟寰俊閫氱煡
                 String message = "";
                 message += "妫�娴嬬粨鏋滄彁浜ら�氱煡";
+                message += "\nIFS鍩�: " + one.getContract();
                 message += "\n鎵规鍙�: " + one.getUpdateBatchNo();
                 message += "\n闆朵欢鍙�: " + one.getPartNo();
                 message += "\n闆朵欢鎻忚堪: " + one.getPartDesc();
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/RawMaterialOrderServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/RawMaterialOrderServiceImpl.java
index e253ca4..2bb2006 100644
--- a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/RawMaterialOrderServiceImpl.java
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/RawMaterialOrderServiceImpl.java
@@ -242,6 +242,7 @@
         if(!validateValue){
             throw new ErrorException("鎶ユ澶辫触锛岄潪娉曠殑閿�鍞鍗曞垎绫绘灇涓�");
         }
+        validateUpdateBatchNo(ifsInventoryQuantity);
         //鎵规鍙峰瓧姣嶈浆澶у啓
         ifsInventoryQuantity.setUpdateBatchNo(ifsInventoryQuantity.getUpdateBatchNo().toUpperCase(Locale.ROOT));
         ifsInventoryQuantityMapper.update(null, Wrappers.<IfsInventoryQuantity>lambdaUpdate()
@@ -266,6 +267,26 @@
             WxCpUtils.informWebHook(wechatProperty.getExaminingUrl(), message);
         });
         return 1;
+    }
+
+    /**
+     * 鏍¢獙澶栬喘璁㈠崟鎶ユ鐨勬壒娆″彿鏄惁閲嶅
+     * @param ifsInventoryQuantity
+     */
+    public void validateUpdateBatchNo(IfsInventoryQuantity ifsInventoryQuantity){
+        if(StringUtils.equals(ifsInventoryQuantity.getOrderType(),OrderType.WG.getValue())){
+            //鏌ヨ鍘嗗彶璁板綍
+            Long count = ifsInventoryQuantityMapper.selectCount(Wrappers.<IfsInventoryQuantity>lambdaQuery()
+                    .eq(IfsInventoryQuantity::getContract,ifsInventoryQuantity.getContract())
+                    .eq(IfsInventoryQuantity::getPartNo,ifsInventoryQuantity.getPartNo())
+                    .eq(IfsInventoryQuantity::getUpdateBatchNo,ifsInventoryQuantity.getUpdateBatchNo())
+                    .eq(IfsInventoryQuantity::getOrderType,OrderType.WG.getValue())
+                    .ne(IfsInventoryQuantity::getState,0)
+            );
+            if(count>0){
+                throw new RuntimeException("鎶ユ澶辫触锛岄浂浠�"+ifsInventoryQuantity.getPartNo()+"鎵�鎶ユ鐨勬壒娆″彿銆�"+ifsInventoryQuantity.getUpdateBatchNo()+"銆戝凡瀛樺湪锛�");
+            }
+        }
     }
 
     /**
@@ -526,6 +547,7 @@
         if(!OrderType.validateValue(ifsInventoryQuantity.getOrderType())){
             throw new ErrorException("鏂板鎶ユ淇℃伅澶辫触锛岄潪娉曠殑閿�鍞鍗曞垎绫绘灇涓�");
         }
+        validateUpdateBatchNo(ifsInventoryQuantity);
         ifsInventoryQuantityMapper.insert(ifsInventoryQuantity);
     }
 
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/StaffAttendanceTrackingRecordServiceImpl.java b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/StaffAttendanceTrackingRecordServiceImpl.java
new file mode 100644
index 0000000..104239e
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/service/impl/StaffAttendanceTrackingRecordServiceImpl.java
@@ -0,0 +1,466 @@
+package com.ruoyi.inspect.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.domain.Result;
+import com.ruoyi.common.enums.ClockInState;
+import com.ruoyi.common.enums.EnterOrExitType;
+import com.ruoyi.common.enums.SyncStatus;
+import com.ruoyi.common.utils.api.icc.IccApiUtil;
+import com.ruoyi.common.utils.api.icc.model.GetResultPageRequest;
+import com.ruoyi.common.utils.api.icc.model.GetResultPageResponse;
+import com.ruoyi.inspect.dto.StaffAttendanceDTO;
+import com.ruoyi.inspect.mapper.StaffAttendanceTrackingRecordMapper;
+import com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord;
+import com.ruoyi.inspect.service.StaffAttendanceTrackingRecordService;
+import com.ruoyi.inspect.util.HourDiffCalculator;
+import com.ruoyi.inspect.vo.StaffAttendanceVO;
+import com.ruoyi.inspect.vo.StaffClockInVO;
+import com.ruoyi.performance.dto.PerformanceShiftMapDto;
+import com.ruoyi.performance.mapper.PerformanceShiftMapper;
+import com.ruoyi.performance.mapper.ShiftTimeMapper;
+import com.ruoyi.performance.pojo.ShiftTime;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author 27233
+ * @description 閽堝琛ㄣ�恠taff_attendance_tracking_record(浜哄憳鑰冨嫟-鑰冨嫟璁板綍)銆戠殑鏁版嵁搴撴搷浣淪ervice瀹炵幇
+ * @createDate 2026-03-09 17:42:25
+ */
+@Slf4j
+@Service
+public class StaffAttendanceTrackingRecordServiceImpl
+        extends ServiceImpl<StaffAttendanceTrackingRecordMapper, StaffAttendanceTrackingRecord>
+        implements StaffAttendanceTrackingRecordService {
+
+    @Autowired
+    private IccApiUtil iccApiUtil;
+
+    @Autowired
+    private PerformanceShiftMapper performanceShiftMapper;
+
+    @Autowired
+    private ShiftTimeMapper shiftTimeMapper;
+
+    private DateTimeFormatter yyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+    private DateTimeFormatter HHmm = DateTimeFormatter.ofPattern("HH:mm");
+
+    private DateTimeFormatter yyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    /** 璐ㄩ噺閮╥d */
+    private final static String deptIds = "6";
+
+    // 鍥哄畾鍓嶇紑
+    private static final String PREFIX = "ZT-";
+
+    // 鏁板瓧閮ㄥ垎鍥哄畾闀垮害
+    private static final int DIGIT_LENGTH = 6;
+
+    /**
+     * 鍚屾鐨勯棬绂佽澶囧垪琛�
+     * channel_name device_code
+     * 10.100.22.2_闂ㄧ閫氶亾_1 1001538
+     * 10.100.22.3_闂ㄧ閫氶亾_1 1001539
+     * 10.100.22.4_闂ㄧ閫氶亾_1 1001540
+     * 10.100.22.5_闂ㄧ閫氶亾_1 1001541
+     * 10.100.22.12_闂ㄧ閫氶亾_1 1001626
+     * 10.100.22.13_闂ㄧ閫氶亾_1 1001627
+     * 10.100.22.14_闂ㄧ閫氶亾_1 1001628
+     * 10.100.22.15_闂ㄧ閫氶亾_1 1001629
+     */
+    private final static List<String> syncDeviceCode = Arrays.asList("1001538", "1001539", "1001540", "1001541",
+            "1001626", "1001627", "1001628", "1001629");
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean syncAttendanceRecord(LocalDateTime startDate, LocalDateTime endDate) {
+        if (ObjectUtil.isAllEmpty(startDate, endDate)) {
+            throw new RuntimeException("鍚屾鏃ユ湡涓嶈兘涓虹┖");
+        }
+
+        // 鏌ヨ宸插悓姝ョ殑璁板綍
+        List<Long> trackingRecordIccIdList = baseMapper.selectIccIdList();
+        try {
+            // 鏌ヨicc寮�鏀惧钩鍙扮殑鑰冨嫟璁板綍
+            GetResultPageRequest getResultPageRequest = new GetResultPageRequest();
+            getResultPageRequest.setPageNum(1);
+            getResultPageRequest.setPageSize(9999);
+            getResultPageRequest.setDeptIds(deptIds);
+            getResultPageRequest.setStartSwingTime(startDate.format(yyyMMddHHmmss));
+            getResultPageRequest.setEndSwingTime(endDate.format(yyyMMddHHmmss));
+            GetResultPageResponse trackingRecordResponse = iccApiUtil.getAttendanceResultPage(getResultPageRequest);
+            if (trackingRecordResponse.isSuccess()) {
+                if (ObjectUtil.isNotNull(trackingRecordResponse.getData())
+                        && !trackingRecordResponse.getData().getPageData().isEmpty()) {
+                    List<StaffAttendanceTrackingRecord> recordList = trackingRecordResponse.getData().getPageData()
+                            .stream()
+                            .filter(f -> !trackingRecordIccIdList.contains(f.getId())
+                                    && syncDeviceCode.contains(f.getDeviceCode()))
+                            .map(result -> {
+                                StaffAttendanceTrackingRecord trackingRecord = new StaffAttendanceTrackingRecord();
+                                BeanUtil.copyProperties(result, trackingRecord);
+                                trackingRecord.setIccId(result.getId());
+                                trackingRecord.setPersonCode(restorePersonCode(result.getPersonCode()));
+                                trackingRecord.setId(null);
+                                return trackingRecord;
+                            }).collect(Collectors.toList());
+                    if (!recordList.isEmpty())
+                        this.saveBatch(recordList);
+                    log.info("鍚屾ICC鑰冨嫟璁板綍鏉℃暟->,{}", recordList.size());
+                }
+            } else {
+                log.error("鍚屾ICC寮�鏀惧钩鍙拌�冨嫟璁板綍閿欒,{}", trackingRecordResponse.getErrMsg());
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return true;
+    }
+
+    @Override
+    public IPage<StaffAttendanceVO> pageAttendanceRecord(Page<StaffAttendanceTrackingRecord> page,
+            StaffAttendanceDTO staffAttendanceDTO) {
+        // 鏌ヨ鎵撳崱璁板綍
+        System.out.println(staffAttendanceDTO.getStartDate());
+        System.out.println(staffAttendanceDTO.getEndDate());
+        System.out.println(ObjectUtils.allNotNull(staffAttendanceDTO.getStartDate(),staffAttendanceDTO.getEndDate()));
+        Wrapper<StaffAttendanceTrackingRecord> queryWrapper = Wrappers.<StaffAttendanceTrackingRecord>lambdaQuery()
+                .eq(StaffAttendanceTrackingRecord::getEnableReport, Boolean.TRUE)
+                .between(ObjectUtils.allNotNull(staffAttendanceDTO.getStartDate(),staffAttendanceDTO.getEndDate()),
+                        StaffAttendanceTrackingRecord::getSwingTime, staffAttendanceDTO.getStartDate(),ObjectUtils.isNotEmpty(staffAttendanceDTO.getEndDate())?staffAttendanceDTO.getEndDate().plusDays(1L):null)
+                .and(StringUtils.isNotEmpty(staffAttendanceDTO.getKeyword()),
+                        i -> i.like(StaffAttendanceTrackingRecord::getPersonCode, staffAttendanceDTO.getKeyword())
+                                .or()
+                                .like(StaffAttendanceTrackingRecord::getPersonName, staffAttendanceDTO.getKeyword()));
+        List<StaffAttendanceTrackingRecord> recordList = baseMapper.selectList(queryWrapper);
+        // 鏌ヨ鐝
+        List<PerformanceShiftMapDto> performanceShifts = performanceShiftMapper.selectListByWorkTime(
+                staffAttendanceDTO.getStartDate(), staffAttendanceDTO.getEndDate(), staffAttendanceDTO.getKeyword());
+        // 缁勮鏁版嵁
+        List<StaffAttendanceVO> resultList = new ArrayList<>();
+        for (int i = 0; i < performanceShifts.size(); i++) {
+            PerformanceShiftMapDto p = performanceShifts.get(i);
+            StaffAttendanceVO vo = new StaffAttendanceVO();
+            // 鑾峰彇瀵瑰簲鐝灏忔椂鏁�
+            if (ObjectUtil.isAllNotEmpty(p.getStartTime(), p.getEndTime()) && !recordList.isEmpty()) {
+                double hourDiff = HourDiffCalculator.getHourDiff(p.getStartTime(), p.getEndTime());
+                /*
+                 * 涓婄彮鏃堕棿鍙栧�硷細
+                 * 姝e父锛氬綋鍓嶇彮娆″紑濮嬪墠鏈�鍚庝竴娆¤繘闂ㄦ椂闂�
+                 * 寮傚父(杩熷埌)锛氭棤褰撳墠鐝寮�濮嬪墠杩涢棬璁板綍锛屽彇褰撳墠鐝寮�濮嬪悗绗竴娆¤繘闂ㄦ椂闂�
+                 * 涓嬬彮鏃堕棿鍙栧�硷細
+                 * 姝e父锛氬綋鍓嶇彮娆$粨鏉熷悗绗竴娆″嚭闂ㄦ椂闂�
+                 * 寮傚父(鏃╅��)锛氭棤褰撳墠鐝缁撴潫鍒颁笅涓�鐝寮�濮嬪墠鐨勫嚭闂ㄨ褰曞苟涓旀渶鍚庝竴娆″嚭闂ㄥ湪褰撳墠鐝鏃堕棿鑼冨洿鍐咃紝鍙栧綋鍓嶇彮娆℃渶鍚庝竴娆″嚭闂ㄦ椂闂�
+                 */
+                // 褰撳墠鐝寮�濮嬪ぉ0鐐规椂闂�
+                LocalDateTime startDateTime = LocalDateTime.of(p.getWorkTime().toLocalDate(), LocalTime.MIN);
+                // 褰撳墠鐝缁撴潫澶�24鐐规椂闂�
+                LocalDateTime endDateTime = LocalDateTime.of(p.getWorkTime().toLocalDate(), LocalTime.MAX);
+                // 褰撳墠鐝寮�濮嬫椂闂�
+                LocalTime currentShiftStartTime = LocalTime.parse(p.getStartTime(), HHmm);
+                LocalDateTime currentShiftStartDateTime = LocalDateTime.of(p.getWorkTime().toLocalDate(),
+                        currentShiftStartTime);
+                // 褰撳墠鐝缁撴潫鏃堕棿
+                LocalTime currentShiftEndTime = LocalTime.parse(p.getEndTime(), HHmm);
+                LocalDateTime currentShiftEndDateTime = LocalDateTime.of(endDateTime.toLocalDate(),
+                        currentShiftEndTime);
+                // 涓嬩竴鐝寮�濮嬫椂闂�
+                LocalDateTime nextShiftStartDateTime = getShiftStartDateTime(i + 1, performanceShifts,
+                        startDateTime.plusDays(1L));
+                if (Double.compare(hourDiff, 0) == -1) {
+                    // 濡傛灉灏忔椂宸负璐熸暟锛岃〃绀鸿法澶╋紝缁撴潫鏃堕棿闇�鍔犱竴
+                    endDateTime = endDateTime.plusDays(1L);
+                }
+                // 杩囨护鍑哄綋鍓嶄汉鍛樺綋鍓嶇彮娆$殑杩�/鍑鸿褰�
+                LocalDateTime workDateTime = null;
+                LocalDateTime offWorkDateTime = null;
+                List<StaffAttendanceTrackingRecord> enterRecords = filterAttendanceRecord(p.getPersonCode(),
+                        EnterOrExitType.ENTER.getValue(), startDateTime, endDateTime, recordList);
+                if (!enterRecords.isEmpty()) {
+                    // 涓婄彮鏃堕棿鍜岀姸鎬�
+                    StaffAttendanceTrackingRecord enterRecord = enterRecords.stream()
+                            .filter(s -> !s.getSwingTime().isAfter(currentShiftStartDateTime))
+                            .max(Comparator.comparing(StaffAttendanceTrackingRecord::getSwingTime))
+                            .orElse(new StaffAttendanceTrackingRecord());
+                    if (BeanUtil.isEmpty(enterRecord)) {
+                        enterRecord = enterRecords.stream()
+                                .filter(s -> (s.getSwingTime().isAfter(currentShiftStartDateTime)
+                                        && s.getSwingTime().isBefore(currentShiftEndDateTime)))
+                                .min(Comparator.comparing(StaffAttendanceTrackingRecord::getSwingTime))
+                                .orElse(new StaffAttendanceTrackingRecord());
+                        workDateTime = enterRecord.getSwingTime();
+                        vo.setWorkClockInState(ClockInState.ABNORMAL.getValue());
+                        vo.setWorkDataId(enterRecord.getId());
+                    } else {
+                        workDateTime = enterRecord.getSwingTime();
+                        vo.setWorkClockInState(ClockInState.NORMAL.getValue());
+                        vo.setWorkDataId(enterRecord.getId());
+                    }
+                }
+                List<StaffAttendanceTrackingRecord> exitRecords = filterAttendanceRecord(p.getPersonCode(),
+                        EnterOrExitType.EXIT.getValue(), startDateTime, endDateTime, recordList);
+                if (!exitRecords.isEmpty()) {
+                    // 涓嬬彮鏃堕棿鍜岀姸鎬�
+                    StaffAttendanceTrackingRecord exitRecord = exitRecords.stream()
+                            .filter(s -> !s.getSwingTime().isBefore(currentShiftEndDateTime)
+                                    && s.getSwingTime().isBefore(nextShiftStartDateTime))
+                            .min(Comparator.comparing(StaffAttendanceTrackingRecord::getSwingTime))
+                            .orElse(new StaffAttendanceTrackingRecord());
+                    if (BeanUtil.isEmpty(exitRecord)) {
+                        exitRecord = exitRecords.stream()
+                                .filter(s -> (s.getSwingTime().isAfter(currentShiftStartDateTime)
+                                        && s.getSwingTime().isBefore(currentShiftEndDateTime)))
+                                .max(Comparator.comparing(StaffAttendanceTrackingRecord::getSwingTime))
+                                .orElse(new StaffAttendanceTrackingRecord());
+                        offWorkDateTime = exitRecord.getSwingTime();
+                        vo.setOffClockInState(ClockInState.ABNORMAL.getValue());
+                        vo.setOffWorkDataId(exitRecord.getId());
+                    } else {
+                        offWorkDateTime = exitRecord.getSwingTime();
+                        vo.setOffClockInState(ClockInState.NORMAL.getValue());
+                        vo.setOffWorkDataId(exitRecord.getId());
+                    }
+
+                }
+                if (ObjectUtils.allNotNull(workDateTime, offWorkDateTime)) {
+                    vo.setActualWorkHours(HourDiffCalculator.getHourDiff(workDateTime.toLocalTime().format(HHmm),
+                            offWorkDateTime.toLocalTime().format(HHmm)));
+                }
+                // 璧嬪��
+                vo.setShiftId(p.getShift());
+                vo.setPersonCode(p.getPersonCode());
+                vo.setPersonName(p.getUserName());
+                vo.setPlannedWorkHours(hourDiff);
+                vo.setSwingDate(startDateTime);
+                vo.setWorkDateTime(workDateTime);
+                vo.setOffWorkDateTime(offWorkDateTime);
+                vo.setDeptName(recordList.get(0).getDeptName());
+                vo.setIsSync(recordList.get(0).getIsSync());
+                vo.setCreateUser(recordList.get(0).getCreateUser());
+                vo.setCreateTime(recordList.get(0).getCreateTime());
+                vo.setUpdateUser(recordList.get(0).getUpdateUser());
+                vo.setUpdateTime(recordList.get(0).getUpdateTime());
+                vo.setResult(ClockInState.ABNORMAL.getValue());
+                if(ObjectUtils.allNotNull(vo.getWorkClockInState(),vo.getOffClockInState())){
+                    vo.setResult(Integer.min(vo.getWorkClockInState(),vo.getOffClockInState()));
+                }
+                // 璁$畻缂哄嫟鏃堕暱
+                if (ObjectUtils.allNotNull(vo.getActualWorkHours(), vo.getPlannedWorkHours())) {
+                    double absenceWorkHours = BigDecimal.valueOf(vo.getPlannedWorkHours())
+                            .subtract(BigDecimal.valueOf(vo.getActualWorkHours())).setScale(2, RoundingMode.HALF_EVEN)
+                            .doubleValue();
+                    if (Double.compare(absenceWorkHours, 0) > 0) {
+                        vo.setAbsenceWorkHours(absenceWorkHours);
+                    }
+                }
+                if (!enterRecords.isEmpty() || !exitRecords.isEmpty())
+                    resultList.add(vo);
+            }
+        }
+        return limitPages(page, resultList);
+    }
+
+    @Override
+    public List<StaffAttendanceTrackingRecord> getClockInRecord(StaffAttendanceDTO staffAttendanceDTO) {
+        ShiftTime shiftTime = shiftTimeMapper.selectOne(Wrappers.<ShiftTime>lambdaQuery().eq(ShiftTime::getShift, staffAttendanceDTO.getShiftId()));
+        if(ObjectUtils.isEmpty(shiftTime)){
+            throw new RuntimeException("鏈煡璇㈠埌褰撳墠鐝鐨勬椂闂撮厤缃�");
+        }
+        LocalDateTime startDateTime = LocalDateTime.of(staffAttendanceDTO.getSwingDate(),LocalTime.MIN);
+        LocalDateTime endDateTime = LocalDateTime.of(staffAttendanceDTO.getSwingDate(),LocalTime.MAX);
+        //鍒ゆ柇褰撳墠鐝鏄惁瑕佽法澶�
+        double hourDiff = HourDiffCalculator.getHourDiff(shiftTime.getStartTime(), shiftTime.getEndTime());
+        if(Double.compare(hourDiff,0)<0){
+            endDateTime = endDateTime.plusDays(1L);
+        }
+        return baseMapper.selectList(Wrappers.<StaffAttendanceTrackingRecord>lambdaQuery()
+                .eq(StaffAttendanceTrackingRecord::getPersonCode,staffAttendanceDTO.getPersonCode())
+                .between(ObjectUtil.isAllNotEmpty(startDateTime, endDateTime),StaffAttendanceTrackingRecord::getSwingTime, startDateTime,endDateTime)
+                .orderByAsc(StaffAttendanceTrackingRecord::getSwingTime)
+        );
+    }
+
+    @Override
+    public PerformanceShiftMapDto checkDutyDate(StaffAttendanceDTO staffAttendanceDTO) {
+        if(ObjectUtils.isEmpty(staffAttendanceDTO.getSwingDate())){
+            throw new RuntimeException("鑰冨嫟鏃ユ湡涓嶈兘涓虹┖");
+        }
+        LocalDateTime startDateTime = LocalDateTime.of(staffAttendanceDTO.getSwingDate(),LocalTime.MIN);
+        LocalDateTime endDateTime = LocalDateTime.of(staffAttendanceDTO.getSwingDate(),LocalTime.MAX);
+        Long count = baseMapper.selectCount(Wrappers.<StaffAttendanceTrackingRecord>lambdaQuery()
+                .eq(StaffAttendanceTrackingRecord::getPersonCode, staffAttendanceDTO.getPersonCode())
+                .between(StaffAttendanceTrackingRecord::getSwingTime, startDateTime, endDateTime));
+        if(count>0){
+            throw new RuntimeException("鎵�閫夋棩鏈熷凡瀛樺湪鑰冨嫟璁板綍锛�");
+        }
+        //鏌ヨ浜哄憳褰撳ぉ鐝閰嶇疆
+        List<PerformanceShiftMapDto> shiftMapDtos = performanceShiftMapper.selectListByWorkTime(startDateTime, endDateTime, staffAttendanceDTO.getPersonCode());
+        if(shiftMapDtos.isEmpty()){
+            throw new RuntimeException("鏈壘鍒颁汉鍛樻墍閫夎�冨嫟鏃堕棿鐨勭彮娆¢厤缃紝璇峰厛閰嶇疆鐝");
+        }
+        return shiftMapDtos.get(0);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveOrUpdateRecord(StaffAttendanceDTO staffAttendanceDTO) {
+        if(ObjectUtils.isEmpty(staffAttendanceDTO)){
+            throw new RuntimeException("浼犲弬涓嶈兘涓虹┖");
+        }
+        LocalDateTime workDateTime = LocalDateTime.of(staffAttendanceDTO.getSwingDate(),staffAttendanceDTO.getWorkDateTime());
+        LocalDateTime offWorkDateTime = LocalDateTime.of(staffAttendanceDTO.getSwingDate(),staffAttendanceDTO.getOffWorkDateTime());
+        //鏍¢獙涓婁笅鐝椂闂存槸鍚﹁法澶�
+        double hourDiff = HourDiffCalculator.getHourDiff(staffAttendanceDTO.getWorkDateTime().format(HHmm), staffAttendanceDTO.getOffWorkDateTime().format(HHmm));
+        if(Double.compare(hourDiff,0)<0){
+            offWorkDateTime = offWorkDateTime.plusDays(1L);
+        }
+        //缁勮涓�/涓嬬彮鑰冨嫟璁板綍
+        StaffAttendanceTrackingRecord workRecord = new StaffAttendanceTrackingRecord(
+                staffAttendanceDTO.getWorkDataId(),
+                workDateTime,
+                staffAttendanceDTO.getPersonCode(),
+                staffAttendanceDTO.getPersonName(),
+                staffAttendanceDTO.getDeptName(),
+                staffAttendanceDTO.getResult(),
+                EnterOrExitType.ENTER.getValue(),
+                SyncStatus.INERT.getValue());
+        StaffAttendanceTrackingRecord offWorkRecord = new StaffAttendanceTrackingRecord(
+                staffAttendanceDTO.getOffWorkDataId(),
+                offWorkDateTime,
+                staffAttendanceDTO.getPersonCode(),
+                staffAttendanceDTO.getPersonName(),
+                staffAttendanceDTO.getDeptName(),
+                staffAttendanceDTO.getResult(),
+                EnterOrExitType.EXIT.getValue(),
+                SyncStatus.INERT.getValue());
+        List<StaffAttendanceTrackingRecord> records = Arrays.asList(workRecord, offWorkRecord);
+        return this.saveOrUpdateBatch(records);
+    }
+
+    /**
+     * 鑷畾涔夊垎椤垫柟娉�
+     * 
+     * @param page       鍒嗛〉瀵硅薄
+     * @param resultList 鏁版嵁鍒楄〃
+     * @return
+     */
+    private IPage<StaffAttendanceVO> limitPages(Page<StaffAttendanceTrackingRecord> page,
+            List<StaffAttendanceVO> resultList) {
+        IPage<StaffAttendanceVO> resultPage = new Page<>();
+        long current = page.getCurrent();
+        long size = page.getSize();
+        if (current < 1)
+            current = 1;
+        long total = resultList.size();
+        long pages = getPages(size,total);
+        int startIndex = Math.toIntExact((current - 1) * size >= total ? (pages - 1) * size : (current - 1) * size);
+        int endIndex = Math.toIntExact(Math.min(current * size, total));
+        List<StaffAttendanceVO> records = resultList.subList(startIndex, endIndex);
+        resultPage.setRecords(records);
+        resultPage.setTotal(total);
+        resultPage.setSize(size);
+        resultPage.setCurrent(current);
+        if(current>=pages)resultPage.setCurrent(pages);
+        return resultPage;
+    }
+
+    /**
+     * 褰撳墠鍒嗛〉鎬婚〉鏁�
+     */
+    private long getPages(long size,long total) {
+        if (size == 0) {
+            return 0L;
+        }
+        long pages = total / size;
+        if (total % size != 0) {
+            pages++;
+        }
+        return pages;
+    }
+
+    /**
+     * 鑾峰彇鎸囧畾涓嬫爣鐨勭彮娆″紑濮嬫椂闂�
+     * 
+     * @param index
+     * @param dtoList
+     * @return
+     */
+    private LocalDateTime getShiftStartDateTime(int index, List<PerformanceShiftMapDto> dtoList,
+            LocalDateTime nextShiftTime) {
+        if (dtoList.isEmpty() || index >= dtoList.size()) {
+            return LocalDateTime.of(nextShiftTime.toLocalDate(), LocalTime.MAX);
+        }
+        LocalTime localTime = ObjectUtil.isNull(dtoList.get(index).getStartTime()) ? LocalTime.MAX
+                : LocalTime.parse(dtoList.get(index).getStartTime(), HHmm);
+        return LocalDateTime.of(nextShiftTime.toLocalDate(), localTime);
+    }
+
+    /**
+     * 杩囨护鎸囧畾鏃堕棿鑼冨洿鐨勮繘鍑鸿褰�
+     * 
+     * @param personCode    浜哄憳缂栧彿
+     * @param enterOrExit   杩涢棬/鍑洪棬
+     * @param startDateTime 寮�濮嬫椂闂�
+     * @param endDateTime   缁撴潫鏃堕棿
+     * @param recordList    杩涘嚭璁板綍鍒楄〃
+     * @return
+     */
+    public List<StaffAttendanceTrackingRecord> filterAttendanceRecord(String personCode, Integer enterOrExit,
+            LocalDateTime startDateTime, LocalDateTime endDateTime, List<StaffAttendanceTrackingRecord> recordList) {
+        if (recordList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        return recordList.stream()
+                .filter(s -> ObjectUtil.equal(s.getEnterOrExit(), enterOrExit))
+                .filter(s -> (s.getSwingTime().isAfter(startDateTime) && s.getSwingTime().isBefore(endDateTime))
+                        && StringUtils.equals(s.getPersonCode(), personCode))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 灏嗙函鏁板瓧澶嶅師涓烘爣鍑嗗憳宸ョ紪鍙�
+     * 
+     * @param number 浼犲叆鐨勬暟瀛楋紙鍛樺伐缂栧彿鍘婚櫎鍓嶇紑鍜屽墠缃�0鍚庣殑鏁板瓧锛屾敮鎸乮nt/long/String绫诲瀷锛�
+     * @return 鏍囧噯鏍煎紡鍛樺伐缂栧彿锛堝杈撳叆123 鈫� ZT-000123锛�
+     * @throws IllegalArgumentException 浼犲叆闈炴暟瀛�/璐熸暟鏃舵姏鍑哄紓甯�
+     */
+    public static String restorePersonCode(Object number) {
+        // 1. 绌哄�兼牎楠�
+        if (number == null) {
+            throw new IllegalArgumentException("浼犲叆鏁板瓧涓嶈兘涓虹┖");
+        }
+
+        // 2. 缁熶竴杞崲涓哄瓧绗︿覆骞跺幓闄ら灏剧┖鏍�
+        String numStr = number.toString().trim();
+
+        // 3. 鏍¢獙鏄惁涓虹函鏁板瓧锛堟帓闄よ礋鏁般�侀潪鏁板瓧瀛楃锛�
+        if (!numStr.matches("\\d+")) {
+            throw new IllegalArgumentException("浼犲叆鐨勪笉鏄湁鏁堟鏁存暟锛�" + numStr);
+        }
+
+        // 4. 琛ュ墠缃�0鍒版寚瀹氶暱搴︼紙6浣嶏級锛岃秴鍑哄垯淇濈暀鍘熸暟瀛�
+        String paddedNum = String.format("%0" + DIGIT_LENGTH + "d", Long.parseLong(numStr));
+
+        // 5. 鎷兼帴鍓嶇紑杩斿洖
+        return PREFIX + paddedNum;
+    }
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/task/SyncStaffAttendanceRecordSchedule.java b/inspect-server/src/main/java/com/ruoyi/inspect/task/SyncStaffAttendanceRecordSchedule.java
new file mode 100644
index 0000000..3d595ed
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/task/SyncStaffAttendanceRecordSchedule.java
@@ -0,0 +1,36 @@
+package com.ruoyi.inspect.task;
+
+
+import com.ruoyi.inspect.service.StaffAttendanceTrackingRecordService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+
+/**
+ * 鍚屾鎷夊彇icc寮�鏀惧钩鍙拌�冨嫟璁板綍瀹氭椂浠诲姟
+ */
+@Slf4j
+@Component
+public class SyncStaffAttendanceRecordSchedule {
+
+    @Autowired
+    private StaffAttendanceTrackingRecordService trackingRecordService;
+
+
+    @Scheduled(cron = "0 0 1 * * ?")
+    public void sync() {
+        log.info("--------鍚屾鑰冨嫟璁板綍瀹氭椂浠诲姟寮�濮�--------");
+        LocalDate yesterday = LocalDate.now(ZoneId.of("Asia/Shanghai")).minusDays(1L);
+        LocalDateTime startTime = LocalDateTime.of(yesterday, LocalTime.MIN);
+        LocalDateTime endTime = LocalDateTime.of(yesterday, LocalTime.MAX);
+        trackingRecordService.syncAttendanceRecord(startTime,endTime);
+        log.info("--------鍚屾鑰冨嫟璁板綍瀹氭椂浠诲姟缁撴潫--------");
+    }
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/util/HourDiffCalculator.java b/inspect-server/src/main/java/com/ruoyi/inspect/util/HourDiffCalculator.java
new file mode 100644
index 0000000..687645e
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/util/HourDiffCalculator.java
@@ -0,0 +1,61 @@
+package com.ruoyi.inspect.util;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+/**
+ * 鏃跺垎鏃堕棿宸绠楀伐鍏风被
+ * 鏀寔鏍煎紡锛欻H:mm锛�24灏忔椂鍒讹級锛屽 08:30銆�23:59銆�00:00
+ */
+public class HourDiffCalculator {
+
+    // 鏍¢獙HH:mm鏍煎紡鐨勬鍒欙紙24灏忔椂鍒讹紝灏忔椂00-23锛屽垎閽�00-59锛�
+    private static final Pattern TIME_PATTERN = Pattern.compile("^([01]?[0-9]|2[0-3]):[0-5][0-9]$");
+
+    /**
+     * 璁$畻涓や釜鏃跺垎瀛楃涓蹭箣闂寸殑鐩搁殧灏忔椂鏁�
+     * @param startTime 寮�濮嬫椂闂达紙HH:mm锛屽 "08:30"锛�
+     * @param endTime 缁撴潫鏃堕棿锛圚H:mm锛屽 "17:45"锛�
+     * @return 鐩搁殧灏忔椂鏁帮紙淇濈暀2浣嶅皬鏁帮紝濡� 9.25 灏忔椂锛�
+     * @throws IllegalArgumentException 鏃堕棿鏍煎紡閿欒鏃舵姏鍑哄紓甯�
+     */
+    public static double getHourDiff(String startTime, String endTime) {
+        // 1. 鏍¢獙鏃堕棿鏍煎紡
+        validateTimeFormat(startTime);
+        validateTimeFormat(endTime);
+
+        // 2. 瑙f瀽鏃跺垎瀛楃涓蹭负鎬诲垎閽熸暟
+        int startMinutes = convertTimeToMinutes(startTime);
+        int endMinutes = convertTimeToMinutes(endTime);
+
+        // 3. 璁$畻鍒嗛挓宸�
+        int minuteDiff = endMinutes - startMinutes;
+
+        // 4. 杞崲涓哄皬鏃舵暟锛堜繚鐣�2浣嶅皬鏁帮紝閬垮厤绮惧害涓㈠け锛�
+        BigDecimal hourDiff = new BigDecimal(minuteDiff)
+                .divide(new BigDecimal(60), 2, RoundingMode.HALF_UP);
+        return hourDiff.doubleValue();
+    }
+
+    /**
+     * 鏍¢獙鏃堕棿鏍煎紡鏄惁涓篐H:mm
+     */
+    private static void validateTimeFormat(String time) {
+        if (time == null || !TIME_PATTERN.matcher(time).matches()) {
+            throw new IllegalArgumentException("鏃堕棿鏍煎紡閿欒锛岄渶涓篐H:mm锛�24灏忔椂鍒讹級锛�" + time);
+        }
+    }
+
+    /**
+     * 灏咹H:mm瀛楃涓茶浆鎹负鎬诲垎閽熸暟锛堝 08:30 鈫� 510 鍒嗛挓锛�
+     */
+    private static int convertTimeToMinutes(String time) {
+        String[] parts = time.split(":");
+        int hour = Integer.parseInt(parts[0]);
+        int minute = Integer.parseInt(parts[1]);
+        return hour * 60 + minute;
+    }
+
+}
\ No newline at end of file
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffAttendanceVO.java b/inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffAttendanceVO.java
new file mode 100644
index 0000000..8bbb11c
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffAttendanceVO.java
@@ -0,0 +1,103 @@
+package com.ruoyi.inspect.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class StaffAttendanceVO {
+
+    /**
+     * 涓婄彮鏁版嵁涓婚敭id
+     */
+    private Long workDataId;
+
+    /**
+     * 涓嬬彮鏁版嵁涓婚敭id
+     */
+    private Long offWorkDataId;
+
+    /**
+     * 浜哄憳缂栧彿
+     */
+    private String personCode;
+
+    /**
+     * 浜哄憳鍚嶇О
+     */
+    private String personName;
+
+    /**
+     *閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     *鐝id
+     */
+    private String shiftId;
+
+    /**
+     *鑰冨嫟缁撴灉
+     */
+    private Integer result;
+
+    /**
+     *鑰冨嫟鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime swingDate;
+
+    /**
+     *涓婄彮鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime workDateTime;
+
+    /**
+     *涓嬬彮鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime offWorkDateTime;
+
+    /**
+     *涓婄彮鎵撳崱鐘舵�侊紙0锛氭甯革紝1锛氬紓甯革級
+     */
+    private Integer workClockInState;
+
+    /**
+     *涓嬬彮鎵撳崱鐘舵�侊紙0锛氭甯革紝1锛氬紓甯革級
+     */
+    private Integer offClockInState;
+
+    /**
+     * 搴斿嫟鏃堕暱
+     */
+    private Double plannedWorkHours;
+
+    /**
+     * 瀹為檯鏃堕暱
+     */
+    private Double actualWorkHours;
+
+    /**
+     * 缂哄嫟鏃堕暱
+     */
+    private Double absenceWorkHours;
+
+    /**
+     * 鏄惁涓哄悓姝ユ暟鎹�
+     */
+    private Integer isSync;
+
+    private Integer createUser;
+
+    private LocalDateTime createTime;
+
+    private Integer updateUser;
+
+    private LocalDateTime updateTime;
+
+
+}
diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffClockInVO.java b/inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffClockInVO.java
new file mode 100644
index 0000000..f615b1e
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/vo/StaffClockInVO.java
@@ -0,0 +1,14 @@
+package com.ruoyi.inspect.vo;
+
+import com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord;
+import lombok.Data;
+
+/**
+ * 浜哄憳鑰冨嫟锛氫汉鍛樻墦鍗¤褰曞搷搴斿璞�
+ */
+@Data
+public class StaffClockInVO extends StaffAttendanceTrackingRecord {
+
+
+
+}
diff --git a/inspect-server/src/main/resources/mapper/StaffAttendanceTrackingRecordMapper.xml b/inspect-server/src/main/resources/mapper/StaffAttendanceTrackingRecordMapper.xml
new file mode 100644
index 0000000..bd826ca
--- /dev/null
+++ b/inspect-server/src/main/resources/mapper/StaffAttendanceTrackingRecordMapper.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.inspect.mapper.StaffAttendanceTrackingRecordMapper">
+
+    <resultMap id="BaseResultMap" type="com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord">
+            <id property="id" column="id" jdbcType="BIGINT"/>
+            <result property="iccId" column="icc_id" jdbcType="BIGINT"/>
+            <result property="swingTime" column="swing_time" jdbcType="TIMESTAMP"/>
+            <result property="personId" column="person_id" jdbcType="BIGINT"/>
+            <result property="personCode" column="person_code" jdbcType="VARCHAR"/>
+            <result property="personName" column="person_name" jdbcType="VARCHAR"/>
+            <result property="deptName" column="dept_name" jdbcType="VARCHAR"/>
+            <result property="result" column="result" jdbcType="INTEGER"/>
+            <result property="cardNumber" column="card_number" jdbcType="VARCHAR"/>
+            <result property="cardStatus" column="card_status" jdbcType="INTEGER"/>
+            <result property="cardType" column="card_type" jdbcType="INTEGER"/>
+            <result property="channelCode" column="channel_code" jdbcType="VARCHAR"/>
+            <result property="channelName" column="channel_name" jdbcType="VARCHAR"/>
+            <result property="deviceCode" column="device_code" jdbcType="VARCHAR"/>
+            <result property="deviceName" column="device_name" jdbcType="VARCHAR"/>
+            <result property="enterOrExit" column="enter_or_exit" jdbcType="INTEGER"/>
+            <result property="imageType" column="image_type" jdbcType="INTEGER"/>
+            <result property="openResult" column="open_result" jdbcType="INTEGER"/>
+            <result property="openType" column="open_type" jdbcType="INTEGER"/>
+            <result property="paperNumber" column="paper_number" jdbcType="VARCHAR"/>
+            <result property="recordImageUrl" column="record_image_url" jdbcType="VARCHAR"/>
+            <result property="recordImage" column="record_image" jdbcType="VARCHAR"/>
+            <result property="remark" column="remark" jdbcType="VARCHAR"/>
+            <result property="maskState" column="mask_state" jdbcType="INTEGER"/>
+            <result property="overTemp" column="over_temp" jdbcType="TINYINT"/>
+            <result property="curTemp" column="cur_temp" jdbcType="DOUBLE"/>
+            <result property="isSync" column="is_sync" jdbcType="INTEGER"/>
+            <result property="enableReport" column="enable_report" jdbcType="BOOLEAN"/>
+            <result property="createUser" column="create_user" jdbcType="INTEGER"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateUser" column="update_user" jdbcType="INTEGER"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,icc_id,swing_time,
+        person_id,person_code,person_name,
+        dept_name,result,card_number,
+        card_status,card_type,channel_code,
+        channel_name,device_code,device_name,
+        enter_or_exit,image_type,open_result,
+        open_type,paper_number,record_image_url,
+        record_image,remark,mask_state,
+        over_temp,cur_temp,is_sync,enable_report,
+        create_user,create_time,update_user,
+        update_time
+    </sql>
+    <select id="selectIccIdList" resultType="java.lang.Long">
+        select icc_id from staff_attendance_tracking_record where icc_id!='' and icc_id is not null
+    </select>
+</mapper>
diff --git a/performance-server/src/main/java/com/ruoyi/performance/dto/PerformanceShiftMapDto.java b/performance-server/src/main/java/com/ruoyi/performance/dto/PerformanceShiftMapDto.java
index 9a1fc71..adf7a1b 100644
--- a/performance-server/src/main/java/com/ruoyi/performance/dto/PerformanceShiftMapDto.java
+++ b/performance-server/src/main/java/com/ruoyi/performance/dto/PerformanceShiftMapDto.java
@@ -12,6 +12,9 @@
 @Data
 public class PerformanceShiftMapDto extends PerformanceShift {
 
+    @ApiModelProperty("鐢ㄦ埛缂栧彿")
+    private String personCode;
+
     @ApiModelProperty("鐢ㄦ埛鍚嶇О")
     private String userName;
 
@@ -35,4 +38,11 @@
 
     @ApiModelProperty("鏃ユ湡琛ㄥご鍒楄〃")
     private List<Map<Object, Object>> headerList = new ArrayList<>();
+
+    @ApiModelProperty("鐝寮�濮嬫椂闂�")
+    private String startTime;
+
+    @ApiModelProperty("鐝缁撴潫鏃堕棿")
+    private String endTime;
+
 }
diff --git a/performance-server/src/main/java/com/ruoyi/performance/mapper/PerformanceShiftMapper.java b/performance-server/src/main/java/com/ruoyi/performance/mapper/PerformanceShiftMapper.java
index 9b3bfda..69c6bf5 100644
--- a/performance-server/src/main/java/com/ruoyi/performance/mapper/PerformanceShiftMapper.java
+++ b/performance-server/src/main/java/com/ruoyi/performance/mapper/PerformanceShiftMapper.java
@@ -5,9 +5,11 @@
 import com.ruoyi.framework.mybatis_config.MyBaseMapper;
 import com.ruoyi.performance.dto.PerformanceShiftMapDto;
 import com.ruoyi.performance.pojo.PerformanceShift;
+import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
 
@@ -19,6 +21,7 @@
  * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
  * @since 2024-05-08 09:12:04
  */
+@Mapper
 public interface PerformanceShiftMapper extends MyBaseMapper<PerformanceShift> {
 
     List<PerformanceShiftMapDto> performanceShift(
@@ -39,4 +42,7 @@
     List<PerformanceShiftMapDto> performanceShiftList(@Param("time") String time, @Param("userName") String userName, @Param("laboratory") String laboratory);
 
     String seldepLimsId(@Param("depLimsId") int depLimsId);
+
+    List<PerformanceShiftMapDto> selectListByWorkTime(@Param("startTime") LocalDateTime startTime,@Param("endTime") LocalDateTime endTime,@Param("keyword") String keyword);
+
 }
diff --git a/performance-server/src/main/java/com/ruoyi/performance/mapper/ShiftTimeMapper.java b/performance-server/src/main/java/com/ruoyi/performance/mapper/ShiftTimeMapper.java
index 192e8ee..8f5ecaa 100644
--- a/performance-server/src/main/java/com/ruoyi/performance/mapper/ShiftTimeMapper.java
+++ b/performance-server/src/main/java/com/ruoyi/performance/mapper/ShiftTimeMapper.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.performance.pojo.ShiftTime;
+import org.apache.ibatis.annotations.Mapper;
 
 /**
  * <p>
@@ -11,6 +12,7 @@
  * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
  * @since 2024-07-24 11:22:17
  */
+@Mapper
 public interface ShiftTimeMapper extends BaseMapper<ShiftTime> {
 
 }
diff --git a/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml b/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml
index 1388484..381ef69 100644
--- a/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml
+++ b/performance-server/src/main/resources/mapper/PerformanceShiftMapper.xml
@@ -145,4 +145,27 @@
         from department_lims
         where id = #{depLimsId}
     </select>
+    <select id="selectListByWorkTime" resultType="com.ruoyi.performance.dto.PerformanceShiftMapDto">
+        SELECT
+            ps.id,
+            ps.shift,
+            ps.work_time,
+            ps.user_id,
+            u.name AS user_name,
+            u.account AS person_code,
+            st.start_time,
+            st.end_time
+        FROM performance_shift ps
+        LEFT JOIN user u ON ps.user_id = u.id
+        LEFT JOIN shift_time st ON ps.shift = st.shift
+        <where>
+            <if test="startTime!=null and endTime!=null">
+                AND ps.work_time BETWEEN #{startTime} AND #{endTime}
+            </if>
+            <if test="keyword!='' and keyword!=null">
+                AND (u.account like concat('%',#{keyword},'%') OR u.name like concat('%',#{keyword},'%'))
+            </if>
+        </where>
+        ORDER BY ps.work_time
+    </select>
 </mapper>
diff --git a/pom.xml b/pom.xml
index 73d75f4..1651658 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,7 +51,6 @@
     <!-- 渚濊禆澹版槑 -->
     <dependencyManagement>
         <dependencies>
-
             <!-- 瑕嗙洊SpringFramework鐨勪緷璧栭厤缃�-->
             <dependency>
                 <groupId>org.springframework</groupId>
@@ -314,7 +313,12 @@
             <artifactId>lombok</artifactId>
             <scope>provided</scope>
         </dependency>
-
+        <!-- 瀵规帴ICC骞冲彴-->
+        <dependency>
+            <groupId>com.dahuatech.icc</groupId>
+            <artifactId>java-sdk-oauth</artifactId>
+            <version>1.0.13.10</version>
+        </dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>easyexcel</artifactId>
diff --git a/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
index 56bb00f..1744cd3 100644
--- a/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
+++ b/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
@@ -120,8 +120,8 @@
     /**
      * 鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
      */
-    @GetMapping("/optionselect")
-    public AjaxResult optionselect()
+    @GetMapping("/optionSelect")
+    public AjaxResult optionSelect()
     {
         List<SysPost> posts = postService.selectPostAll();
         return success(posts);
diff --git a/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/UserController.java b/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/UserController.java
index f8756bd..66e322a 100644
--- a/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/UserController.java
+++ b/ruoyi-admin-ztns/src/main/java/com/ruoyi/web/controller/system/UserController.java
@@ -1,6 +1,7 @@
 package com.ruoyi.web.controller.system;
 
 
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.core.domain.Result;
 import com.ruoyi.common.core.domain.entity.User;
@@ -70,6 +71,11 @@
         return Result.success(userService.delUserDepardLimsId(id));
     }
 
+    @ApiOperation(value = "鏌ヨ鎵�鏈夌敤鎴峰垪琛�")
+    @GetMapping("/selectAllUser")
+    public Result selectAllUser(){
+        return Result.success(userService.list(Wrappers.<User>lambdaQuery().eq(User::getStatus,0)));
+    }
 
 }
 
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Custom.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Custom.java
index 97d05ba..1cb0c13 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Custom.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Custom.java
@@ -2,6 +2,8 @@
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -20,6 +22,7 @@
 
     @ApiModelProperty(value = "涓婚敭")
     @TableId(type = IdType.AUTO)
+    @JsonSerialize(using = ToStringSerializer.class)
     private Long id;
 
     @ApiModelProperty(value = "瀹㈡埛鍚嶇О")
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/ClockInState.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/ClockInState.java
new file mode 100644
index 0000000..9b1891b
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/ClockInState.java
@@ -0,0 +1,22 @@
+package com.ruoyi.common.enums;
+
+import lombok.Getter;
+
+/**
+ * ICC瀵规帴锛氭墦鍗$姸鎬佹灇涓�
+ */
+@Getter
+public enum ClockInState {
+
+    NORMAL("姝e父",1),
+    ABNORMAL("涓嶆甯�",0);
+
+    private String desc;
+
+    private Integer value;
+
+    ClockInState(String desc, Integer value) {
+        this.desc = desc;
+        this.value = value;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/EnterOrExitType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/EnterOrExitType.java
new file mode 100644
index 0000000..69955c6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/EnterOrExitType.java
@@ -0,0 +1,26 @@
+package com.ruoyi.common.enums;
+
+import lombok.Getter;
+
+/**
+ * ICC骞冲彴瀵规帴锛氳繘鍑洪棬绫诲瀷鏋氫妇
+ */
+@Getter
+public enum EnterOrExitType {
+
+    ENTER("杩涢棬",1),
+    EXIT("鍑洪棬",2),
+    ENTER_OR_EXIT("杩�/鍑洪棬",3);
+
+    private String desc;
+
+    private Integer value;
+
+    EnterOrExitType(String desc, Integer value) {
+        this.desc = desc;
+        this.value = value;
+    }
+
+
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/SyncStatus.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/SyncStatus.java
new file mode 100644
index 0000000..9047ca4
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/SyncStatus.java
@@ -0,0 +1,19 @@
+package com.ruoyi.common.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum SyncStatus {
+
+    SYNC("鍚屾",0),
+    INERT("鎵嬪姩鏂板",1);
+
+    private String desc;
+
+    private Integer value;
+
+    SyncStatus(String desc, Integer value) {
+        this.desc = desc;
+        this.value = value;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/IfsApiUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/IfsApiUtils.java
index 1f4e78f..f0a6bf7 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/IfsApiUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/IfsApiUtils.java
@@ -17,6 +17,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * @Author zhuo
@@ -47,9 +48,10 @@
             ObjectMapper objectMapper = new ObjectMapper();
             try {
                 Map map = objectMapper.readValue(body, Map.class);
-                maps.addAll(objectMapper.readValue(JSONUtil.toJsonStr(map.get("LIST_INFO")), new TypeReference<List<Map<String, Object>>>() {
-                }));
-                log.info("鑾峰彇閲囪喘璁㈠崟-->>" + maps);
+                if(Objects.nonNull(map.get("SuccessFlag")) && map.get("SuccessFlag").equals("1")){
+                    maps.addAll(objectMapper.readValue(JSONUtil.toJsonStr(map.get("LIST_INFO")), new TypeReference<List<Map<String, Object>>>() {}));
+                    log.info("鍚屾鐨勯噰璐鍗曟暟閲�-->>,{}" , maps.size());
+                }
             } catch (JsonProcessingException e) {
                 e.printStackTrace();
                 throw new RuntimeException(e);
@@ -108,7 +110,7 @@
      * @return
      */
     public Result importPartLotAttr(String contract,String inAttr) {
-        return getResult(contract,"IMPORT_PART_LOT_ATTR_STD", inAttr, "POST", "搴撳瓨鐗╂枡鎵规灞炴�ф柊澧炰慨鏀规帴鍙�-->");
+        return getResult(contract,"IMPORT_PART_LOT_ATTR_STD", inAttr, "GET", "搴撳瓨鐗╂枡鎵规灞炴�ф柊澧炰慨鏀规帴鍙�-->");
     }
 
     /**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/IccApiUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/IccApiUtil.java
new file mode 100644
index 0000000..054ba38
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/IccApiUtil.java
@@ -0,0 +1,40 @@
+package com.ruoyi.common.utils.api.icc;
+
+import com.dahuatech.hutool.http.Method;
+import com.dahuatech.icc.exception.ClientException;
+import com.dahuatech.icc.oauth.model.v202010.OauthConfigUserPwdInfo;
+import com.dahuatech.icc.oauth.utils.HttpUtils;
+import com.ruoyi.common.utils.api.icc.config.OauthConfigUtil;
+import com.ruoyi.common.utils.api.icc.model.GetResultPageRequest;
+import com.ruoyi.common.utils.api.icc.model.GetResultPageResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 瀵规帴ICC寮�鏀惧钩鍙板伐鍏�
+ */
+@Slf4j
+@Component
+public class IccApiUtil {
+
+    /**
+     * 鍒嗛〉鑾峰彇闂ㄧ杩涘嚭缁撴灉
+     * @param getResultPageRequest
+     * @return
+     * @throws ClientException
+     */
+    public GetResultPageResponse getAttendanceResultPage(GetResultPageRequest getResultPageRequest) {
+        OauthConfigUserPwdInfo config = OauthConfigUtil.getOauthConfig();
+        GetResultPageResponse response=null;
+        try {
+            response = HttpUtils.executeJson("/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/swingCardRecord/bycondition/combined", getResultPageRequest,null, Method.POST , config, GetResultPageResponse.class);
+        } catch (ClientException e) {
+            log.error(e.getErrMsg(), e);
+        }
+        if(!response.isSuccess()) {
+            log.info("鍒嗛〉鑾峰彇闂ㄧ杩涘嚭澶辫触:{}",response.getErrMsg());
+        }
+        return response;
+    }
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/OauthConfigUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/OauthConfigUtil.java
new file mode 100644
index 0000000..dd8c437
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/OauthConfigUtil.java
@@ -0,0 +1,28 @@
+package com.ruoyi.common.utils.api.icc.config;
+
+import com.dahuatech.icc.oauth.model.v202010.OauthConfigUserPwdInfo;
+
+public class OauthConfigUtil {
+
+    /**
+     * 鑾峰彇Oauth閰嶇疆淇℃伅
+     *
+     * @return Oauth閰嶇疆淇℃伅
+     */
+    public static OauthConfigUserPwdInfo getOauthConfig() {
+        PlatformConfig platformConfig = new PlatformConfig();//璇诲彇閰嶇疆
+        OauthConfigUserPwdInfo oauthConfigUserPwdInfo = new OauthConfigUserPwdInfo(
+                platformConfig.getHost(),
+                platformConfig.getClientId(),
+                platformConfig.getClientSecret(),
+                platformConfig.getUsername(),
+                platformConfig.getPassword(),
+                false,
+                platformConfig.getHttpsPort(),
+                platformConfig.getHttpPort()
+        );
+        oauthConfigUserPwdInfo.getHttpConfigInfo().setReadTimeout(platformConfig.getReadTimeout());
+        oauthConfigUserPwdInfo.getHttpConfigInfo().setConnectionTimeout(platformConfig.getConnectionTimeout());
+        return oauthConfigUserPwdInfo;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/PlatformConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/PlatformConfig.java
new file mode 100644
index 0000000..a45ef5e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/config/PlatformConfig.java
@@ -0,0 +1,20 @@
+package com.ruoyi.common.utils.api.icc.config;
+
+import lombok.Getter;
+
+/**
+ * 骞冲彴淇℃伅閰嶇疆
+ */
+@Getter
+public class PlatformConfig {
+
+    private final String clientId = "NS-LIMS";//鍑瘉ID鑷畾涔夛紝閰嶅悎鐢宠鍑瘉娴佺▼鐢宠
+    private final String clientSecret = "3ca893c4-bfda-4d33-bd73-1eb5f3a68df1";//鍑瘉瀵嗛挜锛屽弬鑰冩鍦板潃鐢宠https://open-icc.dahuatech.com/iccdoc/enterprisebase/5.0.15/wiki/common/quickstart.html#%E7%94%B3%E8%AF%B7OpenAPI%E7%94%A8%E6%88%B7
+    private final String username = "NS-LIMS";//骞冲彴鐧诲綍鐢ㄦ埛鍚�
+    private final String password = "zttZTT123!";//骞冲彴鐧诲綍瀵嗙爜
+    private final String host = "10.100.23.241";//骞冲彴IP锛岃仈璋冪幆澧僆P
+    private final String httpsPort = "443";//https榛樿绔彛鏄�443锛岃仈璋冪幆澧�443鏄犲皠澶栫綉绔彛涓�4077
+    private final String httpPort = "83";//http榛樿绔彛鏄�83锛屼絾涓嶅紑鍚紝锛岃仈璋冪幆澧�83鏄犲皠澶栫綉绔彛涓�4078锛涢渶杩愮淮涓績寮�鍚痟ttp璋冭瘯妯″紡鍚庢墠鏀寔锛沬sEnableHttpTest=true鏃舵湁鏁堬紝
+    private final Long connectionTimeout = -1L;//杩炴帴瓒呮椂
+    private final Long readTimeout = -1L;//璇诲彇瓒呮椂
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageRequest.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageRequest.java
new file mode 100644
index 0000000..17595f1
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageRequest.java
@@ -0,0 +1,68 @@
+package com.ruoyi.common.utils.api.icc.model;
+
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * program:java-sdk-demo
+ *
+ * @Author: 355079
+ * @Date:2024-04-29 13:48
+ * @Description: 鍒嗛〉鑾峰彇鑰冨嫟缁撴灉璇锋眰鍙傛暟
+ */
+@Data
+public class GetResultPageRequest {
+    /** 绗嚑椤� */
+    @NotNull
+    private Integer pageNum;
+    /** 姣忛〉鏉℃暟 */
+    @NotNull
+    private Integer pageSize;
+    /** 寮�濮嬫椂闂�(yyyy-MM-dd) */
+    @NotNull
+    private String startSwingTime;
+    /** 缁撴潫鏃堕棿(yyyy-MM-dd) */
+    @NotNull
+    private String endSwingTime;
+    /** 鍏ュ簱寮�濮嬫椂闂达紝鏍煎紡锛歽yyy-MM-dd HH:mm:ss锛孷1.1.4鏂板 */
+    private String startCreateTime;
+    /** 鍏ュ簱缁撴潫鏃堕棿锛屾牸寮忥細yyyy-MM-dd HH:mm:ss锛孷1.1.4鏂板 鎺ㄨ崘鍙栧綋鍓嶆椂闂村噺5鍒嗛挓鎴栨洿闀挎椂闂达紝鍥犱负瀛樺湪瀹㈡埛鏈嶅姟鍣ㄦ椂闂存瘮icc鏈嶅姟鍣ㄦ椂闂村揩锛屾煡璇㈡椂鏈夋柊鏁版嵁杩涘叆瀵艰嚧椤电爜涓庢�绘暟涓嶅噯锛屾暟鎹敊浣� */
+    private String endCreateTime;
+    /** 寮�闂ㄧ被鍨�, 璇﹁ 寮�闂ㄧ被鍨� 瀛楀吀 */
+    private Integer openType;
+    /** 寮�闂ㄧ被鍨嬪閫�, 璇﹁ 寮�闂ㄧ被鍨� 瀛楀吀锛孷1.1.4鏂板 */
+    private List<Integer> openTypes;
+    /** 鍗$墖绫诲瀷, 涓嶄紶-鍏ㄩ儴, 0-IC鍗�, 1-鏈夋簮RFID, 2-CPU鍗� */
+    private String category;
+    /** 浜哄憳鍚嶇О锛屼粎鍏佽姹夊瓧瀛楁瘝鏁板瓧 -_.@ */
+    @Max(value = 64,message = "浜哄憳鍚嶇О鏈�澶ч暱搴﹂檺鍒�64")
+    private String personName;
+    /** 浜哄憳缂栧彿锛屼汉鍛樼紪鍙蜂粎鏀寔瀛楁瘝鎴栨暟瀛� */
+    @Max(value = 64,message = "浜哄憳缂栧彿鏈�澶ч暱搴﹂檺鍒�64")
+    private String personCode;
+    /** 閫氶亾缂栫爜鍒楄〃锛堝彲閫氳繃璁惧绠$悊鎺ュ彛锛岃幏鍙杣nitType涓�7鐨刢hannels锛� */
+    @Max(value = 500,message = "閫氶亾缂栫爜鍒楄〃鏈�澶ч暱搴﹂檺鍒�500")
+    private List<String> channelCodes;
+    /** 閮ㄩ棬ID, 閮ㄩ棬闂�", "鍒嗛殧 */
+    private String deptIds;
+    /** 鍗″彿锛屽瓧姣嶆垨鏁板瓧 */
+    @Max(value = 64,message = "鍗″彿鏈�澶ч暱搴﹂檺鍒�64")
+    private String cardNumber;
+    /** 浜嬩欢绫诲瀷, 涓嶄紶-鍏ㄩ儴, 1-杩涢棬, 2鍑洪棬, 3-杩�/鍑洪棬 */
+    private Integer enterOrExit;
+    /** 寮�闂ㄧ粨鏋�, 涓嶄紶-鍏ㄩ儴, 1-鎴愬姛, 0-澶辫触 */
+    private Integer openResult;
+    /** 鏄惁瓒呮俯 */
+    private Boolean overTemp;
+    /** 浣撴俯浣庨檺 */
+    private Double curTempStart;
+    /** 浣撴俯楂橀檺 */
+    private Double curTempEnd;
+    /** 鍙g僵鐘舵�� 3-甯﹀彛缃�,2鈥旀病甯﹀彛缃�,1-鏈瘑鍒� */
+    private Integer maskState;
+    /** 璁垮绛涢�夛紝1 - 鍙煡璇㈣瀹㈣褰� 2 - 鍙煡璇㈤潪璁垮璁板綍 */
+    private Integer visitorFilter;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageResponse.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageResponse.java
new file mode 100644
index 0000000..d8ca2d6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/api/icc/model/GetResultPageResponse.java
@@ -0,0 +1,89 @@
+package com.ruoyi.common.utils.api.icc.model;
+
+import com.dahuatech.icc.oauth.http.IccResponse;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * program:java-sdk-demo
+ *
+ * @Author: 355079
+ * @Date:2024-04-29 14:21
+ * @Description: 鍒嗛〉鑾峰彇鑰冨嫟缁撴灉璇锋眰鍙傛暟
+ */
+@Data
+public class GetResultPageResponse extends IccResponse {
+    private Data data;
+    @lombok.Data
+    public static class Data{
+        /** 褰撳墠椤� */
+        private Integer currentPage;
+        /** 姣忛〉鏉℃暟 */
+        private Integer pageSize;
+        /** 鎬婚〉鏁� */
+        private Integer totalPage;
+        /** 鎬绘潯鏁� */
+        private Integer totalRows;
+        /**鏄惁鍚敤浜戞暟鎹簱锛宖alse-涓嶅惎鐢紝true-鍚敤*/
+        private Boolean enableCloudDB;
+        /** 鍒嗛〉鏁版嵁 */
+        private List<PageData> pageData;
+        @lombok.Data
+        public static class PageData{
+            /**涓婚敭id*/
+            private Long id;
+            /** 鍒峰崱鏃堕棿锛屾牸寮忥細yyyy-MM-dd HH:mm:ss */
+            private String swingTime;
+            /** 浜哄憳ID */
+            private Long personId;
+            /** 浜哄憳缂栧彿 锛岃嫢涓鸿瀹㈤�氳璁板綍锛屽垯鏄瀹㈤绾﹁褰昳d */
+            private String personCode;
+            /** 浜哄憳濮撳悕 */
+            private String personName;
+            /** 閮ㄩ棬鍚嶇О ,涓虹┖鏃朵唬琛ㄨ褰曚负璁垮閫氳璁板綍锛岄潪绌轰唬琛ㄥ唴閮ㄤ汉鍛橀�氳璁板綍 */
+            private String deptName;
+            /** 鍗″彿 */
+            private String cardNumber;
+            /** 鍗$姸鎬侊紝-1-绌虹櫧鍗★紝0-姝e父鍗★紝1-鎸傚け鍗★紝2-娉ㄩ攢鍗� */
+            private Integer cardStatus;
+            /** 鍗$被鍨嬶紝0-IC鍗�, 1-鏈夋簮RFID, 2-CPU鍗� */
+            private Integer cardType;
+            /** 閫氶亾缂栫爜 */
+            private String channelCode;
+            /** 閫氶亾鍚嶇О */
+            private String channelName;
+
+            /** 璁惧缂栫爜 */
+            private String deviceCode;
+            /** 璁惧鍚嶇О */
+            private String deviceName;
+            /** 杩涘嚭闂ㄧ被鍨嬶紝1-杩涢棬, 2鍑洪棬, 3-杩�/鍑洪棬 */
+            private Integer enterOrExit;
+            /** 1-鍐呴儴浜哄憳, 2-璁垮锛氬唴閮ㄤ汉鍛樻槸鍦ㄤ汉鍛樼鐞嗕腑娣诲姞鐨勪汉鍛橈紝璁垮鏄湪璁垮瀛愮郴缁熶腑褰曞叆鐨勮瀹� */
+            private Integer imageType;
+            /** 寮�闂ㄧ粨鏋滐紝0-澶辫触锛�1-鎴愬姛 */
+            private Integer openResult;
+            /** 寮�闂ㄧ被鍨嬶紝璇﹁ 寮�闂ㄧ被鍨� 瀛楀吀 */
+            private Integer openType;
+            /** 璇佷欢鍙风爜锛屼細杩涜鑴辨晱澶勭悊 */
+            private String paperNumber;
+
+            /** 鎶撳浘锛岀浉瀵硅矾寰勶紝瀹屾暣璁块棶璺緞鍙傝�僌SS鏂瑰紡缁勮 */
+            private String recordImageUrl;
+            /** 鎶撳浘锛岀粷瀵硅矾寰勶紝鍏煎鍘嗗彶鐗堟湰锛屼笉鎺ㄨ崘浣跨敤 */
+            private String recordImage;
+            /** 寮�闂ㄥけ璐ュ師鍥� */
+            private String remark;
+
+            /** 鍏ュ簱鏃堕棿锛屾牸寮忥細yyyy-MM-dd HH:mm:ss */
+            private String createTime;
+            /** 鍙g僵鐘舵��(3-甯﹀彛缃�,2鈥旀病甯﹀彛缃�,1-鏈瘑鍒�) */
+            private Integer maskState;
+            /** 鏄惁瓒呮俯 */
+            private Boolean overTemp;
+            /** 浣撴俯 */
+            private Double curTemp;
+        }
+    }
+}

--
Gitblit v1.9.3