Explorar o código

补充飞书对接

zhouyy hai 5 meses
pai
achega
5a73c6cf70
Modificáronse 12 ficheiros con 483 adicións e 17 borrados
  1. 18 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FeishuInfoController.java
  2. 47 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockCheckRecord.java
  3. 15 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockData.java
  4. 80 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockTaskRecord.java
  5. 17 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockUserTaskResult.java
  6. 11 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuFlexibleRule.java
  7. 25 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuPunchTimeRule.java
  8. 11 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuRestTimeRule.java
  9. 33 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuShiftResult.java
  10. 24 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/LoadTaskResultBO.java
  11. 4 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/FeishuInfoService.java
  12. 198 11
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java

+ 18 - 6
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FeishuInfoController.java

@@ -1,28 +1,25 @@
 package com.management.platform.controller;
 
 
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.google.gson.JsonObject;
 import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
+import com.management.platform.entity.bo.LoadTaskResultBO;
 import com.management.platform.entity.vo.UserVO;
 import com.management.platform.mapper.*;
 import com.management.platform.service.*;
 import com.management.platform.service.impl.FeishuInfoServiceImpl;
 import com.management.platform.util.*;
-import com.taobao.api.ApiException;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.*;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
-
 import org.springframework.web.client.RestTemplate;
 
 import javax.annotation.Resource;
@@ -32,7 +29,10 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
@@ -93,6 +93,18 @@ public class FeishuInfoController {
     @Resource
     DepartmentOtherManagerService departmentOtherManagerService;
 
+    @PostMapping("/loadTaskResult")
+    public HttpRespMsg loadTaskResult(@RequestBody @Validated LoadTaskResultBO queryBO,HttpServletRequest request){
+        HttpRespMsg msg = new HttpRespMsg();
+        try {
+            msg = feishuInfoService.loadTaskResult(queryBO,request);
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError(MessageUtils.message("other.error"));
+            return msg;
+        }
+        return msg;
+    }
 
     /**
      * 初始化内部应用的系统数据

+ 47 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockCheckRecord.java

@@ -0,0 +1,47 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+@Data
+public class FeishuClockCheckRecord {
+    /**用户 ID,对应employee_type*/
+    private String user_id;
+    /**记录创建者 ID,对应employee_type*/
+    private String creator_id;
+    /**打卡位置名称信息*/
+    private String location_name;
+    /**打卡时间,精确到秒的时间戳*/
+    private String check_time;
+    /**打卡备注*/
+    private String comment;
+    /**考勤内部的打卡记录ID(导入时此参数无效)*/
+    private String record_id;
+    /**打卡 Wi-Fi 的 SSID*/
+    private String ssid;
+    /**打卡 Wi-Fi 的 MAC 地址*/
+    private String bssid;
+    /**是否为外勤打卡*/
+    private boolean is_field;
+    /**是否为 Wi-Fi 打卡*/
+    private boolean is_wifi;
+    /**记录生成方式
+     * 0:用户打卡
+     * 1:管理员修改
+     * 2:用户补卡
+     * 3:系统自动生成
+     * 4:下班免打卡
+     * 5:考勤机
+     * 6:极速打卡
+     * 7:考勤开放平台导入*/
+    private int type;
+    /**打卡照片列表*/
+    private String[] photo_urls;
+    /**打卡设备ID(只支持小程序打卡,导入时无效)*/
+    private String device_id;
+    /**打卡结果。目前仅返回 PendingApproval,表示待生效*/
+    private String check_result;
+    /**用户导入的外部打卡记录ID*/
+    private String external_id;
+    /**唯一幂等键*/
+    private String idempotent_id;
+}

+ 15 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockData.java

@@ -0,0 +1,15 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FeishuClockData {
+    /**打卡任务列表*/
+    private List<FeishuClockUserTaskResult> user_task_results;
+    /**无效用户 ID 列表,对应employee_type*/
+    private String[] invalid_user_ids;
+    /**没有权限用户 ID 列表,对应employee_type*/
+    private String[] unauthorized_user_ids;
+}

