解决依赖循环问题/新增调整人员立即生效
This commit is contained in:
parent
e6292c3ae2
commit
965215996a
@ -72,14 +72,6 @@ public class AttendanceGroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/test")
|
|
||||||
@PermitAll
|
|
||||||
public CommonResult test() {
|
|
||||||
groupService.test();
|
|
||||||
return success("ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
@Operation(summary = "获得考勤组分页")
|
@Operation(summary = "获得考勤组分页")
|
||||||
@PreAuthorize("@ss.hasPermission('attendance:group:query')")
|
@PreAuthorize("@ss.hasPermission('attendance:group:query')")
|
||||||
|
@ -50,7 +50,7 @@ public class AttendanceGroupShiftController {
|
|||||||
return success(groupShiftService.createGroupShift(createReqVO));
|
return success(groupShiftService.createGroupShift(createReqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 2024/6/5 如果返回的有值 (判断不是空数组) - 那么前端 跳出提示框 (该班次已有考勤组在使用请选择更新方式) 下面两个按钮 立即生效 和 (推荐)次日生效
|
// 如果返回的有值 (判断不是空数组) - 那么前端 跳出提示框 (该班次已有考勤组在使用请选择更新方式) 下面两个按钮 立即生效 和 (推荐)次日生效
|
||||||
@PutMapping("/update")
|
@PutMapping("/update")
|
||||||
@Operation(summary = "更新考勤组班次")
|
@Operation(summary = "更新考勤组班次")
|
||||||
@PreAuthorize("@ss.hasPermission('attendance:group-shift:update')")
|
@PreAuthorize("@ss.hasPermission('attendance:group-shift:update')")
|
||||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserCreateOrDelVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserRespVO;
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserRespVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
|
||||||
@ -39,10 +40,17 @@ public class AttendanceGroupUserController {
|
|||||||
@PostMapping("/createOrDel")
|
@PostMapping("/createOrDel")
|
||||||
@Operation(summary = "创建删除考勤组人员")
|
@Operation(summary = "创建删除考勤组人员")
|
||||||
@PreAuthorize("@ss.hasPermission('attendance:group-user:create')")
|
@PreAuthorize("@ss.hasPermission('attendance:group-user:create')")
|
||||||
public CommonResult createOrDel(@RequestParam Long attendanceGroupId,
|
public CommonResult<AttendanceGroupUserCreateOrDelVO> createOrDel(@RequestParam Long attendanceGroupId,
|
||||||
@Valid @RequestBody List<Long> userIds) {
|
@Valid @RequestBody List<Long> userIds) {
|
||||||
groupUserService.createOrDel(attendanceGroupId, userIds);
|
AttendanceGroupUserCreateOrDelVO vo = groupUserService.createOrDel(attendanceGroupId, userIds);
|
||||||
return success("ok");
|
return success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/effectiveImmediately")
|
||||||
|
@Operation(summary = "立即生效")
|
||||||
|
public CommonResult effectiveImmediately(@RequestBody AttendanceGroupUserCreateOrDelVO vo) {
|
||||||
|
groupUserService.effectiveImmediately(vo);
|
||||||
|
return success(vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/update")
|
@PutMapping("/update")
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.controller.admin.groupuser.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AttendanceGroupUserCreateOrDelVO {
|
||||||
|
@Schema(description = "考勤组id")
|
||||||
|
private Long attendanceGroupId;
|
||||||
|
|
||||||
|
@Schema(description = "删除的用户")
|
||||||
|
private List<Long> delUserIds;
|
||||||
|
|
||||||
|
@Schema(description = "新增的用户")
|
||||||
|
private List<Long> saveUserIds;
|
||||||
|
}
|
@ -1,41 +1,17 @@
|
|||||||
package cn.iocoder.yudao.module.system.job.attendance;
|
package cn.iocoder.yudao.module.system.job.attendance;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
|
||||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.Constants;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
||||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
|
|
||||||
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.mysql.attendance.group.AttendanceGroupMapper;
|
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
|
|
||||||
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
|
|
||||||
import cn.iocoder.yudao.module.system.service.attendance.fixed.AttendanceFixedService;
|
|
||||||
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.punchrecord.AttendancePunchRecordService;
|
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
|
||||||
import cn.iocoder.yudao.module.system.service.attendance.scheduling.AttendanceSchedulingService;
|
|
||||||
import com.xxl.job.core.biz.model.ReturnT;
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -55,110 +31,17 @@ public class AttendanceStatisticsJob {
|
|||||||
* / -- 5. 如果我凌晨1点 跑 明天的数据 会有什么问题吗? 好像没什么问题 - 嗯
|
* / -- 5. 如果我凌晨1点 跑 明天的数据 会有什么问题吗? 好像没什么问题 - 嗯
|
||||||
*/
|
*/
|
||||||
@Resource
|
@Resource
|
||||||
private AttendanceService attendanceService;
|
|
||||||
@Resource
|
|
||||||
private AttendanceGroupMapper attendanceGroupMapper;
|
|
||||||
@Resource
|
|
||||||
private AttendanceGroupUserMapper attendanceGroupUserMapper;
|
|
||||||
@Resource
|
|
||||||
private AttendanceFixedService attendanceFixedService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AttendanceSchedulingService attendanceSchedulingService;
|
|
||||||
@Resource
|
|
||||||
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
|
|
||||||
@Resource
|
|
||||||
private AttendancePunchRecordService attendancePunchRecordService;
|
private AttendancePunchRecordService attendancePunchRecordService;
|
||||||
@Resource
|
|
||||||
private StringRedisTemplate stringRedisTemplate;
|
|
||||||
|
|
||||||
@XxlJob("attendanceStatisticsJob")
|
@XxlJob("attendanceStatisticsJob")
|
||||||
@TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
|
@TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
|
||||||
public ReturnT<String> execute() throws Exception {
|
public ReturnT<String> execute() throws Exception {
|
||||||
log.info("开始 考勤预设");
|
log.info("开始 考勤预设");
|
||||||
// 获取所有考勤组
|
|
||||||
List<AttendanceGroupDO> attendanceGroupDOS = attendanceGroupMapper.selectList();
|
|
||||||
// -- 根据考勤组ids 获取所有人员
|
|
||||||
List<AttendanceGroupUserDO> attendanceGroupUserDOS = attendanceGroupUserMapper.selectList();
|
|
||||||
//将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())));
|
|
||||||
// -- 获取考勤组下考勤规则 - 将将考勤组分组 - 按类型
|
|
||||||
LocalDateTime tomorrowLocalDateTime = LocalDateTimeUtil.offset(LocalDateTime.now(), 1, ChronoUnit.DAYS);
|
LocalDateTime tomorrowLocalDateTime = LocalDateTimeUtil.offset(LocalDateTime.now(), 1, ChronoUnit.DAYS);
|
||||||
LocalDateTime theDayAfterTomorrowLocalDateTime = LocalDateTimeUtil.offset(tomorrowLocalDateTime, 1, ChronoUnit.DAYS);
|
attendancePunchRecordService.defaultPersistence(Collections.emptyList(), tomorrowLocalDateTime);
|
||||||
String time = tomorrowLocalDateTime.format(Constants.REPO_DATE_FORMAT);
|
|
||||||
// 获取到考勤组 - 班次 key/value 格式
|
|
||||||
Map<Long, Long> map = this.getAttendanceGroupShiftIdGroupByGroup(attendanceGroupDOS, tomorrowLocalDateTime);
|
|
||||||
Map<Long, AttendanceGroupDO> groupMap = attendanceGroupDOS.stream().collect(Collectors.toMap(AttendanceGroupDO::getId, v -> v));
|
|
||||||
// -- 获取班次子表列表
|
|
||||||
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));
|
|
||||||
List<AttendancePunchRecordDO> attendancePunchRecordDOList = new ArrayList<>();
|
|
||||||
for (Map.Entry<Long, Long> entry : map.entrySet()) {
|
|
||||||
String key = Constants.ATTENDANCE + Constants.UNDERLINE + entry.getKey() + Constants.UNDERLINE; // + 时间
|
|
||||||
AttendanceGroupDO attendanceGroupDO = groupMap.get(entry.getKey());
|
|
||||||
List<Long> userIds = groupUserMap.get(entry.getKey());
|
|
||||||
if (CollectionUtil.isEmpty(userIds)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOS = itemMaps.get(entry.getValue());
|
|
||||||
if (CollectionUtil.isEmpty(attendanceGroupShiftItemDOS)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
List<AttendanceOnTheDayDTO> attendanceOnTheDayDTOS = attendanceService.buildAttendanceOnTheDay(attendanceGroupShiftItemDOS);
|
|
||||||
for (Long userId : userIds) {
|
|
||||||
for (AttendanceOnTheDayDTO attendanceOnTheDayDTO : attendanceOnTheDayDTOS) {
|
|
||||||
AttendancePunchRecordDO attendancePunchRecordDO = new AttendancePunchRecordDO();
|
|
||||||
attendancePunchRecordDO.setUserId(userId);
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupId(entry.getKey());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupName(attendanceGroupDO.getGroupName());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupShiftId(attendanceOnTheDayDTO.getKqAttendanceGroupShiftId());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupShiftName(attendanceOnTheDayDTO.getKqAttendanceGroupShiftName());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupShiftItemId(attendanceOnTheDayDTO.getId());
|
|
||||||
attendancePunchRecordDO.setType(attendanceGroupDO.getType());
|
|
||||||
attendancePunchRecordDO.setPunchType(attendanceGroupDO.getPunchType());
|
|
||||||
attendancePunchRecordDO.setWorkType(attendanceOnTheDayDTO.getType());
|
|
||||||
attendancePunchRecordDO.setLevel(attendanceOnTheDayDTO.getLevel());
|
|
||||||
attendancePunchRecordDO.setStatus(AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH);
|
|
||||||
attendancePunchRecordDO.setFieldServiceFlag(Constants.FALSE);
|
|
||||||
attendancePunchRecordDO.setNextDayFlag(Constants.TRUE);
|
|
||||||
attendancePunchRecordDO.setDayTime(time);
|
|
||||||
LocalDateTime shouldPunchTime = LocalDateTime.ofInstant(DateUtils.buildHHmmTime(attendanceOnTheDayDTO.getTime(),
|
|
||||||
(attendanceOnTheDayDTO.getNextDayFlag() == 0 ? tomorrowLocalDateTime : theDayAfterTomorrowLocalDateTime)).toInstant(), ZoneId.systemDefault());
|
|
||||||
attendancePunchRecordDO.setShouldPunchTime(shouldPunchTime);
|
|
||||||
attendancePunchRecordDO.setLatestPunchTime(shouldPunchTime.plusMinutes(attendanceOnTheDayDTO.getAfterPunchTime()));
|
|
||||||
attendancePunchRecordDOList.add(attendancePunchRecordDO);
|
|
||||||
}
|
|
||||||
stringRedisTemplate.opsForHash().put(key + time, userId, JSONUtil.toJsonStr(attendanceOnTheDayDTOS));
|
|
||||||
}
|
|
||||||
//设置缓存 2天
|
|
||||||
stringRedisTemplate.expire(key + time, 2, TimeUnit.DAYS);
|
|
||||||
}
|
|
||||||
// -- 批量
|
|
||||||
attendancePunchRecordService.saveBatch(attendancePunchRecordDOList);
|
|
||||||
}
|
|
||||||
log.info("结束 考勤预设");
|
log.info("结束 考勤预设");
|
||||||
// 返回执行成功
|
// 返回执行成功
|
||||||
return ReturnT.SUCCESS;
|
return ReturnT.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Long, Long> getAttendanceGroupShiftIdGroupByGroup(List<AttendanceGroupDO> attendanceGroupDOS, LocalDateTime localDateTime) {
|
|
||||||
Map<Long, Long> map = new HashMap<>();
|
|
||||||
List<AttendanceGroupDO> fixedList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(1)).collect(Collectors.toList());
|
|
||||||
List<AttendanceGroupDO> schedulingList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(2)).collect(Collectors.toList());
|
|
||||||
if (!fixedList.isEmpty()) {
|
|
||||||
Map<Long, Long> attendanceFixedMap = attendanceFixedService.getGroupToShiftIdMap(fixedList, localDateTime);
|
|
||||||
if (ObjectUtil.isNotEmpty(attendanceFixedMap)) {
|
|
||||||
map.putAll(attendanceFixedMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!schedulingList.isEmpty()) {
|
|
||||||
Map<Long, Long> attendanceSchedulingMap = attendanceSchedulingService.getGroupToShiftIdMap(schedulingList, localDateTime);
|
|
||||||
if (ObjectUtil.isNotEmpty(attendanceSchedulingMap)) {
|
|
||||||
map.putAll(attendanceSchedulingMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,6 @@ public interface AttendanceGroupService {
|
|||||||
*/
|
*/
|
||||||
AttendanceGroupDO getByUserId(Long userId);
|
AttendanceGroupDO getByUserId(Long userId);
|
||||||
|
|
||||||
void test();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有
|
* 获取所有
|
||||||
*
|
*
|
||||||
|
@ -126,70 +126,6 @@ public class AttendanceGroupServiceImpl implements AttendanceGroupService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void test() {
|
|
||||||
// 获取所有考勤组
|
|
||||||
List<AttendanceGroupDO> attendanceGroupDOS = attendanceGroupMapper.selectList();
|
|
||||||
// -- 根据考勤组ids 获取所有人员
|
|
||||||
List<AttendanceGroupUserDO> attendanceGroupUserDOS = attendanceGroupUserMapper.selectList();
|
|
||||||
//将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())));
|
|
||||||
// -- 获取考勤组下考勤规则 - 将将考勤组分组 - 按类型
|
|
||||||
LocalDateTime tomorrowLocalDateTime = LocalDateTime.now();
|
|
||||||
LocalDateTime theDayAfterTomorrowLocalDateTime = LocalDateTimeUtil.offset(tomorrowLocalDateTime, 1, ChronoUnit.DAYS);
|
|
||||||
|
|
||||||
String time = tomorrowLocalDateTime.format(Constants.REPO_DATE_FORMAT);
|
|
||||||
// 获取到考勤组 - 班次 key/value 格式
|
|
||||||
Map<Long, Long> map = this.getAttendanceGroupShiftIdGroupByGroup(attendanceGroupDOS, tomorrowLocalDateTime);
|
|
||||||
Map<Long, AttendanceGroupDO> groupMap = attendanceGroupDOS.stream().collect(Collectors.toMap(AttendanceGroupDO::getId, v -> v));
|
|
||||||
// -- 获取班次子表列表
|
|
||||||
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));
|
|
||||||
List<AttendancePunchRecordDO> attendancePunchRecordDOList = new ArrayList<>();
|
|
||||||
for (Map.Entry<Long, Long> entry : map.entrySet()) {
|
|
||||||
AttendanceGroupDO attendanceGroupDO = groupMap.get(entry.getKey());
|
|
||||||
List<Long> userIds = groupUserMap.get(entry.getKey());
|
|
||||||
if (CollectionUtil.isEmpty(userIds)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOS = itemMaps.get(entry.getValue());
|
|
||||||
if (CollectionUtil.isEmpty(attendanceGroupShiftItemDOS)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
List<AttendanceOnTheDayDTO> attendanceOnTheDayDTOS = attendanceService.buildAttendanceOnTheDay(attendanceGroupShiftItemDOS);
|
|
||||||
for (Long userId : userIds) {
|
|
||||||
for (AttendanceOnTheDayDTO attendanceOnTheDayDTO : attendanceOnTheDayDTOS) {
|
|
||||||
AttendancePunchRecordDO attendancePunchRecordDO = new AttendancePunchRecordDO();
|
|
||||||
attendancePunchRecordDO.setUserId(userId);
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupId(entry.getKey());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupName(attendanceGroupDO.getGroupName());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupShiftId(attendanceOnTheDayDTO.getKqAttendanceGroupShiftId());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupShiftName(attendanceOnTheDayDTO.getKqAttendanceGroupShiftName());
|
|
||||||
attendancePunchRecordDO.setAttendanceGroupShiftItemId(attendanceOnTheDayDTO.getId());
|
|
||||||
attendancePunchRecordDO.setType(attendanceGroupDO.getType());
|
|
||||||
attendancePunchRecordDO.setPunchType(attendanceGroupDO.getPunchType());
|
|
||||||
attendancePunchRecordDO.setWorkType(attendanceOnTheDayDTO.getType());
|
|
||||||
attendancePunchRecordDO.setLevel(attendanceOnTheDayDTO.getLevel());
|
|
||||||
attendancePunchRecordDO.setStatus(AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH);
|
|
||||||
attendancePunchRecordDO.setFieldServiceFlag(Constants.FALSE);
|
|
||||||
attendancePunchRecordDO.setNextDayFlag(Constants.TRUE);
|
|
||||||
attendancePunchRecordDO.setDayTime(time);
|
|
||||||
LocalDateTime shouldPunchTime = LocalDateTime.ofInstant(DateUtils.buildHHmmTime(attendanceOnTheDayDTO.getTime(),
|
|
||||||
(attendanceOnTheDayDTO.getNextDayFlag() == 0 ? tomorrowLocalDateTime : theDayAfterTomorrowLocalDateTime)).toInstant(), ZoneId.systemDefault());
|
|
||||||
attendancePunchRecordDO.setShouldPunchTime(shouldPunchTime);
|
|
||||||
attendancePunchRecordDO.setLatestPunchTime(shouldPunchTime.plusMinutes(attendanceOnTheDayDTO.getAfterPunchTime()));
|
|
||||||
|
|
||||||
attendancePunchRecordDOList.add(attendancePunchRecordDO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// -- 批量
|
|
||||||
attendancePunchRecordService.saveBatch(attendancePunchRecordDOList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AttendanceGroupDO> getAll() {
|
public List<AttendanceGroupDO> getAll() {
|
||||||
return attendanceGroupMapper.selectList();
|
return attendanceGroupMapper.selectList();
|
||||||
@ -205,24 +141,4 @@ public class AttendanceGroupServiceImpl implements AttendanceGroupService {
|
|||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Map<Long, Long> getAttendanceGroupShiftIdGroupByGroup(List<AttendanceGroupDO> attendanceGroupDOS, LocalDateTime localDateTime) {
|
|
||||||
Map<Long, Long> map = new HashMap<>();
|
|
||||||
List<AttendanceGroupDO> fixedList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(1)).collect(Collectors.toList());
|
|
||||||
List<AttendanceGroupDO> schedulingList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(2)).collect(Collectors.toList());
|
|
||||||
if (!fixedList.isEmpty()) {
|
|
||||||
Map<Long, Long> attendanceFixedMap = attendanceFixedService.getGroupToShiftIdMap(fixedList, localDateTime);
|
|
||||||
if (ObjectUtil.isNotEmpty(attendanceFixedMap)) {
|
|
||||||
map.putAll(attendanceFixedMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!schedulingList.isEmpty()) {
|
|
||||||
Map<Long, Long> attendanceSchedulingMap = attendanceSchedulingService.getGroupToShiftIdMap(schedulingList, localDateTime);
|
|
||||||
if (ObjectUtil.isNotEmpty(attendanceSchedulingMap)) {
|
|
||||||
map.putAll(attendanceSchedulingMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -69,6 +69,7 @@ public interface AttendanceGroupShiftService {
|
|||||||
List<AttendanceGroupShiftVO> listByShiftIds(List<Long> listByShiftIds);
|
List<AttendanceGroupShiftVO> listByShiftIds(List<Long> listByShiftIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 立即生效
|
||||||
*
|
*
|
||||||
* @param groupIds
|
* @param groupIds
|
||||||
*/
|
*/
|
||||||
|
@ -13,12 +13,15 @@ import cn.iocoder.yudao.module.system.controller.admin.groupshift.vo.AttendanceG
|
|||||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.fixed.AttendanceFixedDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.fixed.AttendanceFixedDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshift.AttendanceGroupShiftDO;
|
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.groupshiftitem.AttendanceGroupShiftItemDO;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.scheduling.AttendanceSchedulingDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.scheduling.AttendanceSchedulingDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.fixed.AttendanceFixedMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.fixed.AttendanceFixedMapper;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupshift.AttendanceGroupShiftMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupshift.AttendanceGroupShiftMapper;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupshiftitem.AttendanceGroupShiftItemMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupshiftitem.AttendanceGroupShiftItemMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.scheduling.AttendanceSchedulingMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.scheduling.AttendanceSchedulingMapper;
|
||||||
import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService;
|
import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService;
|
||||||
|
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
@ -57,7 +60,12 @@ public class AttendanceGroupShiftServiceImpl implements AttendanceGroupShiftServ
|
|||||||
private AttendanceGroupService attendanceGroupService;
|
private AttendanceGroupService attendanceGroupService;
|
||||||
@Resource
|
@Resource
|
||||||
private StringRedisTemplate stringRedisTemplate;
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
@Resource
|
||||||
|
@Lazy
|
||||||
|
private AttendancePunchRecordMapper attendancePunchRecordMapper;
|
||||||
|
@Resource
|
||||||
|
@Lazy
|
||||||
|
private AttendancePunchRecordService attendancePunchRecordService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@ -131,8 +139,6 @@ public class AttendanceGroupShiftServiceImpl implements AttendanceGroupShiftServ
|
|||||||
|
|
||||||
// -- 查询下有没有考勤组在用这个班次 - 如果有的话就要考虑更新 是立即更新 还是 次日更新
|
// -- 查询下有没有考勤组在用这个班次 - 如果有的话就要考虑更新 是立即更新 还是 次日更新
|
||||||
List<Long> useGroupIds = attendanceGroupService.getUseGroupIds(updateReqVO.getId());
|
List<Long> useGroupIds = attendanceGroupService.getUseGroupIds(updateReqVO.getId());
|
||||||
// TODO: 2024/6/5 如果考勤组没有使用班次 则不需要更新
|
|
||||||
|
|
||||||
|
|
||||||
boolean flag = false;
|
boolean flag = false;
|
||||||
if (CollectionUtil.isEmpty(oldItems)) {
|
if (CollectionUtil.isEmpty(oldItems)) {
|
||||||
@ -224,13 +230,27 @@ public class AttendanceGroupShiftServiceImpl implements AttendanceGroupShiftServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void effectiveImmediately(List<Long> groupIds) {
|
public void effectiveImmediately(List<Long> groupIds) {
|
||||||
String time = LocalDateTime.now().format(Constants.REPO_DATE_FORMAT);
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
String time = now.format(Constants.REPO_DATE_FORMAT);
|
||||||
|
String yesterdayStr = LocalDateTimeUtil.offset(now, 1, ChronoUnit.DAYS).format(Constants.REPO_DATE_FORMAT);
|
||||||
// TODO: 2024/6/5 删除当天redis中考勤记录 - 重新计算新的考勤记录到redis 和 数据库中
|
// TODO: 2024/6/5 删除当天redis中考勤记录 - 重新计算新的考勤记录到redis 和 数据库中
|
||||||
for (Long groupId : groupIds) {
|
for (Long groupId : groupIds) {
|
||||||
String key = Constants.ATTENDANCE + Constants.UNDERLINE + groupId + Constants.UNDERLINE; // + 时间
|
String key = Constants.ATTENDANCE + Constants.UNDERLINE + groupId + Constants.UNDERLINE; // + 时间
|
||||||
stringRedisTemplate.delete(key + time);
|
stringRedisTemplate.delete(key + time);
|
||||||
|
stringRedisTemplate.delete(key + yesterdayStr);
|
||||||
|
// -- 生成新的考勤记录到redis中 - 和数据库中(数据库中会有什么问题?) - 可能会导致两条数据一起更新 旧的数据和新的数据一起更新
|
||||||
|
// -- 如果不生成会导致什么问题 - 可能导致考勤组人员缺卡 从而导致统计的时候缺卡统计不到
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: 2024/6/6 这里如果慢的话可以异步处理
|
||||||
|
// -- 删除当前考勤组预留的考勤记录
|
||||||
|
attendancePunchRecordMapper.delete(new LambdaQueryWrapper<AttendancePunchRecordDO>()
|
||||||
|
.in(AttendancePunchRecordDO::getAttendanceGroupId, groupIds)
|
||||||
|
.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE));
|
||||||
|
// -- 重新计算 - 插入到redis 和数据中
|
||||||
|
attendancePunchRecordService.defaultPersistence(groupIds, LocalDateTime.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AttendanceGroupShiftVO> buildShift(List<AttendanceGroupShiftDO> dos) {
|
private List<AttendanceGroupShiftVO> buildShift(List<AttendanceGroupShiftDO> dos) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.system.service.attendance.groupuser;
|
package cn.iocoder.yudao.module.system.service.attendance.groupuser;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserCreateOrDelVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
||||||
@ -21,7 +22,7 @@ public interface AttendanceGroupUserService {
|
|||||||
* @param attendanceGroupId
|
* @param attendanceGroupId
|
||||||
* @param userIds
|
* @param userIds
|
||||||
*/
|
*/
|
||||||
void createOrDel(Long attendanceGroupId, List<Long> userIds);
|
AttendanceGroupUserCreateOrDelVO createOrDel(Long attendanceGroupId, List<Long> userIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新考勤组人员
|
* 更新考勤组人员
|
||||||
@ -60,4 +61,11 @@ public interface AttendanceGroupUserService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<Long> getUserIdsByGroupId(Long id);
|
List<Long> getUserIdsByGroupId(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人员调整立即生效
|
||||||
|
*
|
||||||
|
* @param vo
|
||||||
|
*/
|
||||||
|
void effectiveImmediately(AttendanceGroupUserCreateOrDelVO vo);
|
||||||
}
|
}
|
@ -1,18 +1,28 @@
|
|||||||
package cn.iocoder.yudao.module.system.service.attendance.groupuser;
|
package cn.iocoder.yudao.module.system.service.attendance.groupuser;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.Constants;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserCreateOrDelVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
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.mysql.attendance.groupuser.AttendanceGroupUserMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -30,39 +40,40 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AttendanceGroupUserMapper groupUserMapper;
|
private AttendanceGroupUserMapper groupUserMapper;
|
||||||
|
@Resource
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
@Resource
|
||||||
|
private AttendancePunchRecordMapper attendancePunchRecordMapper;
|
||||||
|
@Resource
|
||||||
|
private AttendancePunchRecordService attendancePunchRecordService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createOrDel(Long attendanceGroupId, List<Long> userIds) {
|
public AttendanceGroupUserCreateOrDelVO createOrDel(Long attendanceGroupId, List<Long> userIds) {
|
||||||
|
AttendanceGroupUserCreateOrDelVO vo = new AttendanceGroupUserCreateOrDelVO();
|
||||||
|
|
||||||
List<AttendanceGroupUserDO> groupUserList = groupUserMapper.selectList(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId);
|
List<AttendanceGroupUserDO> groupUserList = groupUserMapper.selectList(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId);
|
||||||
List<AttendanceGroupUserDO> list = new ArrayList<>();
|
List<AttendanceGroupUserDO> list = new ArrayList<>();
|
||||||
if (CollectionUtil.isEmpty(groupUserList)) {
|
|
||||||
if (CollectionUtil.isNotEmpty(userIds)) {
|
if (CollectionUtil.isEmpty(userIds)) {
|
||||||
for (Long userId : userIds) {
|
userIds = Collections.emptyList();
|
||||||
list.add(new AttendanceGroupUserDO().setUserId(userId).setAttendanceGroupId(attendanceGroupId));
|
|
||||||
}
|
|
||||||
groupUserMapper.insertBatch(list);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (CollectionUtil.isNotEmpty(userIds)) {
|
|
||||||
List<Long> oldUserIds = groupUserList.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
|
|
||||||
List<Long> delIds = new ArrayList<>(CollectionUtil.subtract(oldUserIds, userIds));
|
|
||||||
List<Long> saveIds = new ArrayList<>(CollectionUtil.subtract(userIds, oldUserIds));
|
|
||||||
if (CollectionUtil.isNotEmpty(delIds)) {
|
|
||||||
groupUserMapper.delete(new LambdaQueryWrapper<AttendanceGroupUserDO>().eq(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId)
|
|
||||||
.in(AttendanceGroupUserDO::getUserId, delIds));
|
|
||||||
}
|
|
||||||
if (CollectionUtil.isNotEmpty(saveIds)) {
|
|
||||||
for (Long userId : saveIds) {
|
|
||||||
list.add(new AttendanceGroupUserDO().setUserId(userId).setAttendanceGroupId(attendanceGroupId));
|
|
||||||
}
|
|
||||||
groupUserMapper.insertBatch(list);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
groupUserMapper.delete(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
List<Long> oldUserIds = groupUserList.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
|
||||||
|
List<Long> delIds = new ArrayList<>(CollectionUtil.subtract(oldUserIds, userIds));
|
||||||
|
List<Long> saveIds = new ArrayList<>(CollectionUtil.subtract(userIds, oldUserIds));
|
||||||
|
if (CollectionUtil.isNotEmpty(delIds)) {
|
||||||
|
groupUserMapper.delete(new LambdaQueryWrapper<AttendanceGroupUserDO>().eq(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId)
|
||||||
|
.in(AttendanceGroupUserDO::getUserId, delIds));
|
||||||
|
}
|
||||||
|
if (CollectionUtil.isNotEmpty(saveIds)) {
|
||||||
|
for (Long userId : saveIds) {
|
||||||
|
list.add(new AttendanceGroupUserDO().setUserId(userId).setAttendanceGroupId(attendanceGroupId));
|
||||||
|
}
|
||||||
|
groupUserMapper.insertBatch(list);
|
||||||
|
}
|
||||||
|
vo.setAttendanceGroupId(attendanceGroupId);
|
||||||
|
vo.setDelUserIds(delIds);
|
||||||
|
vo.setSaveUserIds(saveIds);
|
||||||
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -105,4 +116,25 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
|
|||||||
return list.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
|
return list.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void effectiveImmediately(AttendanceGroupUserCreateOrDelVO vo) {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
String time = now.format(Constants.REPO_DATE_FORMAT);
|
||||||
|
String yesterdayStr = LocalDateTimeUtil.offset(now, 1, ChronoUnit.DAYS).format(Constants.REPO_DATE_FORMAT);
|
||||||
|
// 删除掉redis 中的记录 -
|
||||||
|
if (CollectionUtil.isNotEmpty(vo.getDelUserIds())) {
|
||||||
|
String key = Constants.ATTENDANCE + Constants.UNDERLINE + vo.getAttendanceGroupId() + Constants.UNDERLINE; // + 时间
|
||||||
|
stringRedisTemplate.opsForHash().delete(key + time, vo.getDelUserIds().stream().map(String::valueOf).toArray(String[]::new));
|
||||||
|
stringRedisTemplate.opsForHash().delete(key + yesterdayStr, vo.getDelUserIds().stream().map(String::valueOf).toArray(String[]::new));
|
||||||
|
//删除掉这些人员在这个考勤组里的记录
|
||||||
|
attendancePunchRecordMapper.delete(new LambdaQueryWrapper<AttendancePunchRecordDO>()
|
||||||
|
.eq(AttendancePunchRecordDO::getAttendanceGroupId, vo.getAttendanceGroupId())
|
||||||
|
.in(AttendancePunchRecordDO::getUserId, vo.getDelUserIds())
|
||||||
|
.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE));
|
||||||
|
}
|
||||||
|
if (CollectionUtil.isNotEmpty(vo.getSaveUserIds())) {
|
||||||
|
attendancePunchRecordService.defaultPersistence(vo.getAttendanceGroupId(), vo.getSaveUserIds(), LocalDateTime.now());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,10 +3,15 @@ package cn.iocoder.yudao.module.system.service.attendance.punchrecord;
|
|||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
|
||||||
|
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.attendance.punchrecord.AttendancePunchRecordDO;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户打卡记录 Service 接口
|
* 用户打卡记录 Service 接口
|
||||||
@ -59,4 +64,34 @@ public interface AttendancePunchRecordService {
|
|||||||
* @param attendancePunchRecordDOList
|
* @param attendancePunchRecordDOList
|
||||||
*/
|
*/
|
||||||
void saveBatch(List<AttendancePunchRecordDO> attendancePunchRecordDOList);
|
void saveBatch(List<AttendancePunchRecordDO> attendancePunchRecordDOList);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预设考勤
|
||||||
|
* @param groupId
|
||||||
|
* @param userIds
|
||||||
|
* @param localDateTime
|
||||||
|
*/
|
||||||
|
void defaultPersistence(Long groupId, List<Long> userIds, LocalDateTime localDateTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预设考勤
|
||||||
|
*
|
||||||
|
* @param groupIds 考勤组ids
|
||||||
|
* @param localDateTime 时间
|
||||||
|
*/
|
||||||
|
void defaultPersistence(List<Long> groupIds, LocalDateTime localDateTime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预设持久化考勤
|
||||||
|
*
|
||||||
|
* @param map 获取到考勤组 - 班次 key/value 格式
|
||||||
|
* @param groupMap 考勤组id分map
|
||||||
|
* @param groupUserMap 考勤组id分组用户列表
|
||||||
|
* @param itemMaps 考勤班次子表根据考勤班次分组
|
||||||
|
* @param time 时间格式 yyyy-MM-dd
|
||||||
|
* @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);
|
||||||
}
|
}
|
@ -1,17 +1,45 @@
|
|||||||
package cn.iocoder.yudao.module.system.service.attendance.punchrecord;
|
package cn.iocoder.yudao.module.system.service.attendance.punchrecord;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.Constants;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
|
||||||
|
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.attendance.punchrecord.AttendancePunchRecordDO;
|
||||||
|
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;
|
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
|
||||||
|
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
|
||||||
|
import cn.iocoder.yudao.module.system.service.attendance.fixed.AttendanceFixedService;
|
||||||
|
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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
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.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.PUNCH_RECORD_NOT_EXISTS;
|
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.PUNCH_RECORD_NOT_EXISTS;
|
||||||
@ -27,6 +55,22 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AttendancePunchRecordMapper punchRecordMapper;
|
private AttendancePunchRecordMapper punchRecordMapper;
|
||||||
|
@Resource
|
||||||
|
@Lazy // 避免依赖循环
|
||||||
|
private AttendanceService attendanceService;
|
||||||
|
@Resource
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
@Resource
|
||||||
|
private AttendanceFixedService attendanceFixedService;
|
||||||
|
@Resource
|
||||||
|
private AttendanceSchedulingService attendanceSchedulingService;
|
||||||
|
@Resource
|
||||||
|
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
|
||||||
|
@Resource
|
||||||
|
private AttendanceGroupUserMapper attendanceGroupUserMapper;
|
||||||
|
@Resource
|
||||||
|
private AttendanceGroupMapper attendanceGroupMapper;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createPunchRecord(AttendancePunchRecordSaveReqVO createReqVO) {
|
public Long createPunchRecord(AttendancePunchRecordSaveReqVO createReqVO) {
|
||||||
@ -76,4 +120,134 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
|
|||||||
punchRecordMapper.insertBatch(attendancePunchRecordDOList);
|
punchRecordMapper.insertBatch(attendancePunchRecordDOList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void defaultPersistence(Long groupId, List<Long> userIds, LocalDateTime localDateTime) {
|
||||||
|
if (groupId == null || CollectionUtil.isEmpty(userIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AttendanceGroupDO attendanceGroupDO = attendanceGroupMapper.selectById(groupId);
|
||||||
|
List<AttendanceGroupDO> attendanceGroupDOS = new ArrayList<>();
|
||||||
|
attendanceGroupDOS.add(attendanceGroupDO);
|
||||||
|
|
||||||
|
List<AttendanceGroupUserDO> attendanceGroupUserDOS = attendanceGroupUserMapper.selectList(new LambdaQueryWrapper<AttendanceGroupUserDO>()
|
||||||
|
.eq(AttendanceGroupUserDO::getAttendanceGroupId, groupId)
|
||||||
|
.in(AttendanceGroupUserDO::getUserId, userIds));
|
||||||
|
this.defaultPersistence(attendanceGroupDOS, attendanceGroupUserDOS, localDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void defaultPersistence(List<Long> groupIds, LocalDateTime localDateTime) {
|
||||||
|
List<AttendanceGroupDO> attendanceGroupDOS;
|
||||||
|
List<AttendanceGroupUserDO> attendanceGroupUserDOS;
|
||||||
|
if (CollectionUtil.isNotEmpty(groupIds)) {
|
||||||
|
attendanceGroupDOS = attendanceGroupMapper.selectBatchIds(groupIds);
|
||||||
|
attendanceGroupUserDOS = attendanceGroupUserMapper.selectList(new LambdaQueryWrapper<AttendanceGroupUserDO>()
|
||||||
|
.in(AttendanceGroupUserDO::getAttendanceGroupId, groupIds));
|
||||||
|
} else {
|
||||||
|
attendanceGroupDOS = attendanceGroupMapper.selectList();
|
||||||
|
attendanceGroupUserDOS = attendanceGroupUserMapper.selectList();
|
||||||
|
}
|
||||||
|
this.defaultPersistence(attendanceGroupDOS, attendanceGroupUserDOS, localDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void defaultPersistence(List<AttendanceGroupDO> attendanceGroupDOS, List<AttendanceGroupUserDO> attendanceGroupUserDOS, LocalDateTime localDateTime) {
|
||||||
|
// 获取所有考勤组
|
||||||
|
// -- 根据考勤组ids 获取所有人员
|
||||||
|
//将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())));
|
||||||
|
// -- 获取考勤组下考勤规则 - 将将考勤组分组 - 按类型
|
||||||
|
String time = localDateTime.format(Constants.REPO_DATE_FORMAT);
|
||||||
|
// 获取到考勤组 - 班次 key/value 格式
|
||||||
|
Map<Long, Long> map = this.getAttendanceGroupShiftIdGroupByGroup(attendanceGroupDOS, localDateTime);
|
||||||
|
Map<Long, AttendanceGroupDO> groupMap = attendanceGroupDOS.stream().collect(Collectors.toMap(AttendanceGroupDO::getId, v -> v));
|
||||||
|
// -- 获取班次子表列表
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param map 获取到考勤组 - 班次 key/value 格式
|
||||||
|
* @param groupMap 考勤组id分map
|
||||||
|
* @param groupUserMap 考勤组id分组用户列表
|
||||||
|
* @param itemMaps 考勤班次子表根据考勤班次分组
|
||||||
|
* @param time 时间格式 yyyy-MM-dd
|
||||||
|
* @param localDateTime 需要预设的时间
|
||||||
|
*/
|
||||||
|
@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) {
|
||||||
|
List<AttendancePunchRecordDO> attendancePunchRecordDOList = new ArrayList<>();
|
||||||
|
LocalDateTime nextDayLocalDateTime = LocalDateTimeUtil.offset(localDateTime, 1, ChronoUnit.DAYS);
|
||||||
|
for (Map.Entry<Long, Long> entry : map.entrySet()) {
|
||||||
|
String key = Constants.ATTENDANCE + Constants.UNDERLINE + entry.getKey() + Constants.UNDERLINE; // + 时间
|
||||||
|
AttendanceGroupDO attendanceGroupDO = groupMap.get(entry.getKey());
|
||||||
|
List<Long> userIds = groupUserMap.get(entry.getKey());
|
||||||
|
if (CollectionUtil.isEmpty(userIds)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOS = itemMaps.get(entry.getValue());
|
||||||
|
if (CollectionUtil.isEmpty(attendanceGroupShiftItemDOS)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<AttendanceOnTheDayDTO> attendanceOnTheDayDTOS = attendanceService.buildAttendanceOnTheDay(attendanceGroupShiftItemDOS);
|
||||||
|
for (Long userId : userIds) {
|
||||||
|
for (AttendanceOnTheDayDTO attendanceOnTheDayDTO : attendanceOnTheDayDTOS) {
|
||||||
|
AttendancePunchRecordDO attendancePunchRecordDO = new AttendancePunchRecordDO();
|
||||||
|
attendancePunchRecordDO.setUserId(userId);
|
||||||
|
attendancePunchRecordDO.setAttendanceGroupId(entry.getKey());
|
||||||
|
attendancePunchRecordDO.setAttendanceGroupName(attendanceGroupDO.getGroupName());
|
||||||
|
attendancePunchRecordDO.setAttendanceGroupShiftId(attendanceOnTheDayDTO.getKqAttendanceGroupShiftId());
|
||||||
|
attendancePunchRecordDO.setAttendanceGroupShiftName(attendanceOnTheDayDTO.getKqAttendanceGroupShiftName());
|
||||||
|
attendancePunchRecordDO.setAttendanceGroupShiftItemId(attendanceOnTheDayDTO.getId());
|
||||||
|
attendancePunchRecordDO.setType(attendanceGroupDO.getType());
|
||||||
|
attendancePunchRecordDO.setPunchType(attendanceGroupDO.getPunchType());
|
||||||
|
attendancePunchRecordDO.setWorkType(attendanceOnTheDayDTO.getType());
|
||||||
|
attendancePunchRecordDO.setLevel(attendanceOnTheDayDTO.getLevel());
|
||||||
|
attendancePunchRecordDO.setStatus(AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH);
|
||||||
|
attendancePunchRecordDO.setFieldServiceFlag(Constants.FALSE);
|
||||||
|
attendancePunchRecordDO.setNextDayFlag(Constants.TRUE);
|
||||||
|
attendancePunchRecordDO.setDayTime(time);
|
||||||
|
LocalDateTime shouldPunchTime = LocalDateTime.ofInstant(DateUtils.buildHHmmTime(attendanceOnTheDayDTO.getTime(),
|
||||||
|
(attendanceOnTheDayDTO.getNextDayFlag() == 0 ? localDateTime : nextDayLocalDateTime)).toInstant(), ZoneId.systemDefault());
|
||||||
|
attendancePunchRecordDO.setShouldPunchTime(shouldPunchTime);
|
||||||
|
attendancePunchRecordDO.setLatestPunchTime(shouldPunchTime.plusMinutes(attendanceOnTheDayDTO.getAfterPunchTime()));
|
||||||
|
attendancePunchRecordDOList.add(attendancePunchRecordDO);
|
||||||
|
}
|
||||||
|
stringRedisTemplate.opsForHash().put(key + time, userId, JSONUtil.toJsonStr(attendanceOnTheDayDTOS));
|
||||||
|
}
|
||||||
|
//设置缓存 2天
|
||||||
|
stringRedisTemplate.expire(key + time, 2, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
// -- 批量
|
||||||
|
this.saveBatch(attendancePunchRecordDOList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Long, Long> getAttendanceGroupShiftIdGroupByGroup(List<AttendanceGroupDO> attendanceGroupDOS, LocalDateTime localDateTime) {
|
||||||
|
Map<Long, Long> map = new HashMap<>();
|
||||||
|
List<AttendanceGroupDO> fixedList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(1)).collect(Collectors.toList());
|
||||||
|
List<AttendanceGroupDO> schedulingList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(2)).collect(Collectors.toList());
|
||||||
|
if (!fixedList.isEmpty()) {
|
||||||
|
Map<Long, Long> attendanceFixedMap = attendanceFixedService.getGroupToShiftIdMap(fixedList, localDateTime);
|
||||||
|
if (ObjectUtil.isNotEmpty(attendanceFixedMap)) {
|
||||||
|
map.putAll(attendanceFixedMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!schedulingList.isEmpty()) {
|
||||||
|
Map<Long, Long> attendanceSchedulingMap = attendanceSchedulingService.getGroupToShiftIdMap(schedulingList, localDateTime);
|
||||||
|
if (ObjectUtil.isNotEmpty(attendanceSchedulingMap)) {
|
||||||
|
map.putAll(attendanceSchedulingMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user