钉钉考勤
This commit is contained in:
@@ -62,6 +62,20 @@ public class AttendanceController {
|
||||
public CzgResult<ArrayList<DingAttendanceStatsVO>> getList(
|
||||
@RequestParam(required = false) String name, @RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime) {
|
||||
return CzgResult.success(attendanceService.list(StpKit.USER.getShopId(), name, startTime, endTime));
|
||||
return CzgResult.success(attendanceService.list(StpKit.USER.getShopId(), name, startTime, endTime, null));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户打卡详情
|
||||
* @param userId 返回的userId
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
*/
|
||||
@GetMapping("/detail")
|
||||
public CzgResult<Map<String, Object>> detail(
|
||||
@RequestParam String userId, @RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime, @RequestParam(required = false, defaultValue = "0") Integer weekNum) {
|
||||
return CzgResult.success(attendanceService.detail(StpKit.USER.getShopId(), userId, startTime, endTime, weekNum));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ package com.czg.market.service;
|
||||
import com.czg.market.vo.DingAttendanceStatsVO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
public interface AttendanceService {
|
||||
ArrayList<DingAttendanceStatsVO> list(Long shopId, String name, String startTime, String endTime);
|
||||
ArrayList<DingAttendanceStatsVO> list(Long shopId, String name, String startTime, String endTime, String userId);
|
||||
|
||||
Map<String, Object> detail(Long shopId, String userId, String startTime, String endTime, Integer weekNum);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.czg.market.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -34,6 +35,8 @@ public class DingAttendanceStatsVO {
|
||||
*/
|
||||
private boolean isActive;
|
||||
|
||||
private JSONArray report;
|
||||
|
||||
public void setValByName(String name, String val) {
|
||||
switch (name) {
|
||||
case "出勤天数":
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.czg.service.market.service.impl;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.account.entity.ShopConfig;
|
||||
import com.czg.account.service.ShopConfigService;
|
||||
import com.czg.market.service.AttendanceService;
|
||||
@@ -10,8 +12,13 @@ import com.czg.market.vo.DingAttendanceStatsVO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.DayOfWeek;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
@Service
|
||||
public class AttendanceServiceImpl implements AttendanceService {
|
||||
@@ -21,18 +28,18 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
private ShopConfigService shopConfigService;
|
||||
|
||||
@Override
|
||||
public ArrayList<DingAttendanceStatsVO> list(Long shopId, String name, String startTime, String endTime) {
|
||||
public ArrayList<DingAttendanceStatsVO> list(Long shopId, String name, String startTime, String endTime, String userId) {
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
if (StrUtil.isBlank(startTime)) {
|
||||
start = DateUtil.beginOfMonth(new Date());
|
||||
}else {
|
||||
} else {
|
||||
start = DateUtil.parse(startTime);
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(endTime)) {
|
||||
end = DateUtil.date();
|
||||
}else {
|
||||
} else {
|
||||
end = DateUtil.parse(endTime);
|
||||
}
|
||||
|
||||
@@ -41,6 +48,65 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return dingService.getUserReport(shopId, config.getDingAppKey(), config.getDingAppSecret(), start, end, name);
|
||||
return dingService.getUserReport(shopId, config.getDingAppKey(), config.getDingAppSecret(), start, end, name, userId);
|
||||
}
|
||||
|
||||
// 自定义规则:1-5 → 数字, 6 → 六, 7 → 日
|
||||
private static String formatWeek(String week) {
|
||||
return switch (week) {
|
||||
case "星期一" -> "1";
|
||||
case "星期二" -> "2";
|
||||
case "星期三" -> "3";
|
||||
case "星期四" -> "4";
|
||||
case "星期五" -> "5";
|
||||
case "星期六" -> "六";
|
||||
case "星期日" -> "日";
|
||||
default -> week;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> detail(Long shopId, String userId, String startTime, String endTime, Integer weekNum) {
|
||||
ArrayList<DingAttendanceStatsVO> listed = list(shopId, null, startTime, endTime, userId);
|
||||
|
||||
ArrayList<Map<String, Object>> weekList = new ArrayList<>();
|
||||
DateTime dateTime = DateUtil.parse(endTime);
|
||||
for (int i = 7 * weekNum; i < 7 + 7 * weekNum; i++) {
|
||||
DateTime date = DateUtil.offsetDay(dateTime, i * -1);
|
||||
String week = formatWeek(DateUtil.dayOfWeekEnum(date).toChinese());
|
||||
if (date.compareTo(DateUtil.parseDate(startTime)) < 0) {
|
||||
break;
|
||||
}
|
||||
weekList.add(new HashMap<>(){{
|
||||
put("week", week);
|
||||
put("date", date);
|
||||
}});
|
||||
}
|
||||
|
||||
if (listed.isEmpty()) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("attendanceSummary", null);
|
||||
put("weekList", weekList);
|
||||
put("statusList", null);
|
||||
}};
|
||||
}
|
||||
ShopConfig config = shopConfigService.getById(shopId);
|
||||
if (config == null || StrUtil.isBlank(config.getDingAppSecret())) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("attendanceSummary", null);
|
||||
put("weekList", weekList);
|
||||
put("statusList", null);
|
||||
}};
|
||||
}
|
||||
ConcurrentLinkedDeque<String> statusList = new ConcurrentLinkedDeque<>();
|
||||
weekList.parallelStream().forEach(week -> {
|
||||
statusList.add(dingService.getAttendanceStatus(config.getDingAppKey(), config.getDingAppSecret(), shopId, (Date) week.get("date"), userId));
|
||||
});
|
||||
|
||||
return Map.of(
|
||||
"attendanceSummary", listed.getFirst(),
|
||||
"weekList", weekList,
|
||||
"statusList", statusList
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.market.vo.DingAttendanceStatsVO;
|
||||
import com.czg.market.vo.DingUserVO;
|
||||
@@ -15,6 +16,7 @@ import com.dingtalk.api.request.*;
|
||||
import com.dingtalk.api.response.*;
|
||||
import com.taobao.api.ApiException;
|
||||
import com.taobao.api.TaobaoResponse;
|
||||
import com.taobao.api.internal.util.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -24,10 +26,20 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class DingService {
|
||||
public static final Map<String, String> STATUS_MAP = new HashMap<>(){{
|
||||
put("Normal", "正常");
|
||||
put("Early", "早退");
|
||||
put("Late", "迟到");
|
||||
put("SeriousLate", "严重迟到");
|
||||
put("Absenteeism", "旷工迟到");
|
||||
put("NotSigned", "未打卡");
|
||||
}};
|
||||
|
||||
@Resource
|
||||
private RedisService redisService;
|
||||
|
||||
|
||||
|
||||
public String getToken(String key, String secret, Long shopId) {
|
||||
Object accessToken = redisService.get("ding_access_token:" + shopId);
|
||||
if (accessToken instanceof String && StrUtil.isNotBlank((String) accessToken)) {
|
||||
@@ -53,6 +65,20 @@ public class DingService {
|
||||
return data.getString("access_token");
|
||||
}
|
||||
|
||||
public String getColumIdByName(String key, String secret, Long shopId, String name) {
|
||||
Map<String, String> columns = getColumns(key, secret, shopId);
|
||||
String columId = null;
|
||||
for (Map.Entry<String, String> entry : columns.entrySet()) {
|
||||
String key1 = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
if (value.equals(name)) {
|
||||
columId = key1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return columId;
|
||||
}
|
||||
|
||||
public Map<String, String> getColumns(String key, String secret, Long shopId) {
|
||||
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/getattcolumns");
|
||||
OapiAttendanceGetattcolumnsRequest req = new OapiAttendanceGetattcolumnsRequest();
|
||||
@@ -72,7 +98,7 @@ public class DingService {
|
||||
Map<String, String> columMap = jsonObject.getJSONObject("result").getJSONArray("columns").stream()
|
||||
.filter(item -> {
|
||||
JSONObject item1 = (JSONObject) item;
|
||||
return item1.containsKey("id") && CollUtil.newArrayList("出勤天数", "休息天数", "工作时长", "迟到次数", "迟到时长", "应出勤天数").contains(item1.getString("name"));
|
||||
return item1.containsKey("id") && CollUtil.newArrayList("出勤天数", "休息天数", "工作时长", "迟到次数", "迟到时长", "应出勤天数", "旷工迟到次数").contains(item1.getString("name"));
|
||||
})
|
||||
.collect(Collectors.toMap(item -> ((JSONObject) item).getLong("id").toString(), item -> ((JSONObject) item).getString("name")));
|
||||
|
||||
@@ -125,7 +151,33 @@ public class DingService {
|
||||
return data == null ? null : data.getJSONObject("result");
|
||||
}
|
||||
|
||||
public ArrayList<DingUserVO> getUserList(String name,String key, String secret, Long shopId) {
|
||||
public String getAttendanceStatus(String key, String secret, Long shopId, Date date, String userId) {
|
||||
String status = "";
|
||||
try {
|
||||
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/getupdatedata");
|
||||
OapiAttendanceGetupdatedataRequest req = new OapiAttendanceGetupdatedataRequest();
|
||||
req.setUserid(userId);
|
||||
req.setWorkDate(date);
|
||||
OapiAttendanceGetupdatedataResponse rsp = client.execute(req, getToken(key, secret, shopId));
|
||||
JSONArray resultList = JSONObject.parseObject(rsp.getBody()).getJSONObject("result").getJSONArray("attendance_result_list");
|
||||
if (resultList.isEmpty()) {
|
||||
status = "休息日";
|
||||
}
|
||||
for (Object item : resultList) {
|
||||
JSONObject jsonObject = (JSONObject) item;
|
||||
String timeResult = jsonObject.getString("time_result");
|
||||
if (!"正常".equals(status)) {
|
||||
status = STATUS_MAP.get(timeResult);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
} catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<DingUserVO> getUserList(String name,String key, String secret, Long shopId, String userId) {
|
||||
try {
|
||||
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
|
||||
OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
|
||||
@@ -140,7 +192,17 @@ public class DingService {
|
||||
dingUserVOS.addAll(getUserByDeptId(dptId, key, secret, shopId));
|
||||
}
|
||||
if (StrUtil.isNotBlank(name)) {
|
||||
return dingUserVOS.stream().filter(item -> item.getName().contains(name)).collect(Collectors.toCollection(ArrayList::new));
|
||||
return dingUserVOS.stream().filter(item -> {
|
||||
boolean flag = true;
|
||||
if (StrUtil.isNotBlank(userId)) {
|
||||
flag = item.getUserid().equals(userId);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(name)) {
|
||||
flag = item.getName().contains(name);
|
||||
}
|
||||
return flag;
|
||||
}).collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
return dingUserVOS;
|
||||
}catch (Exception e) {
|
||||
@@ -148,9 +210,9 @@ public class DingService {
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<DingAttendanceStatsVO> getUserReport(Long shopId, String key, String secret, DateTime startTime, DateTime endTime, String name) {
|
||||
public ArrayList<DingAttendanceStatsVO> getUserReport(Long shopId, String key, String secret, DateTime startTime, DateTime endTime, String name, String userId) {
|
||||
Map<String, String> columns = getColumns(key, secret, shopId);
|
||||
ArrayList<DingUserVO> userList = getUserList(name, key, secret, shopId);
|
||||
ArrayList<DingUserVO> userList = getUserList(name, key, secret, shopId, userId);
|
||||
ArrayList<DingAttendanceStatsVO> statsVOS = new ArrayList<>();
|
||||
for (DingUserVO item : userList) {
|
||||
JSONObject repost = null;
|
||||
@@ -166,6 +228,7 @@ public class DingService {
|
||||
statsVO.setName(item.getName());
|
||||
if (repost != null) {
|
||||
statsVO.setActive(true);
|
||||
statsVO.setReport(repost.getJSONArray("column_vals"));
|
||||
repost.getJSONArray("column_vals").forEach(info -> {
|
||||
JSONObject infoObj = (JSONObject) info;
|
||||
Long id = infoObj.getJSONObject("column_vo").getLong("id");
|
||||
|
||||
Reference in New Issue
Block a user