+ 80 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockTaskRecord.java

@@ -0,0 +1,80 @@
+package com.management.platform.entity.bo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+public class FeishuClockTaskRecord {
+    /**上班打卡记录 ID*/
+    private String check_in_record_id;
+    /**上班打卡记录*/
+    private FeishuClockCheckRecord check_in_record;
+    /**下班打卡记录 ID*/
+    private String check_out_record_id;
+    /**下班打卡记录*/
+    private FeishuClockCheckRecord check_out_record;
+    /**上班打卡结果
+     * NoNeedCheck:无需打卡
+     * SystemCheck:系统打卡(已弃用)
+     * Normal:正常
+     * Early:早退
+     * Late:迟到
+     * Lack:缺卡
+     * Todo:未打卡*/
+    private String check_in_result;
+    /**下班打卡结果
+     * NoNeedCheck:无需打卡
+     * SystemCheck:系统打卡(已弃用)
+     * Normal:正常
+     * Early:早退
+     * Late:迟到
+     * Lack:缺卡
+     * Todo:未打卡*/
+    private String check_out_result;
+    /**上班打卡结果补充
+     None:无
+     ManagerModification:管理员修改
+     CardReplacement:补卡通过
+     ShiftChange:换班
+     Travel:出差
+     Leave:请假
+     GoOut:外出
+     CardReplacementApplication:补卡申请中
+     FieldPunch:外勤打卡*/
+    private String check_in_result_supplement;
+    /**下班打卡结果补充
+     None:无
+     ManagerModification:管理员修改
+     CardReplacement:补卡通过
+     ShiftChange:换班
+     Travel:出差
+     Leave:请假
+     GoOut:外出
+     CardReplacementApplication:补卡申请中
+     FieldPunch:外勤打卡*/
+    private String check_out_result_supplement;
+    /**上班打卡时间,秒级时间戳*/
+    private String check_in_shift_time;
+    /**下班打卡时间,秒级时间戳*/
+    private String check_out_shift_time;
+    /**班次类型,0正常,1加班班次*/
+    private int task_shift_type;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" ,timezone="GMT+8")
+    private Date checkInShiftDateTime;
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
+    private Date checkOutShiftDateTime;
+
+    public void setDateTime() {
+        Long l1 = Long.valueOf(this.check_in_shift_time) * 1000L;
+        Long l2 = Long.valueOf(this.check_out_shift_time) * 1000L;
+        this.checkInShiftDateTime = new Date(l1);
+        this.checkOutShiftDateTime = new Date(l2);
+    }
+
+}

+ 17 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuClockUserTaskResult.java

@@ -0,0 +1,17 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FeishuClockUserTaskResult {
+    private String result_id;
+    private String user_id;
+    private String employee_name;
+    private int day;
+    private String group_id;
+    private String shift_id;
+    private List<FeishuClockTaskRecord> records;
+
+}

+ 11 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuFlexibleRule.java

@@ -0,0 +1,11 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+@Data
+public class FeishuFlexibleRule {
+    /**下班最多可早走,单位:分钟(上班早到几分钟,下班可早走几分钟)*/
+    private int flexible_early_minutes;
+    /**上班最多可晚到,单位:分钟(上班晚到几分钟,下班须晚走几分钟)*/
+    private int flexible_late_minutes;
+}

+ 25 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuPunchTimeRule.java

