|
@@ -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;
|
|
|
+ }
|
|
|
+
|
|
|
}
|