From a06aa2fda6c614824f89df1c6c14d47746e58712 Mon Sep 17 00:00:00 2001 From: aikai Date: Thu, 30 May 2024 17:50:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=A2=E9=98=9F=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/enums/ErrorCodeConstants.java | 6 +- .../app/attendance/AttendanceController.java | 23 +- .../TeamAttendanceStatisticsByCycleDTO.java | 36 +++ .../dto/TeamAttendanceStatisticsByDayDTO.java | 28 ++ .../attendance/vo/AttendanceStatisticsVO.java | 32 -- .../app/attendance/vo/CalculateNum.java | 36 +++ .../vo/TeamAttendancePunchStatisticsVO.java | 33 ++ .../vo/TeamAttendanceStatisticsByCycleVO.java | 53 +++ .../vo/TeamAttendanceStatisticsByDayVO.java | 22 ++ .../service/attendance/AttendanceService.java | 26 +- .../attendance/AttendanceServiceImpl.java | 304 ++++++++++++++++-- 11 files changed, 529 insertions(+), 70 deletions(-) create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByCycleDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByDayDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/CalculateNum.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendancePunchStatisticsVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByCycleVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByDayVO.java diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 0a3b2b68..ccdbccad 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; /** * System 错误码枚举类 - * + *

* system 系统,使用 1-002-000-000 段 */ public interface ErrorCodeConstants { @@ -45,7 +45,7 @@ public interface ErrorCodeConstants { // ========== 部门模块 1-002-004-000 ========== ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门"); - ErrorCode DEPT_PARENT_NOT_EXITS = new ErrorCode(1_002_004_001,"父级部门不存在"); + ErrorCode DEPT_PARENT_NOT_EXITS = new ErrorCode(1_002_004_001, "父级部门不存在"); ErrorCode DEPT_NOT_FOUND = new ErrorCode(1_002_004_002, "当前部门不存在"); ErrorCode DEPT_EXITS_CHILDREN = new ErrorCode(1_002_004_003, "存在子部门,无法删除"); ErrorCode DEPT_PARENT_ERROR = new ErrorCode(1_002_004_004, "不能设置自己为父部门"); @@ -195,6 +195,8 @@ public interface ErrorCodeConstants { ErrorCode THE_START_TIME_CANNOT_BE_GREATER_THAN_THE_END_TIME = new ErrorCode(1_003_011_000, "开始时间不可大于结束时间!"); + ErrorCode NO_PERMISSION_TO_VIEW_CURRENT_ATTENDANCE_GROUP_INFORMATION = new ErrorCode(1_003_012_000, "无权限查看当前考勤组信息!"); + ErrorCode LOG_FORM_NOT_USE = new ErrorCode(1_009_010_004, "你不用使用该日志模板"); ErrorCode LOG_USE_NOT_EXISTS = new ErrorCode(1_009_010_005, "模板不存在"); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java index 4855c197..cf1ac79c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java @@ -1,14 +1,8 @@ package cn.iocoder.yudao.module.system.controller.app.attendance; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePunchDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePunchPageDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendanceStatisticsByCycleDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendanceStatisticsByDayDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchPageVO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchVO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendanceStatisticsVO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendanceStatusByDayVO; +import cn.iocoder.yudao.module.system.controller.app.attendance.dto.*; +import cn.iocoder.yudao.module.system.controller.app.attendance.vo.*; import cn.iocoder.yudao.module.system.service.attendance.AttendanceService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -57,6 +51,17 @@ public class AttendanceController { return success(vo); } + @GetMapping("/teamStatisticsByDay") + @Operation(summary = "团队统计按天") + public CommonResult> teamStatisticsByDay(@ModelAttribute @Valid TeamAttendanceStatisticsByDayDTO dto) { + Map map = attendanceService.teamStatisticsByDay(dto); + return success(map); + } - + @GetMapping("/tesmStatisticsByCycle") + @Operation(summary = "团队统计按周期") + public CommonResult tesmStatisticsByCycle(@ModelAttribute @Valid TeamAttendanceStatisticsByCycleDTO dto) { + TeamAttendanceStatisticsByCycleVO map = attendanceService.tesmStatisticsByCycle(dto); + return success(map); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByCycleDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByCycleDTO.java new file mode 100644 index 00000000..f4dc60fa --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByCycleDTO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.controller.app.attendance.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + + +@Data +@Accessors(chain = true) +public class TeamAttendanceStatisticsByCycleDTO { + private Long userId = getLoginUserId(); + + @Schema(description = "考勤组id") + private Long groupId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT) + @Schema(description = "开始时间") + @NotNull(message = "开始时间不可以为空") + private Date startTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT) + @Schema(description = "结束时间") + @NotNull(message = "结束时间不可以为空") + private Date endTime; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByDayDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByDayDTO.java new file mode 100644 index 00000000..a3d92bf6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/TeamAttendanceStatisticsByDayDTO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.controller.app.attendance.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + + +@Data +@Accessors(chain = true) +public class TeamAttendanceStatisticsByDayDTO { + @Schema(description = "考勤组id") + private Long groupId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT) + @Schema(description = "当前查看的时间 (默认当天 yyyy-MM-dd)") + private Date time = new Date(); + + private Long userId = getLoginUserId(); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java index e33f0305..47c4bb6c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java @@ -27,36 +27,4 @@ public class AttendanceStatisticsVO { private List restDays; @Schema(description = "头部次数") private CalculateNum calculateNum; - - @Data - public static class CalculateNum { - @Schema(description = "总考勤时间") - long totalWorkingHours = 0L; - @Schema(description = "总出勤天数") - int totalAttendanceDays = 0; - @Schema(description = "总休息天数") - int totalRestDays = 0; - @Schema(description = "迟到总次数") - int totalLateArrivalsNumber = 0; - @Schema(description = "迟到总时间") - long totalLateArrivalsTime = 0L; - @Schema(description = "迟到总时间中文") - String totalLateArrivalsTimeStr; - @Schema(description = "早退总次数") - int totalEarlyDeparturesNumber = 0; - @Schema(description = "早退总时间") - long totalEarlyDeparturesTime = 0L; - @Schema(description = "早退总时间中文") - String totalEarlyDeparturesTimeStr; - @Schema(description = "缺卡总次数") - int totalMissingCardsNumber = 0; - @Schema(description = "矿工总天数") - int totalMinerDays = 0; - @Schema(description = "外勤次数") - int totalFieldServiceNumber = 0; - @Schema(description = "平均工时") - long averageWorkingHours = 0L; - @Schema(description = "平均工时中文") - String averageWorkingHoursStr; - } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/CalculateNum.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/CalculateNum.java new file mode 100644 index 00000000..df7017c3 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/CalculateNum.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.controller.app.attendance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class CalculateNum { + @Schema(description = "总考勤时间") + long totalWorkingHours = 0L; + @Schema(description = "总出勤天数") + int totalAttendanceDays = 0; + @Schema(description = "总休息天数") + int totalRestDays = 0; + @Schema(description = "迟到总次数") + int totalLateArrivalsNumber = 0; + @Schema(description = "迟到总时间") + long totalLateArrivalsTime = 0L; + @Schema(description = "迟到总时间中文") + String totalLateArrivalsTimeStr; + @Schema(description = "早退总次数") + int totalEarlyDeparturesNumber = 0; + @Schema(description = "早退总时间") + long totalEarlyDeparturesTime = 0L; + @Schema(description = "早退总时间中文") + String totalEarlyDeparturesTimeStr; + @Schema(description = "缺卡总次数") + int totalMissingCardsNumber = 0; + @Schema(description = "矿工总天数") + int totalMinerDays = 0; + @Schema(description = "外勤次数") + int totalFieldServiceNumber = 0; + @Schema(description = "平均工时") + long averageWorkingHours = 0L; + @Schema(description = "平均工时中文") + String averageWorkingHoursStr; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendancePunchStatisticsVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendancePunchStatisticsVO.java new file mode 100644 index 00000000..7517a807 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendancePunchStatisticsVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.system.controller.app.attendance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +public class TeamAttendancePunchStatisticsVO { + @Schema(description = "用户id") + private Long userId; + + @Schema(description = "名字") + private String name; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "考勤组名称") + private String groupName; + + @Schema(description = "班次名称") + private String shiftName; + + @Schema(description = "上面的次数/时间") + private String top; + + @Schema(description = "下面的次数/时间") + private String down; + + @Schema(description = "头部次数") + private CalculateNum calculateNum; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByCycleVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByCycleVO.java new file mode 100644 index 00000000..8b0e243b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByCycleVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.controller.app.attendance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Accessors(chain = true) +public class TeamAttendanceStatisticsByCycleVO { + + @Schema(description = "平均工作时间") + private List averageWorkingHoursList; + + @Schema(description = "迟到") + private List beLateList; + + @Schema(description = "早退") + private List leaveEarlyList; + + @Schema(description = "缺卡") + private List missingCardList; + + @Schema(description = "旷工") + private List absenteeismList; + + @Schema(description = "外勤") + private List fieldServiceList; + + + @Data + public static class TeamAttendanceStatisticsNumVO { + @Schema(description = "平均工时") + private BigDecimal averageWorkingHours; + + @Schema(description = "迟到次数") + private Integer beLateNum; + + @Schema(description = "早退次数") + private Integer leaveEarlyNum; + + @Schema(description = "缺卡次数") + private Integer missingCardNum; + + @Schema(description = "旷工次数") + private Integer absenteeismNum; + + @Schema(description = "外勤次数") + private Integer fieldServiceNum; + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByDayVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByDayVO.java new file mode 100644 index 00000000..d3ab8d7c --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/TeamAttendanceStatisticsByDayVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.system.controller.app.attendance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +public class TeamAttendanceStatisticsByDayVO { + @Schema(description = "应到人数") + private Integer answerNum; + @Schema(description = "打卡人数") + private Integer punchNum; + @Schema(description = "未打卡数量") + private Integer punchStatusMissNum; + @Schema(description = "迟到数量") + private Integer lateNum; + @Schema(description = "早退数量") + private Integer leaveEarlyNum; + @Schema(description = "外勤数量") + private Integer fieldworkNum; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java index c551aad0..78b09739 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java @@ -1,13 +1,7 @@ package cn.iocoder.yudao.module.system.service.attendance; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePunchDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePunchPageDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendanceStatisticsByCycleDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendanceStatisticsByDayDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchPageVO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchVO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendanceStatisticsVO; -import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendanceStatusByDayVO; +import cn.iocoder.yudao.module.system.controller.app.attendance.dto.*; +import cn.iocoder.yudao.module.system.controller.app.attendance.vo.*; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO; import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO; @@ -72,4 +66,20 @@ public interface AttendanceService { * @return */ AttendanceStatisticsVO statisticsByCycle(AttendanceStatisticsByCycleDTO dto); + + /** + * 团队统计按天查询 + * + * @param dto + * @return + */ + Map teamStatisticsByDay(TeamAttendanceStatisticsByDayDTO dto); + + /** + * 团队按周期查询 + * + * @param dto + * @return + */ + TeamAttendanceStatisticsByCycleVO tesmStatisticsByCycle(TeamAttendanceStatisticsByCycleDTO dto); } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java index ab592936..448a6567 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java @@ -14,15 +14,13 @@ import cn.iocoder.yudao.framework.common.Constants; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.distance.GeoUtil; import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePunchDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePunchPageDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendanceStatisticsByCycleDTO; -import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendanceStatisticsByDayDTO; +import cn.iocoder.yudao.module.system.controller.app.attendance.dto.*; import cn.iocoder.yudao.module.system.controller.app.attendance.vo.*; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshift.AttendanceGroupShiftDO; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper; import cn.iocoder.yudao.module.system.handler.PunchHandler; import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService; @@ -31,6 +29,7 @@ import cn.iocoder.yudao.module.system.service.attendance.groupshiftitem.Attendan import cn.iocoder.yudao.module.system.service.attendance.punch.PunchService; import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO; import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.extern.slf4j.Slf4j; @@ -46,6 +45,7 @@ import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; import static cn.hutool.core.date.DateUtil.dayOfWeekEnum; @@ -73,6 +73,9 @@ public class AttendanceServiceImpl implements AttendanceService { private AttendancePunchRecordService attendancePunchRecordService; @Resource private AttendancePunchRecordMapper attendancePunchRecordMapper; + @Resource + private AdminUserService adminUserService; + // 定义一些常量以提高代码的可读性和可维护性 /** @@ -465,7 +468,7 @@ public class AttendanceServiceImpl implements AttendanceService { List missingCardsNumber = new ArrayList<>(); List minerDays = new ArrayList<>(); List fieldServiceNumber = new ArrayList<>(); - AttendanceStatisticsVO.CalculateNum calculateNum = new AttendanceStatisticsVO.CalculateNum(); + CalculateNum calculateNum = new CalculateNum(); for (Map.Entry> entry : map.entrySet()) { String day = entry.getKey(); @@ -492,7 +495,7 @@ public class AttendanceServiceImpl implements AttendanceService { List missingCardsList = this.calculateMissingCardsList(day, weekChinese, workMap, calculateNum); missingCardsNumber.addAll(missingCardsList); - // -- 矿工计算 + // -- 旷工计算 AttendancePunchStatisticsVO miner = this.calculateMiner(day, weekChinese, entry.getValue(), calculateNum); if (miner != null) { minerDays.add(miner); @@ -519,6 +522,180 @@ public class AttendanceServiceImpl implements AttendanceService { return vo; } + @Override + public Map teamStatisticsByDay(TeamAttendanceStatisticsByDayDTO dto) { + Map map = new HashMap<>(); + //查询考勤组 + AttendanceGroupDO attendanceGroupDO = attendanceGroupService.getGroup(dto.getGroupId()); + // - 判断当前用户是否有权限查看 + // TODO: 2024/5/28 这里需要根据数据权限再过滤一下 ? 或者说移动端不让看 有数据权限的直接在管理后台看 + if (!dto.getUserId().equals(attendanceGroupDO.getUserId())) { + throw exception(NO_PERMISSION_TO_VIEW_CURRENT_ATTENDANCE_GROUP_INFORMATION); + } + List dateList = DateUtils.betweenDayList(DateUtil.beginOfMonth(dto.getTime()), + DateUtil.endOfMonth(dto.getTime())); + List list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper() + .eq(AttendancePunchRecordDO::getAttendanceGroupId, dto.getGroupId()) + .in(AttendancePunchRecordDO::getDayTime, dateList) + .orderByAsc(AttendancePunchRecordDO::getDayTime) + .orderByAsc(AttendancePunchRecordDO::getLevel) + .orderByAsc(AttendancePunchRecordDO::getWorkType)); + Map> punchRecorMap = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime)); + + for (Map.Entry> entry : punchRecorMap.entrySet()) { + Map> userMap = entry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId)); + Map> punchMap = entry.getValue().stream().filter(a -> ObjectUtil.isNotEmpty(a.getPunchTime())).collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId)); + int punchStatusMissNum = 0; + int lateNum = 0; + int leaveEarlyNum = 0; + int fieldworkNum = 0; + for (AttendancePunchRecordDO attendancePunchRecordDO : entry.getValue()) { + if (AttendanceOnTheDayDTO.PUNCH_STATUS_MISS.equals(attendancePunchRecordDO.getStatus())) { + punchStatusMissNum++; + } + if (AttendanceOnTheDayDTO.PUNCH_STATUS_LEAVE_EARLY.equals(attendancePunchRecordDO.getStatus())) { + lateNum++; + } + if (AttendanceOnTheDayDTO.PUNCH_STATUS_LATE.equals(attendancePunchRecordDO.getStatus())) { + leaveEarlyNum++; + } + if (Constants.TRUE.equals(attendancePunchRecordDO.getFieldServiceFlag())) { + fieldworkNum++; + } + } + TeamAttendanceStatisticsByDayVO vo = new TeamAttendanceStatisticsByDayVO(); + vo.setAnswerNum(userMap.keySet().size()); + vo.setPunchNum(punchMap.keySet().size()); + vo.setPunchStatusMissNum(punchStatusMissNum); + vo.setLateNum(lateNum); + vo.setLeaveEarlyNum(leaveEarlyNum); + vo.setFieldworkNum(fieldworkNum); + map.put(entry.getKey(), vo); + } + return map; + } + + @Override + public TeamAttendanceStatisticsByCycleVO tesmStatisticsByCycle(TeamAttendanceStatisticsByCycleDTO dto) { + TeamAttendanceStatisticsByCycleVO vo = new TeamAttendanceStatisticsByCycleVO(); + TeamAttendanceStatisticsByCycleVO.TeamAttendanceStatisticsNumVO teamAttendanceStatisticsNumVO = new TeamAttendanceStatisticsByCycleVO.TeamAttendanceStatisticsNumVO(); + //查询考勤组 + AttendanceGroupDO attendanceGroupDO = attendanceGroupService.getGroup(dto.getGroupId()); + // - 判断当前用户是否有权限查看 + // TODO: 2024/5/28 这里需要根据数据权限再过滤一下 ? 或者说移动端不让看 有数据权限的直接在管理后台看 + if (!dto.getUserId().equals(attendanceGroupDO.getUserId())) { + throw exception(NO_PERMISSION_TO_VIEW_CURRENT_ATTENDANCE_GROUP_INFORMATION); + } + Date thisTime = new Date(); + Date beginTime = dto.getStartTime(); + Date endTime = dto.getEndTime(); + if (beginTime.getTime() > endTime.getTime()) { + throw exception(THE_START_TIME_CANNOT_BE_GREATER_THAN_THE_END_TIME); + } + // -- 如果结束时间大于当前时间 - 那么结束时间 = 当前时间 + if (endTime.getTime() > thisTime.getTime()) { + endTime = thisTime; + } + List dateList = DateUtils.betweenDayList(beginTime, endTime); + List list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper() + .eq(AttendancePunchRecordDO::getAttendanceGroupId, dto.getGroupId()) + .in(AttendancePunchRecordDO::getDayTime, dateList) + .orderByAsc(AttendancePunchRecordDO::getDayTime) + .orderByAsc(AttendancePunchRecordDO::getLevel) + .orderByAsc(AttendancePunchRecordDO::getWorkType)); + + + //获取用户列表 + List userIds = list.stream().map(AttendancePunchRecordDO::getUserId).distinct().collect(Collectors.toList()); + List userList = adminUserService.getUserList(userIds); + Map userMap = new HashMap<>(); + if (CollectionUtil.isNotEmpty(userList)) { + userMap = userList.stream().collect(Collectors.toMap(AdminUserDO::getId, Function.identity())); + } + //平均工时 + List averageWorkingHours = new ArrayList<>(); + //迟到 + List beLateList = new ArrayList<>(); + //早退 + List leaveEarlyList = new ArrayList<>(); + //缺卡 + List missingCardList = new ArrayList<>(); + //旷工 + List absenteeismList = new ArrayList<>(); + //外勤 + List fieldServiceList = new ArrayList<>(); + + Map> userPunchMap = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId)); + // -- 根据用户分组 + for (Map.Entry> entry : userPunchMap.entrySet()) { + // 通用头部 ------------------------------------ + TeamAttendancePunchStatisticsVO averageWorkingHourVO = new TeamAttendancePunchStatisticsVO(); + AdminUserDO adminUserDO = userMap.get(entry.getKey()); + averageWorkingHourVO.setUserId(entry.getKey()); + if (adminUserDO != null) { + averageWorkingHourVO.setName(adminUserDO.getNickname()); + averageWorkingHourVO.setAvatar(adminUserDO.getAvatar()); + } + // 通用头部 ------------------------------------ + + CalculateNum calculateNum = new CalculateNum(); + //按日期分组 + Map> dayMap = entry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime)); + for (Map.Entry> dayEntry : dayMap.entrySet()) { + // -- 按照班次子表分组 + Map> workMap = dayEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupShiftItemId)); + this.calculateAverageWorkingHour(workMap, calculateNum); + // -- 出考勤天数 + this.calculateAttendanceDays(dayEntry.getValue(), calculateNum); + // -- 迟到 + this.calculateBeLate(workMap, calculateNum); + // -- 早退 + this.calculateEarlyDepartures(workMap, calculateNum); + // -- 缺卡 + this.calculateMissingCardsList(workMap, calculateNum); + // -- 旷工 + this.calculateMiner(entry.getValue(), calculateNum); + // -- 外勤 + this.calculateFieldService(workMap, calculateNum); + } + calculateNum.setAverageWorkingHours(calculateNum.getTotalAttendanceDays() == 0 ? 0 : calculateNum.getTotalWorkingHours() / calculateNum.getTotalAttendanceDays()); + calculateNum.setAverageWorkingHoursStr(DateUtil.formatBetween(calculateNum.getAverageWorkingHours(), BetweenFormatter.Level.MINUTE)); + calculateNum.setTotalLateArrivalsTimeStr(DateUtil.formatBetween(calculateNum.getTotalLateArrivalsTime(), BetweenFormatter.Level.MINUTE)); + calculateNum.setTotalEarlyDeparturesTimeStr(DateUtil.formatBetween(calculateNum.getTotalEarlyDeparturesTime(), BetweenFormatter.Level.MINUTE)); + averageWorkingHourVO.setCalculateNum(calculateNum); + + // --- 平均工时 + averageWorkingHours.add(averageWorkingHourVO.setTop(calculateNum.getAverageWorkingHoursStr()).setDown("出勤" + calculateNum.getTotalAttendanceDays() + "天")); + // --- 迟到 + if (calculateNum.getTotalLateArrivalsNumber() > 0) { + beLateList.add(averageWorkingHourVO.setTop(calculateNum.getTotalLateArrivalsNumber() + "次").setDown(calculateNum.getTotalLateArrivalsTimeStr())); + } + // --- 早退 + if (calculateNum.getTotalEarlyDeparturesNumber() > 0) { + leaveEarlyList.add(averageWorkingHourVO.setTop(calculateNum.getTotalEarlyDeparturesNumber() + "次").setDown(calculateNum.getTotalEarlyDeparturesTimeStr())); + } + // --- 缺卡 + if (calculateNum.getTotalMissingCardsNumber() > 0) { + missingCardList.add(averageWorkingHourVO.setTop(calculateNum.getTotalMissingCardsNumber() + "次").setDown("")); + } + // --- 旷工 + if (calculateNum.getTotalMinerDays() > 0) { + absenteeismList.add(averageWorkingHourVO.setTop(calculateNum.getTotalMinerDays() + "天").setDown("")); + } + // --- 外勤 + if (calculateNum.getTotalFieldServiceNumber() > 0) { + fieldServiceList.add(averageWorkingHourVO.setTop(calculateNum.getTotalFieldServiceNumber() + "次").setDown("")); + } + } + vo.setAverageWorkingHoursList(averageWorkingHours); + vo.setBeLateList(beLateList); + vo.setLeaveEarlyList(leaveEarlyList); + vo.setMissingCardList(missingCardList); + vo.setAbsenteeismList(absenteeismList); + vo.setFieldServiceList(fieldServiceList); + return vo; + } + /** * 外勤计算 * @@ -528,7 +705,7 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private List calculateFieldService(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + private List calculateFieldService(String day, String weekChinese, Map> workMap, CalculateNum calculateNum) { List list = new ArrayList<>(); int todayFieldService = 0; for (Map.Entry> workEntry : workMap.entrySet()) { @@ -551,6 +728,21 @@ public class AttendanceServiceImpl implements AttendanceService { return list; } + + private void calculateFieldService(Map> workMap, CalculateNum calculateNum) { + int todayFieldService = 0; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 缺卡计算 + List fieldServiceList = workEntry.getValue().stream().filter(a -> Constants.TRUE.equals(a.getFieldServiceFlag())).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(fieldServiceList)) { + todayFieldService += fieldServiceList.size(); + } + } + } + calculateNum.setTotalFieldServiceNumber(calculateNum.getTotalFieldServiceNumber() + todayFieldService); + } + /** * 计算矿工 * @@ -559,7 +751,7 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private AttendancePunchStatisticsVO calculateMiner(String day, String weekChinese, List list, AttendanceStatisticsVO.CalculateNum calculateNum) { + private AttendancePunchStatisticsVO calculateMiner(String day, String weekChinese, List list, CalculateNum calculateNum) { AttendancePunchStatisticsVO vo = null; List collect = list.stream().filter(a -> a.getStatus().equals(AttendanceOnTheDayDTO.PUNCH_STATUS_MISS)).collect(Collectors.toList()); if (collect.size() == list.size()) { @@ -571,6 +763,13 @@ public class AttendanceServiceImpl implements AttendanceService { return vo; } + private void calculateMiner(List list, CalculateNum calculateNum) { + List collect = list.stream().filter(a -> a.getStatus().equals(AttendanceOnTheDayDTO.PUNCH_STATUS_MISS)).collect(Collectors.toList()); + if (collect.size() == list.size()) { + calculateNum.setTotalMinerDays(calculateNum.getTotalMinerDays() + 1); + } + } + /** * 休息时间计算 * @@ -579,7 +778,7 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private List calculateRestDayList(List dateList, List attendanceTime, AttendanceStatisticsVO.CalculateNum calculateNum) { + private List calculateRestDayList(List dateList, List attendanceTime, CalculateNum calculateNum) { List list = new ArrayList<>(); List subtract = new ArrayList<>(CollectionUtil.subtract(dateList, attendanceTime)); for (String timeStr : subtract) { @@ -600,7 +799,7 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private List calculateMissingCardsList(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + private List calculateMissingCardsList(String day, String weekChinese, Map> workMap, CalculateNum calculateNum) { List list = new ArrayList<>(); int todayMissingCardsNumber = 0; for (Map.Entry> workEntry : workMap.entrySet()) { @@ -623,6 +822,20 @@ public class AttendanceServiceImpl implements AttendanceService { return list; } + private void calculateMissingCardsList(Map> workMap, CalculateNum calculateNum) { + int todayMissingCardsNumber = 0; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 缺卡计算 + List missingCardsList = workEntry.getValue().stream().filter(a -> AttendanceOnTheDayDTO.PUNCH_STATUS_MISS.equals(a.getStatus())).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(missingCardsList)) { + todayMissingCardsNumber += missingCardsList.size(); + } + } + } + calculateNum.setTotalMissingCardsNumber(calculateNum.getTotalMissingCardsNumber() + todayMissingCardsNumber); + } + /** * 早退计算 * @@ -632,7 +845,7 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private List calculateEarlyDepartures(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + private List calculateEarlyDepartures(String day, String weekChinese, Map> workMap, CalculateNum calculateNum) { List list = new ArrayList<>(); int todayEarlyDeparturesNumber = 0; long todayEarlyDeparturesTime = 0L; @@ -659,6 +872,24 @@ public class AttendanceServiceImpl implements AttendanceService { return list; } + + private void calculateEarlyDepartures(Map> workMap, CalculateNum calculateNum) { + int todayEarlyDeparturesNumber = 0; + long todayEarlyDeparturesTime = 0L; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 早退计算 + List earlyDeparturesList = workEntry.getValue().stream().filter(a -> AttendanceOnTheDayDTO.PUNCH_STATUS_LEAVE_EARLY.equals(a.getStatus())).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(earlyDeparturesList)) { + todayEarlyDeparturesNumber += earlyDeparturesList.size(); + todayEarlyDeparturesTime += earlyDeparturesList.stream().mapToLong(AttendancePunchRecordDO::getLeaveEarlyTime).sum(); + } + } + } + calculateNum.setTotalEarlyDeparturesNumber(calculateNum.getTotalEarlyDeparturesNumber() + todayEarlyDeparturesNumber); + calculateNum.setTotalEarlyDeparturesTime(calculateNum.getTotalEarlyDeparturesTime() + todayEarlyDeparturesTime); + } + /** * 计算迟到 * @@ -668,7 +899,7 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private List calculateBeLate(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + private List calculateBeLate(String day, String weekChinese, Map> workMap, CalculateNum calculateNum) { List list = new ArrayList<>(); int todayLateArrivalsNumber = 0; long todayLateArrivalsTime = 0L; @@ -696,6 +927,24 @@ public class AttendanceServiceImpl implements AttendanceService { return list; } + + private void calculateBeLate(Map> workMap, CalculateNum calculateNum) { + int todayLateArrivalsNumber = 0; + long todayLateArrivalsTime = 0L; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 迟到计算 + List beLateList = workEntry.getValue().stream().filter(a -> AttendanceOnTheDayDTO.PUNCH_STATUS_LATE.equals(a.getStatus())).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(beLateList)) { + todayLateArrivalsNumber += beLateList.size(); + todayLateArrivalsTime += beLateList.stream().mapToLong(AttendancePunchRecordDO::getLateTime).sum(); + } + } + } + calculateNum.setTotalLateArrivalsNumber(calculateNum.getTotalLateArrivalsNumber() + todayLateArrivalsNumber); + calculateNum.setTotalLateArrivalsTime(calculateNum.getTotalLateArrivalsTime() + todayLateArrivalsTime); + } + /** * 计算考勤工时 * @@ -705,8 +954,22 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private AttendancePunchStatisticsVO calculateAverageWorkingHour(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + private AttendancePunchStatisticsVO calculateAverageWorkingHour(String day, String weekChinese, Map> workMap, CalculateNum calculateNum) { AttendancePunchStatisticsVO vo = new AttendancePunchStatisticsVO(); + long todayWorkingHours = this.calculateAverageWorkingHour(workMap, calculateNum); + vo.setDay(day); + vo.setWeek(weekChinese); + vo.setTime(DateUtil.formatBetween(todayWorkingHours, BetweenFormatter.Level.MINUTE)); + return vo; + } + + /** + * 计算考勤工时 + * + * @param workMap + * @return + */ + private long calculateAverageWorkingHour(Map> workMap, CalculateNum calculateNum) { long todayWorkingHours = 0L; for (Map.Entry> workEntry : workMap.entrySet()) { if (CollectionUtil.isNotEmpty(workEntry.getValue())) { @@ -717,18 +980,15 @@ public class AttendanceServiceImpl implements AttendanceService { if (ObjectUtil.isNotEmpty(first.getPunchTime()) && ObjectUtil.isNotEmpty(last.getPunchTime())) { long time = Math.abs(LocalDateTimeUtil.between(first.getPunchTime(), last.getPunchTime(), ChronoUnit.MILLIS)); todayWorkingHours += time; - DateUtil.formatBetween(time, BetweenFormatter.Level.MINUTE); } } } } - vo.setDay(day); - vo.setWeek(weekChinese); - vo.setTime(DateUtil.formatBetween(todayWorkingHours, BetweenFormatter.Level.MINUTE)); calculateNum.setTotalWorkingHours(calculateNum.getTotalWorkingHours() + todayWorkingHours); - return vo; + return todayWorkingHours; } + /** * 计算出勤天数 * @@ -738,7 +998,7 @@ public class AttendanceServiceImpl implements AttendanceService { * @param calculateNum * @return */ - private AttendancePunchStatisticsVO calculateAttendanceDays(String day, String weekChinese, List list, AttendanceStatisticsVO.CalculateNum calculateNum) { + private AttendancePunchStatisticsVO calculateAttendanceDays(String day, String weekChinese, List list, CalculateNum calculateNum) { AttendancePunchStatisticsVO averageWorkingHourVO = null; List collect = list.stream().filter(a -> ObjectUtil.isNotEmpty(a.getPunchTime())).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(collect)) { @@ -750,6 +1010,12 @@ public class AttendanceServiceImpl implements AttendanceService { return averageWorkingHourVO; } + private void calculateAttendanceDays(List list, CalculateNum calculateNum) { + List collect = list.stream().filter(a -> ObjectUtil.isNotEmpty(a.getPunchTime())).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(collect)) { + calculateNum.setTotalAttendanceDays(calculateNum.getTotalAttendanceDays() + 1); + } + } }