@@ -0,0 +1,25 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+@Data
+public class FeishuPunchTimeRule {
+    /**上班时间,格式为hh:mm*/
+    private String on_time;
+    /**下班时间,格式为hh:mm。如果是第二天凌晨2点, 则为26:00*/
+    private String off_time;
+//    /**晚到多久记为迟到,单位:分钟*/
+//    private int late_minutes_as_late;
+    /**晚到多久记为缺卡,单位:分钟*/
+    private int late_minutes_as_lack;
+//    /**最早多久可打上班卡,单位:分钟*/
+//    private int on_advance_minutes;
+//    /**早退多久记为早退,单位:分钟*/
+//    private int early_minutes_as_early;
+    /**早退多久记为缺卡,单位:分钟*/
+    private int early_minutes_as_lack;
+//    /**最晚多久可打下班卡,单位:分钟*/
+//    private int off_delay_minutes;
+//    /**晚到多久记为严重迟到,单位:分钟*/
+//    private int late_minutes_as_serious_late;
+}

+ 11 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuRestTimeRule.java

@@ -0,0 +1,11 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+@Data
+public class FeishuRestTimeRule {
+    /**休息开始,格式为mm:ss*/
+    private String rest_begin_time;
+    /**休息结束,格式为mm:ss*/
+    private String rest_end_time;
+}

+ 33 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/FeishuShiftResult.java

@@ -0,0 +1,33 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FeishuShiftResult {
+    /**班次ID*/
+    private String shift_id;
+    /**班次名称*/
+    private String shift_name;
+    /**打卡次数*/
+    private int punch_times;
+    /**是否弹性打卡*/
+    private boolean is_flexible;
+    /**弹性打卡时间,单位:分钟,设置【上班最多可晚到】与【下班最多可早走】时间,如果不设置flexible_rule则生效*/
+    private Integer flexible_minutes;
+    /**班次ID*/
+    private List<FeishuFlexibleRule> flexible_rule;
+    /**不需要打下班卡*/
+    private boolean no_need_off;
+    /**班次ID*/
+    private List<FeishuPunchTimeRule> punch_time_rule;
+//    /**晚走晚到规则(仅飞书人事企业版可用)*/
+//    private String late_off_late_on_rule;
+    /**休息规则*/
+    private List<FeishuRestTimeRule> rest_time_rule;
+//    /**加班规则(仅飞书人事企业版可用)*/
+//    private String overtime_rule;
+//    /**是否允许在非打卡时段申请打卡*/
+//    private boolean allow_punch_approval;
+}

+ 24 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/bo/LoadTaskResultBO.java

@@ -0,0 +1,24 @@
+package com.management.platform.entity.bo;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+@Data
+public class LoadTaskResultBO {
+    @NotBlank(message = "appId不能为空")
+    private String appId;
+    /**employee_no 或 employee_id 列表,长度不超过 50*/
+    @Size(min = 1, max = 50,message = "工号数组大小有误")
+    private String[] userIds;
+    /**工时管家用户id*/
+//    @Size(min = 1,max = 50,message = "用户id数组大小有误")
+    private String[] wtUserIds;
+    /**查询的起始工作日,格式为yyyyMMdd*/
+    private Integer checkDateFrom;
+    /**查询的结束工作日,格式为yyyyMMdd*/
+    private Integer checkDateTo;
+    /**是否需要加班班段打卡结果*/
+    private Boolean needOverTimeResult = false;
+}

+ 4 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/FeishuInfoService.java

@@ -4,8 +4,10 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.management.platform.entity.FeishuInfo;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.entity.bo.LoadTaskResultBO;
 import com.management.platform.util.HttpRespMsg;
 
+import javax.servlet.http.HttpServletRequest;
 import java.util.List;
 import java.util.Map;
 
@@ -39,4 +41,6 @@ public interface FeishuInfoService extends IService<FeishuInfo> {
     void batchSendCardMessage(FeishuInfo feishuInfo, List<String> userIds, String sendTypeName, Map<String, String> templateVariableDetail, String pushUrl) throws Exception;
 
     HttpRespMsg initSuperManager(String corpid, String name);
+
+    HttpRespMsg loadTaskResult(LoadTaskResultBO queryBO, HttpServletRequest request);
 }

