diff --git a/cash-api/market-server/src/main/java/com/czg/controller/admin/AttendanceController.java b/cash-api/market-server/src/main/java/com/czg/controller/admin/AttendanceController.java index 312d9e1e6..04e31ce57 100644 --- a/cash-api/market-server/src/main/java/com/czg/controller/admin/AttendanceController.java +++ b/cash-api/market-server/src/main/java/com/czg/controller/admin/AttendanceController.java @@ -62,6 +62,20 @@ public class AttendanceController { public CzgResult> 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> 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)); } } diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/service/AttendanceService.java b/cash-common/cash-common-service/src/main/java/com/czg/market/service/AttendanceService.java index eae89aeb0..e055cc43f 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/market/service/AttendanceService.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/service/AttendanceService.java @@ -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 list(Long shopId, String name, String startTime, String endTime); + ArrayList list(Long shopId, String name, String startTime, String endTime, String userId); + + Map detail(Long shopId, String userId, String startTime, String endTime, Integer weekNum); } diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/vo/DingAttendanceStatsVO.java b/cash-common/cash-common-service/src/main/java/com/czg/market/vo/DingAttendanceStatsVO.java index fe69c8400..ab2193acb 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/market/vo/DingAttendanceStatsVO.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/vo/DingAttendanceStatsVO.java @@ -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 "出勤天数": diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/AttendanceServiceImpl.java b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/AttendanceServiceImpl.java index 1e188d2b9..404df6faa 100644 --- a/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/AttendanceServiceImpl.java +++ b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/AttendanceServiceImpl.java @@ -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 list(Long shopId, String name, String startTime, String endTime) { + public ArrayList 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 detail(Long shopId, String userId, String startTime, String endTime, Integer weekNum) { + ArrayList listed = list(shopId, null, startTime, endTime, userId); + + ArrayList> 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() {{ + put("attendanceSummary", null); + put("weekList", weekList); + put("statusList", null); + }}; + } + ShopConfig config = shopConfigService.getById(shopId); + if (config == null || StrUtil.isBlank(config.getDingAppSecret())) { + return new HashMap() {{ + put("attendanceSummary", null); + put("weekList", weekList); + put("statusList", null); + }}; + } + ConcurrentLinkedDeque 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 + ); } } diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/DingService.java b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/DingService.java index e222782bb..3d0e8ba07 100644 --- a/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/DingService.java +++ b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/DingService.java @@ -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 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 columns = getColumns(key, secret, shopId); + String columId = null; + for (Map.Entry entry : columns.entrySet()) { + String key1 = entry.getKey(); + String value = entry.getValue(); + if (value.equals(name)) { + columId = key1; + break; + } + } + return columId; + } + public Map 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 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 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 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 getUserReport(Long shopId, String key, String secret, DateTime startTime, DateTime endTime, String name) { + public ArrayList getUserReport(Long shopId, String key, String secret, DateTime startTime, DateTime endTime, String name, String userId) { Map columns = getColumns(key, secret, shopId); - ArrayList userList = getUserList(name, key, secret, shopId); + ArrayList userList = getUserList(name, key, secret, shopId, userId); ArrayList 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");