团队统计

This commit is contained in:
aikai 2024-05-30 17:50:28 +08:00
parent e1adac3c89
commit a06aa2fda6
11 changed files with 529 additions and 70 deletions

View File

@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* System 错误码枚举类
*
* <p>
* 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, "模板不存在");

View File

@ -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<Map<String, TeamAttendanceStatisticsByDayVO>> teamStatisticsByDay(@ModelAttribute @Valid TeamAttendanceStatisticsByDayDTO dto) {
Map<String, TeamAttendanceStatisticsByDayVO> map = attendanceService.teamStatisticsByDay(dto);
return success(map);
}
@GetMapping("/tesmStatisticsByCycle")
@Operation(summary = "团队统计按周期")
public CommonResult<TeamAttendanceStatisticsByCycleVO> tesmStatisticsByCycle(@ModelAttribute @Valid TeamAttendanceStatisticsByCycleDTO dto) {
TeamAttendanceStatisticsByCycleVO map = attendanceService.tesmStatisticsByCycle(dto);
return success(map);
}
}

View File

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

View File

@ -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();
}

View File

@ -27,36 +27,4 @@ public class AttendanceStatisticsVO {
private List<AttendancePunchStatisticsVO> 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;
}
}

View File

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

View File

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

View File

@ -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<TeamAttendancePunchStatisticsVO> averageWorkingHoursList;
@Schema(description = "迟到")
private List<TeamAttendancePunchStatisticsVO> beLateList;
@Schema(description = "早退")
private List<TeamAttendancePunchStatisticsVO> leaveEarlyList;
@Schema(description = "缺卡")
private List<TeamAttendancePunchStatisticsVO> missingCardList;
@Schema(description = "旷工")
private List<TeamAttendancePunchStatisticsVO> absenteeismList;
@Schema(description = "外勤")
private List<TeamAttendancePunchStatisticsVO> 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;
}
}

View File

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

View File

@ -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<String, TeamAttendanceStatisticsByDayVO> teamStatisticsByDay(TeamAttendanceStatisticsByDayDTO dto);
/**
* 团队按周期查询
*
* @param dto
* @return
*/
TeamAttendanceStatisticsByCycleVO tesmStatisticsByCycle(TeamAttendanceStatisticsByCycleDTO dto);
}

View File