+ 198 - 11
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java

@@ -1,37 +1,39 @@
 package com.management.platform.service.impl;
 
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.google.gson.JsonObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
+import com.management.platform.entity.bo.*;
 import com.management.platform.mapper.FeishuInfoMapper;
 import com.management.platform.mapper.FeishuSendMapper;
 import com.management.platform.mapper.SysRoleMapper;
 import com.management.platform.mapper.UserMapper;
-import com.management.platform.service.DepartmentOtherManagerService;
 import com.management.platform.service.FeishuInfoService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.MD5Util;
 import com.management.platform.util.MessageUtils;
-import com.management.platform.util.UserAgentUtils;
-import org.apache.http.client.methods.HttpGet;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.*;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.client.RestTemplate;
-import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.view.RedirectView;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -63,6 +65,12 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
         public static final String BATCH_SEND_MESSAGE="https://open.feishu.cn/open-apis/message/v4/batch_send/";
         /*获取单个用户信息*/
         public static final String GET_USER_INFO="https://open.feishu.cn/open-apis/contact/v3/users/:user_id";
+        /**获取多用户打卡结果*/
+        public static final String GET_USERS_CLOCK_RES="https://open.feishu.cn/open-apis/attendance/v1/user_tasks/query";
+        /**获取多用户审批结果*/
+        public static final String GET_USERS_APPROVE_RES = "https://open.feishu.cn/open-apis/attendance/v1/user_approvals/query";
+
+        public static final String GET_USERS_SHIFT_RES = "https://open.feishu.cn/open-apis/attendance/v1/shifts/";
 
 
         @Resource
@@ -74,6 +82,9 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
         @Resource
         SysRoleMapper sysRoleMapper;
 
+        @Autowired
+        private RestTemplate restTemplate;
+
         @Override
         public String getAppAccessToken(FeishuInfo feishuInfo) {
                 String result="";
@@ -482,4 +493,180 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
                 return msg;
         }
 
