考勤统计调整

This commit is contained in:
aikai 2024-06-26 10:30:46 +08:00
parent 1257d8e288
commit edf7945f61
13 changed files with 134 additions and 17 deletions

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.attendance.dto;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@ -19,6 +20,11 @@ public class AttendancePunchPageDTO {
@Schema(description = "纬度")
private String latitude;
/**
* 当前用户
*/
private AdminUserDO user;
/**
* 当前用户id
*/

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.controller.admin.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.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -65,4 +66,9 @@ public class AttendancePunchPageVO {
* 考勤组班次子表
*/
private Long attendanceGroupShiftItemId;
/**
* 当前用户
*/
private AdminUserDO user;
}

View File

@ -17,6 +17,9 @@ public class AttendancePunchRecordSaveReqVO {
@Schema(description = "考勤组管理员id", example = "11409")
private Long userId;
@Schema(description = "部门id", example = "11409")
private Long deptId;
@Schema(description = "考勤组id", example = "22293")
private Long attendanceGroupId;

View File

@ -32,6 +32,10 @@ public class AttendancePunchRecordDO extends BaseDO {
* 考勤组管理员id
*/
private Long userId;
/**
* 部门id
*/
private Long deptId;
/**
* 考勤组id
*/

View File

@ -11,6 +11,7 @@ import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.attendance.dto.*;
@ -27,6 +28,7 @@ import cn.iocoder.yudao.module.system.handler.PunchHandler;
import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService;
import cn.iocoder.yudao.module.system.service.attendance.groupshift.AttendanceGroupShiftService;
import cn.iocoder.yudao.module.system.service.attendance.groupshiftitem.AttendanceGroupShiftItemService;
import cn.iocoder.yudao.module.system.service.attendance.groupuser.AttendanceGroupUserService;
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;
@ -71,7 +73,6 @@ public class AttendanceServiceImpl implements AttendanceService {
private AttendanceGroupShiftService attendanceGroupShiftService;
@Resource
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
@Resource
private AttendancePunchRecordService attendancePunchRecordService;
@Resource
@ -81,6 +82,8 @@ public class AttendanceServiceImpl implements AttendanceService {
@Resource
private AttendanceGroupMapper attendanceGroupMapper;
@Resource
private AttendanceGroupUserService attendanceGroupUserService;
// 定义一些常量以提高代码的可读性和可维护性
@ -101,6 +104,9 @@ public class AttendanceServiceImpl implements AttendanceService {
@Override
public AttendancePunchPageVO getPunchPage(AttendancePunchPageDTO dto) {
// -- 获取当前登陆用户 - 如果当前登陆用户状态异常 - 则不允许打卡
AdminUserDO user = adminUserService.getUser(dto.getUserId());
dto.setUser(user);
AttendancePunchPageVO vo = new AttendancePunchPageVO();
//获取当前登录用户所在群组
AttendanceGroupDO activationGroup = attendanceGroupService.getByUserId(dto.getUserId());
@ -120,6 +126,9 @@ public class AttendanceServiceImpl implements AttendanceService {
AttendancePunchPageVO pageVO = this.getPunchPage(new AttendancePunchPageDTO().setPunchType(dto.getPunchType())
.setLongitude(dto.getLongitude()).setLatitude(dto.getLatitude())
.setFlag(true).setLocalDateTime(dto.getLocalDateTime()).setUserId(dto.getUserId()));
if (pageVO.getUser() == null || pageVO.getUser().getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
throw exception(USER_NOT_EXISTS);
}
// -- 获取当天的考勤记录
if (Constants.FALSE.equals(pageVO.getInGroup())) {
throw exception(NOT_IN_THE_ATTENDANCE_GROUP);
@ -143,6 +152,7 @@ public class AttendanceServiceImpl implements AttendanceService {
//更新预打卡记录 - update 如果修改数量为0 则新增
AttendancePunchRecordSaveReqVO attendancePunchRecordSaveReqVO = new AttendancePunchRecordSaveReqVO()
.setUserId(dto.getUserId())
.setDeptId(pageVO.getUser().getDeptId())
.setAttendanceGroupId(pageVO.getActivationGroup().getId())
.setAttendanceGroupName(pageVO.getActivationGroup().getGroupName())
.setAttendanceGroupShiftId(pageVO.getAttendanceGroupShiftDO().getId())
@ -190,7 +200,6 @@ public class AttendanceServiceImpl implements AttendanceService {
dayDTO.setPunchAddress(dto.getPunchAddress());
dayDTO.setRemark(dto.getRemark());
dayDTO.setImage(dto.getImage());
// TODO: 2024/5/31 可能会有问题
dayDTO.setShouldPunchTime(pageVO.getShouldPunchTime());
dayDTO.setPunchLocalDateTime(dto.getLocalDateTime());
dayDTO.setLateTime(attendancePunchRecordSaveReqVO.getLateTime());
@ -648,8 +657,8 @@ public class AttendanceServiceImpl implements AttendanceService {
// -- 根据用户分组
for (Map.Entry<Long, List<AttendancePunchRecordDO>> entry : userPunchMap.entrySet()) {
// 通用头部 ------------------------------------
TeamAttendancePunchStatisticsVO averageWorkingHourVO = new TeamAttendancePunchStatisticsVO();
AdminUserDO adminUserDO = userMap.get(entry.getKey());
TeamAttendancePunchStatisticsVO averageWorkingHourVO = new TeamAttendancePunchStatisticsVO();
averageWorkingHourVO.setUserId(entry.getKey());
if (adminUserDO != null) {
averageWorkingHourVO.setName(adminUserDO.getNickname());
@ -687,23 +696,33 @@ public class AttendanceServiceImpl implements AttendanceService {
averageWorkingHours.add(averageWorkingHourVO.setTop(calculateNum.getAverageWorkingHoursStr()).setDown("出勤" + calculateNum.getTotalAttendanceDays() + ""));
// --- 迟到
if (calculateNum.getTotalLateArrivalsNumber() > 0) {
beLateList.add(averageWorkingHourVO.setTop(calculateNum.getTotalLateArrivalsNumber() + "").setDown(calculateNum.getTotalLateArrivalsTimeStr()));
TeamAttendancePunchStatisticsVO item = new TeamAttendancePunchStatisticsVO();
BeanUtil.copyProperties(averageWorkingHourVO, item);
beLateList.add(item.setTop(calculateNum.getTotalLateArrivalsNumber() + "").setDown(calculateNum.getTotalLateArrivalsTimeStr()));
}
// --- 早退
if (calculateNum.getTotalEarlyDeparturesNumber() > 0) {
leaveEarlyList.add(averageWorkingHourVO.setTop(calculateNum.getTotalEarlyDeparturesNumber() + "").setDown(calculateNum.getTotalEarlyDeparturesTimeStr()));
TeamAttendancePunchStatisticsVO item = new TeamAttendancePunchStatisticsVO();
BeanUtil.copyProperties(averageWorkingHourVO, item);
leaveEarlyList.add(item.setTop(calculateNum.getTotalEarlyDeparturesNumber() + "").setDown(calculateNum.getTotalEarlyDeparturesTimeStr()));
}
// --- 缺卡
if (calculateNum.getTotalMissingCardsNumber() > 0) {
missingCardList.add(averageWorkingHourVO.setTop(calculateNum.getTotalMissingCardsNumber() + "").setDown(""));
TeamAttendancePunchStatisticsVO item = new TeamAttendancePunchStatisticsVO();
BeanUtil.copyProperties(averageWorkingHourVO, item);
missingCardList.add(item.setTop(calculateNum.getTotalMissingCardsNumber() + "").setDown(""));
}
// --- 旷工
if (calculateNum.getTotalMinerDays() > 0) {
absenteeismList.add(averageWorkingHourVO.setTop(calculateNum.getTotalMinerDays() + "").setDown(""));
TeamAttendancePunchStatisticsVO item = new TeamAttendancePunchStatisticsVO();
BeanUtil.copyProperties(averageWorkingHourVO, item);
absenteeismList.add(item.setTop(calculateNum.getTotalMinerDays() + "").setDown(""));
}
// --- 外勤
if (calculateNum.getTotalFieldServiceNumber() > 0) {
fieldServiceList.add(averageWorkingHourVO.setTop(calculateNum.getTotalFieldServiceNumber() + "").setDown(""));
TeamAttendancePunchStatisticsVO item = new TeamAttendancePunchStatisticsVO();
BeanUtil.copyProperties(averageWorkingHourVO, item);
fieldServiceList.add(item.setTop(calculateNum.getTotalFieldServiceNumber() + "").setDown(""));
}
}
@ -760,6 +779,40 @@ public class AttendanceServiceImpl implements AttendanceService {
@Override
public void exportAttendanceExcel(HttpServletResponse response, ExportAttendanceExcelDTO dto) {
List<AdminUserDO> userList = new ArrayList<>();
List<Long> userIds = new ArrayList<>();
if (dto.getMemberRange() == 1) {
userList = adminUserService.getAllList(CommonStatusEnum.ENABLE.getStatus(), null, userIds);
} else if (dto.getMemberRange() == 2) {
// -- 获取考勤组ids
userIds = attendanceGroupUserService.getUserIdsByGroupIds(dto.getTargetIds());
userList = adminUserService.getAllList(CommonStatusEnum.ENABLE.getStatus(), null, userIds);
} else {
userList = adminUserService.getAllList(CommonStatusEnum.ENABLE.getStatus(), null, dto.getTargetIds());
}
// -- 统计
List<String> dateList = DateUtils.betweenDayList(dto.getStartTime(), dto.getEndTime());
if (dto.getType() == 1) {
this.monthlyStatistics(response, userList, dateList);
}
}
/**
* 按月导出
*
* @param response
* @param userList
* @param dateList
*/
private void monthlyStatistics(HttpServletResponse response, List<AdminUserDO> userList, List<String> dateList) {
//查询出数据 -- 时间周期 - 用户列表
List<AttendancePunchRecordDO> list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper<AttendancePunchRecordDO>()
.in(AttendancePunchRecordDO::getUserId, userList)
.in(AttendancePunchRecordDO::getDayTime, dateList));
// -- 根据部门分组 - 根据考勤组分组
Map<Long, Map<Long, List<AttendancePunchRecordDO>>> map = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDeptId, Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupId)));
}

View File

@ -235,6 +235,7 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
vo.setAttendanceGroupShiftId(attendanceFixedDO.getAttendanceGroupShiftId());
attendanceService.calculatePunch(dto, vo);
vo.setAttendanceGroupId(activationGroup.getId());
vo.setUser(dto.getUser());
return vo;
}

View File

@ -57,10 +57,10 @@ public interface AttendanceGroupUserService {
/**
* 根据考勤组id获取考勤人员ids
*
* @param id
* @param groupId
* @return
*/
List<Long> getUserIdsByGroupId(Long id);
List<Long> getUserIdsByGroupId(Long groupId);
/**
* 人员调整立即生效
@ -68,4 +68,10 @@ public interface AttendanceGroupUserService {
* @param vo
*/
void effectiveImmediately(AttendanceGroupUserCreateOrDelVO vo);
/**
* 通过考勤组ids获取考勤人员ids
* @param groupIds
*/
List<Long> getUserIdsByGroupIds(List<Long> groupIds);
}

View File

@ -141,4 +141,14 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
}
}
@Override
public List<Long> getUserIdsByGroupIds(List<Long> groupIds) {
if (CollectionUtil.isEmpty(groupIds)) {
return Collections.emptyList();
}
return groupUserMapper.selectList(new LambdaQueryWrapper<AttendanceGroupUserDO>()
.in(AttendanceGroupUserDO::getAttendanceGroupId, groupIds))
.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
}
}

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.Attendance
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import javax.validation.Valid;
import java.time.LocalDateTime;
@ -96,7 +97,7 @@ public interface AttendancePunchRecordService {
* @param localDateTime 需要预设的时间
*/
void defaultPersistence(Map<Long, Long> map, Map<Long, AttendanceGroupDO> groupMap, Map<Long, List<Long>> groupUserMap,
Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps, String time, LocalDateTime localDateTime);
Map<Long, AdminUserDO> userMap, Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps, String time, LocalDateTime localDateTime);
/**
* 获取未提醒列表 获取当天的未打卡并且未提醒记录

View File

@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.Attendance
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
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.group.AttendanceGroupMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
@ -23,6 +24,7 @@ import cn.iocoder.yudao.module.system.service.attendance.fixed.AttendanceFixedSe
import cn.iocoder.yudao.module.system.service.attendance.groupshiftitem.AttendanceGroupShiftItemService;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import cn.iocoder.yudao.module.system.service.attendance.scheduling.AttendanceSchedulingService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
@ -34,10 +36,7 @@ import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -70,6 +69,8 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
private AttendanceGroupUserMapper attendanceGroupUserMapper;
@Resource
private AttendanceGroupMapper attendanceGroupMapper;
@Resource
private AdminUserService adminUserService;
@Override
@ -161,6 +162,11 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
//将attendanceGroupUserDOS对象中的type相同的userId合并成一个数组 type作为key 用户id列表List<Long>作为value
Map<Long, List<Long>> groupUserMap = attendanceGroupUserDOS.stream().collect(Collectors.groupingBy(AttendanceGroupUserDO::getAttendanceGroupId,
Collectors.mapping(AttendanceGroupUserDO::getUserId, Collectors.toList())));
//获取用户部门
//合并groupUserMap的values
List<Long> userIds = groupUserMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
List<AdminUserDO> userList = adminUserService.getUserList(userIds);
Map<Long, AdminUserDO> userMap = userList.stream().collect(Collectors.toMap(AdminUserDO::getId, a -> a));
// -- 获取考勤组下考勤规则 - 将将考勤组分组 - 按类型
String time = localDateTime.format(Constants.REPO_DATE_FORMAT);
// 获取到考勤组 - 班次 key/value 格式
@ -170,7 +176,7 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
if (MapUtil.isNotEmpty(map)) {
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOList = attendanceGroupShiftItemService.getGroupShiftItemListByShiftIds(new ArrayList<>(map.values()));
Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps = attendanceGroupShiftItemDOList.stream().collect(Collectors.groupingBy(AttendanceGroupShiftItemDO::getKqAttendanceGroupShiftId));
this.defaultPersistence(map, groupMap, groupUserMap, itemMaps, time, localDateTime);
this.defaultPersistence(map, groupMap, groupUserMap, userMap, itemMaps, time, localDateTime);
}
}
@ -185,7 +191,7 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
*/
@Override
public void defaultPersistence(Map<Long, Long> map, Map<Long, AttendanceGroupDO> groupMap, Map<Long, List<Long>> groupUserMap,
Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps, String time, LocalDateTime localDateTime) {
Map<Long, AdminUserDO> userMap, Map<Long, List<AttendanceGroupShiftItemDO>> itemMaps, String time, LocalDateTime localDateTime) {
List<AttendancePunchRecordDO> attendancePunchRecordDOList = new ArrayList<>();
LocalDateTime nextDayLocalDateTime = LocalDateTimeUtil.offset(localDateTime, 1, ChronoUnit.DAYS);
for (Map.Entry<Long, Long> entry : map.entrySet()) {
@ -201,9 +207,12 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
}
List<AttendanceOnTheDayDTO> attendanceOnTheDayDTOS = attendanceService.buildAttendanceOnTheDay(attendanceGroupShiftItemDOS);
for (Long userId : userIds) {
AdminUserDO adminUserDO = userMap.get(userId);
Long deptId = adminUserDO == null ? null : adminUserDO.getDeptId();
for (AttendanceOnTheDayDTO attendanceOnTheDayDTO : attendanceOnTheDayDTOS) {
AttendancePunchRecordDO attendancePunchRecordDO = new AttendancePunchRecordDO();
attendancePunchRecordDO.setUserId(userId);
attendancePunchRecordDO.setDeptId(deptId);
attendancePunchRecordDO.setAttendanceGroupId(entry.getKey());
attendancePunchRecordDO.setAttendanceGroupName(attendanceGroupDO.getGroupName());
attendancePunchRecordDO.setAttendanceGroupShiftId(attendanceOnTheDayDTO.getKqAttendanceGroupShiftId());

View File

@ -230,6 +230,7 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
vo.setAttendanceGroupShiftId(attendanceSchedulingDO.getAttendanceGroupShiftId());
attendanceService.calculatePunch(dto, vo);
vo.setAttendanceGroupId(activationGroup.getId());
vo.setUser(dto.getUser());
return vo;
}

View File

@ -289,4 +289,11 @@ public interface AdminUserService {
* @return
*/
List<AdminUserDO> selectByUserIds(Collection<Long> userIds);
/**
* 获取所有用户
*
* @return
*/
List<AdminUserDO> getAllList(Integer status, Integer type, List<Long> userIds);
}

View File

@ -26,6 +26,7 @@ import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import com.xingyuv.http.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
@ -587,4 +588,13 @@ public class AdminUserServiceImpl implements AdminUserService {
}
return userMapper.selectBatchIds(userIds);
}
@Override
public List<AdminUserDO> getAllList(Integer status, Integer type, List<Long> userIds) {
return userMapper.selectList(new LambdaQueryWrapper<AdminUserDO>()
.eq(status != null, AdminUserDO::getStatus, status)
.eq(type != null, AdminUserDO::getUserType, type)
.in(CollectionUtil.isNotEmpty(userIds), AdminUserDO::getId, userIds));
}
}