@ -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<AttendancePunchStatisticsVO> missingCardsNumber = new ArrayList<>();
List<AttendancePunchStatisticsVO> minerDays = new ArrayList<>();
List<AttendancePunchStatisticsVO> fieldServiceNumber = new ArrayList<>();
AttendanceStatisticsVO.CalculateNum calculateNum = new AttendanceStatisticsVO.CalculateNum();
CalculateNum calculateNum = new CalculateNum();
for (Map.Entry<String, List<AttendancePunchRecordDO>> entry : map.entrySet()) {
String day = entry.getKey();
@ -492,7 +495,7 @@ public class AttendanceServiceImpl implements AttendanceService {
List<AttendancePunchStatisticsVO> 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<String, TeamAttendanceStatisticsByDayVO> teamStatisticsByDay(TeamAttendanceStatisticsByDayDTO dto) {
Map<String, TeamAttendanceStatisticsByDayVO> 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<String> dateList = DateUtils.betweenDayList(DateUtil.beginOfMonth(dto.getTime()),
DateUtil.endOfMonth(dto.getTime()));
List<AttendancePunchRecordDO> list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper<AttendancePunchRecordDO>()
.eq(AttendancePunchRecordDO::getAttendanceGroupId, dto.getGroupId())
.in(AttendancePunchRecordDO::getDayTime, dateList)
.orderByAsc(AttendancePunchRecordDO::getDayTime)
.orderByAsc(AttendancePunchRecordDO::getLevel)
.orderByAsc(AttendancePunchRecordDO::getWorkType));
Map<String, List<AttendancePunchRecordDO>> punchRecorMap = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime));
for (Map.Entry<String, List<AttendancePunchRecordDO>> entry : punchRecorMap.entrySet()) {
Map<Long, List<AttendancePunchRecordDO>> userMap = entry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId));
Map<Long, List<AttendancePunchRecordDO>> 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<String> dateList = DateUtils.betweenDayList(beginTime, endTime);
List<AttendancePunchRecordDO> list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper<AttendancePunchRecordDO>()
.eq(AttendancePunchRecordDO::getAttendanceGroupId, dto.getGroupId())
.in(AttendancePunchRecordDO::getDayTime, dateList)
.orderByAsc(AttendancePunchRecordDO::getDayTime)
.orderByAsc(AttendancePunchRecordDO::getLevel)
.orderByAsc(AttendancePunchRecordDO::getWorkType));
//获取用户列表
List<Long> userIds = list.stream().map(AttendancePunchRecordDO::getUserId).distinct().collect(Collectors.toList());
List<AdminUserDO> userList = adminUserService.getUserList(userIds);
Map<Long, AdminUserDO> userMap = new HashMap<>();
if (CollectionUtil.isNotEmpty(userList)) {
userMap = userList.stream().collect(Collectors.toMap(AdminUserDO::getId, Function.identity()));
}
//平均工时
List<TeamAttendancePunchStatisticsVO> averageWorkingHours = new ArrayList<>();
//迟到
List<TeamAttendancePunchStatisticsVO> beLateList = new ArrayList<>();
//早退
List<TeamAttendancePunchStatisticsVO> leaveEarlyList = new ArrayList<>();
//缺卡
List<TeamAttendancePunchStatisticsVO> missingCardList = new ArrayList<>();
//旷工
List<TeamAttendancePunchStatisticsVO> absenteeismList = new ArrayList<>();
//外勤
List<TeamAttendancePunchStatisticsVO> fieldServiceList = new ArrayList<>();
Map<Long, List<AttendancePunchRecordDO>> userPunchMap = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId));
// -- 根据用户分组
for (Map.Entry<Long, List<AttendancePunchRecordDO>> 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<String, List<AttendancePunchRecordDO>> dayMap = entry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime));
for (Map.Entry<String, List<AttendancePunchRecordDO>> dayEntry : dayMap.entrySet()) {
// -- 按照班次子表分组
Map<Long, List<AttendancePunchRecordDO>> 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<AttendancePunchStatisticsVO> calculateFieldService(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
private List<AttendancePunchStatisticsVO> calculateFieldService(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
int todayFieldService = 0;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
@ -551,6 +728,21 @@ public class AttendanceServiceImpl implements AttendanceService {
return list;
}
private void calculateFieldService(Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
int todayFieldService = 0;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 缺卡计算
List<AttendancePunchRecordDO> 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<AttendancePunchRecordDO> list, AttendanceStatisticsVO.CalculateNum calculateNum) {
private AttendancePunchStatisticsVO calculateMiner(String day, String weekChinese, List<AttendancePunchRecordDO> list, CalculateNum calculateNum) {
AttendancePunchStatisticsVO vo = null;
List<AttendancePunchRecordDO> 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<AttendancePunchRecordDO> list, CalculateNum calculateNum) {
List<AttendancePunchRecordDO> 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<AttendancePunchStatisticsVO> calculateRestDayList(List<String> dateList, List<String> attendanceTime, AttendanceStatisticsVO.CalculateNum calculateNum) {
private List<AttendancePunchStatisticsVO> calculateRestDayList(List<String> dateList, List<String> attendanceTime, CalculateNum calculateNum) {
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
List<String> 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<AttendancePunchStatisticsVO> calculateMissingCardsList(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
private List<AttendancePunchStatisticsVO> calculateMissingCardsList(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
int todayMissingCardsNumber = 0;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
@ -623,6 +822,20 @@ public class AttendanceServiceImpl implements AttendanceService {
return list;
}
private void calculateMissingCardsList(Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
int todayMissingCardsNumber = 0;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 缺卡计算
List<AttendancePunchRecordDO> 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<AttendancePunchStatisticsVO> calculateEarlyDepartures(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
private List<AttendancePunchStatisticsVO> calculateEarlyDepartures(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
int todayEarlyDeparturesNumber = 0;
long todayEarlyDeparturesTime = 0L;
@ -659,6 +872,24 @@ public class AttendanceServiceImpl implements AttendanceService {
return list;
}
private void calculateEarlyDepartures(Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
int todayEarlyDeparturesNumber = 0;
long todayEarlyDeparturesTime = 0L;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 早退计算
List<AttendancePunchRecordDO> 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<AttendancePunchStatisticsVO> calculateBeLate(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
private List<AttendancePunchStatisticsVO> calculateBeLate(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
int todayLateArrivalsNumber = 0;
long todayLateArrivalsTime = 0L;
@ -696,6 +927,24 @@ public class AttendanceServiceImpl implements AttendanceService {
return list;
}
private void calculateBeLate(Map<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
int todayLateArrivalsNumber = 0;
long todayLateArrivalsTime = 0L;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
// -- 迟到计算
List<AttendancePunchRecordDO> 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<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
private AttendancePunchStatisticsVO calculateAverageWorkingHour(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> 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<Long, List<AttendancePunchRecordDO>> workMap, CalculateNum calculateNum) {
long todayWorkingHours = 0L;
for (Map.Entry<Long, List<AttendancePunchRecordDO>> 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<AttendancePunchRecordDO> list, AttendanceStatisticsVO.CalculateNum calculateNum) {
private AttendancePunchStatisticsVO calculateAttendanceDays(String day, String weekChinese, List<AttendancePunchRecordDO> list, CalculateNum calculateNum) {
AttendancePunchStatisticsVO averageWorkingHourVO = null;
List<AttendancePunchRecordDO> 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<AttendancePunchRecordDO> list, CalculateNum calculateNum) {
List<AttendancePunchRecordDO> collect = list.stream().filter(a -> ObjectUtil.isNotEmpty(a.getPunchTime())).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(collect)) {
calculateNum.setTotalAttendanceDays(calculateNum.getTotalAttendanceDays() + 1);
}
}
}