+        @Override
+        public HttpRespMsg loadTaskResult(LoadTaskResultBO queryBO, HttpServletRequest request) {
+                HttpRespMsg msg = new HttpRespMsg();
+//                User user = userMapper.selectById(request.getHeader("TOKEN"));
+//                if(null == user){
+//                        msg.setError("token有误,用户不存在");
+//                        return msg;
+//                }
+//                Integer companyId = user.getCompanyId();
+
+                LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
+                lqw.select(User::getId,User::getJobNumber).isNotNull(User::getJobNumber)
+                        .in(User::getId,Arrays.asList(queryBO.getWtUserIds()));
+                List<User> users = userMapper.selectList(lqw);
+                if(CollectionUtils.isEmpty(users)){
+                        msg.setError("未查询到飞书工号");
+                        return msg;
+                }
+                Map<String, String> jobNumIdMap = users.stream().collect(Collectors.toMap(User::getJobNumber, User::getId));
+                String[] feishuUserIdArr = users.stream().map(User::getJobNumber).toArray(String[]::new);
+                queryBO.setUserIds(feishuUserIdArr);
+
+                FeishuClockData feishuClockData = getFeishuClockData(queryBO);
+                if(null == feishuClockData){
+                        msg.setError("飞书获取用户考勤数据失败,请联系管理员");
+                        return msg;
+                }
+                for (FeishuClockUserTaskResult userTaskResult : feishuClockData.getUser_task_results()) {
+                        for (FeishuClockTaskRecord record : userTaskResult.getRecords()) {
+                                record.setDateTime();
+                        }
+                }
+//                                msg.setData(userTaskResults);
+
+                //用户id、day、考勤组、班次、打卡记录list
+
+                //获取所有班次信息
+                List<String> allShiftList = feishuClockData.getUser_task_results().stream()
+                        .map(FeishuClockUserTaskResult::getShift_id)
+                        .distinct().collect(Collectors.toList());
+                //获取所有班次对应的上下班、弹性、休息时间
+                Map<String,FeishuShiftResult> shiftResultMap = new HashMap<>(allShiftList.size());
+                for (String shiftId : allShiftList) {
+                        FeishuShiftResult shiftResult = getFeishuShiftResult(queryBO.getAppId(), shiftId);
+                        if(null != shiftResult){
+                                shiftResultMap.put(shiftId,shiftResult);
+                        }
+                }
+
+                List<Map<String,Object>> res = new ArrayList();
+                SimpleDateFormat HMFormat = new SimpleDateFormat("HH:mm");
+                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                for (FeishuClockUserTaskResult userTaskResult : feishuClockData.getUser_task_results()) {
+                        int day = userTaskResult.getDay();//日期 yyyyMMdd
+                        String dayStr = String.valueOf(day).substring(0,4)+"-"+String.valueOf(day).substring(4,6)+"-"+String.valueOf(day).substring(6,7);
+                        //获取正常上班时间段
+                        Optional<FeishuClockTaskRecord> first = userTaskResult.getRecords().stream()
+                                .filter(t -> 0 == t.getTask_shift_type())
+                                .findFirst();
+                        if(first.isPresent()){
+                                Map<String,Object> map = new HashMap<>();
+                                FeishuClockTaskRecord record = first.get();
+                                UserFvTime userFvTime = new UserFvTime();
+                                //计算时长 需考虑考勤--待处理
+
+                                FeishuShiftResult shiftResult = shiftResultMap.get(userTaskResult.getShift_id());
+                                //判断弹性上下班
+                                Integer flexibleMinutes = null;
+                                if(shiftResult.is_flexible()){
+                                        //可以弹性上下班
+                                        flexibleMinutes = shiftResult.getFlexible_minutes();
+                                        if(null == flexibleMinutes || 0 == flexibleMinutes){
+                                                //从规则中获取
+                                                if(CollectionUtils.isNotEmpty(shiftResult.getFlexible_rule())){
+                                                        //此处仅获取第一个作为规则
+                                                        flexibleMinutes = shiftResult.getFlexible_rule().get(0).getFlexible_early_minutes();
+                                                }
+                                        }
+
+                                }
+                                flexibleMinutes = null==flexibleMinutes?0:flexibleMinutes;
+                                //获取打卡规则
+                                FeishuPunchTimeRule feishuPunchTimeRule = null;
+                                if(CollectionUtils.isNotEmpty(shiftResult.getPunch_time_rule())){
+                                        //仅获取第一个
+                                        feishuPunchTimeRule  = shiftResult.getPunch_time_rule().get(0);
+                                }
+                                /**
+                                 * 弹性时间 0 非0
+                                 * 0 仅判断是否缺卡
+                                 * 非0 先判断弹性,再判断是否缺卡
+                                 * */
+                                if(null != feishuPunchTimeRule){
+                                        LocalDateTime.parse(feishuPunchTimeRule.getOn_time(),DateTimeFormatter.ofPattern("HH:mm"));
+                                }
+
+
+                                Instant checkInInstant = Instant.ofEpochSecond(Long.parseLong(record.getCheck_in_record().getCheck_time()));
+                                LocalDateTime checkInLocalTime = LocalDateTime.ofInstant(checkInInstant, ZoneId.of("GMT+8"));
+                                Instant checkOutInstant = Instant.ofEpochSecond(Long.parseLong(record.getCheck_out_record().getCheck_time()));
+                                LocalDateTime checkOutLocalTime = LocalDateTime.ofInstant(checkOutInstant, ZoneId.of("GMT+8"));
+
+                                System.out.println("checkInInstant=== "+checkInLocalTime+",checkOutLocalTime=== "+checkOutLocalTime);
+
+
+
+
+                                long secondCost = Long.parseLong(record.getCheck_out_record().getCheck_time())
+                                        -Long.parseLong(record.getCheck_in_record().getCheck_time());
+//                                                long hourCost = BigDecimal.valueOf(secondCost / (60 * 60))
+//                                                        .setScale(0, RoundingMode.UP).longValue();
+                                float hourCost = BigDecimal.valueOf(secondCost / (60 * 60f)).setScale(2, RoundingMode.HALF_UP).floatValue();
+                                userFvTime.setWorkHours(hourCost);
+                                userFvTime.setWorkDate(LocalDate.parse(String.valueOf(userTaskResult.getDay()), DateTimeFormatter.ofPattern("yyyyMMdd")));
+                                //需要关联user表job_number
+                                userFvTime.setUserId(jobNumIdMap.get(userTaskResult.getUser_id()));
+                                Date checkInTime = new Date(Long.parseLong(record.getCheck_in_record().getCheck_time()) * 1000);
+                                Date checkOutTime = new Date(Long.parseLong(record.getCheck_out_record().getCheck_time()) * 1000);
+                                userFvTime.setStartTime(HMFormat.format(checkInTime));
+                                userFvTime.setStartTime(HMFormat.format(checkOutTime));
+
+                                map.put("data",userFvTime);
+                                map.put("startDateTime",format.format(checkInTime));
+                                map.put("endDateTime",format.format(checkOutTime));
+                                res.add(map);
+                        }
+                }
+                msg.setData(res);
+                return msg;
+        }
+
+
+        public FeishuClockData getFeishuClockData(LoadTaskResultBO queryBO){
+                FeishuClockData result = null;
+                HttpHeaders headers = new HttpHeaders();
+                MediaType type = MediaType.parseMediaType("application/json; charset=utf-8");
+                headers.setContentType(type);
+                headers.add("Authorization","Bearer "+getTenantAccessToken(queryBO.getAppId()));
+
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("user_ids",queryBO.getUserIds());
+                jsonObject.put("check_date_from",queryBO.getCheckDateFrom());
+                jsonObject.put("check_date_to",queryBO.getCheckDateTo());
+                jsonObject.put("need_overtime_result",queryBO.getNeedOverTimeResult());
+
+                HttpEntity<JSONObject> httpEntity = new HttpEntity<>(jsonObject, headers);
+
+                ResponseEntity<String> responseEntity = restTemplate.exchange(GET_USERS_CLOCK_RES+"?employee_type=employee_id"
+                        , HttpMethod.POST,httpEntity,String.class);
+                if (responseEntity.getStatusCode() == HttpStatus.OK) {
+                        String resp = responseEntity.getBody();
+                        JSONObject respJson = JSONObject.parseObject(resp);
+                        if (respJson.getInteger("code")==0){
+                                result = JSONObject.toJavaObject(respJson.getJSONObject("data"), FeishuClockData.class);
+                        }
+                }
+                return result;
+        }
+
+        public FeishuShiftResult getFeishuShiftResult(String appId,String shiftId){
+                FeishuShiftResult result = null;
+                HttpHeaders shiftHttpHeader = new HttpHeaders();
+                shiftHttpHeader.add("Authorization","Bearer "+getTenantAccessToken(appId));
+                HttpEntity<JSONObject> shiftEntity = new HttpEntity<>(null, shiftHttpHeader);
+                ResponseEntity<String> tmpResponse = restTemplate.exchange(GET_USERS_SHIFT_RES+shiftId
+                        , HttpMethod.GET,shiftEntity,String.class);
+                if (tmpResponse.getStatusCode() == HttpStatus.OK) {
+                        String tmpResp = tmpResponse.getBody();
+                        JSONObject tmpRespJson = JSONObject.parseObject(tmpResp);
+                        if (tmpRespJson.getInteger("code")==0){
+                                result = JSONObject.toJavaObject(tmpRespJson.getJSONObject("data"), FeishuShiftResult.class);
+                        }
+                }
+                return result;
+        }
+
 }