```feat(考勤): 新增请假类型字段和相关逻辑在考勤模块中,为 punch 记录新增请假类型字段,并在服务中整合相关逻辑:

- 在AttendancePunchRecordDO和AttendancePunchRecordDTO中添加leaveType属性。
- 更新请假审批通过时的逻辑,以设置请假类型。- 在考勤报表中添加请假类型的处理,确保数据一致性和准确性。
- 引入字典数据以支持请假类型的映射和本地化显示。

BREAKING CHANGE: 在考勤表和相关DTO中新增字段leaveType,可能影响现有的数据库结构和依赖于旧结构的代码。需要进行相应的数据库更新和代码适配。
```
This commit is contained in:
aikai 2024-08-27 22:12:46 +08:00
parent 603c75f7ee
commit 458014331d
9 changed files with 86 additions and 37 deletions

View File

@ -16,6 +16,10 @@ public class BpmOALeaveDTO {
* 关联 AdminUserDO id 属性
*/
private Long userId;
/**
* 请假类型
*/
private String type;
/**
* 开始时间
*/

View File

@ -103,6 +103,7 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
.setStartTime(bpmOALeaveDO.getStartTime())
.setEndTime(bpmOALeaveDO.getEndTime())
.setLeaveId(id)
.setLeaveType(bpmOALeaveDO.getType())
);
if (!commonResult.isSuccess()) {
throw exception(FAILED_TO_APPLY_FOR_LEAVE);

View File

@ -29,4 +29,8 @@ public class AttendancePunchRecordDTO {
* 请假id 对应bpm_oa_leave表id
*/
private Long leaveId;
/**
* 请假类型
*/
private String leaveType;
}

View File

@ -9,7 +9,7 @@ import java.util.List;
@Data
@Accessors(chain = true)
public class AttendanceStatusByDayVO {
@Schema(description = "状态 0正常 1异常(迟到/早退/缺卡/请假/补卡)")
@Schema(description = "状态 0正常 1异常(迟到/早退/缺卡/请假)")
private Integer status;
@Schema(description = "是否有提交过 请假/加班/出差/外出/补卡 申请 0否 1是")
private Integer submitStatus = 0;

View File

@ -20,6 +20,9 @@ public class LogStatisticsDetailsListGroupByUserDTO {
@Schema(description = "部门id")
private Long deptId;
@Schema(description = "用户昵称")
private String nickName;
/**
* 时间列表
*/

View File

@ -150,6 +150,11 @@ public class AttendancePunchRecordDO extends BaseDO {
*/
private Long leaveId;
/**
* 请假类型
*/
private String leaveType;
@TableField(exist = false)
private String deptName;
}

View File

@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshift.Atten
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.dept.PostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
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.punchrecord.AttendancePunchRecordMapper;
@ -35,6 +36,7 @@ import cn.iocoder.yudao.module.system.service.attendance.groupuser.AttendanceGro
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.dict.DictDataService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
@ -96,6 +98,8 @@ public class AttendanceServiceImpl implements AttendanceService {
private AttendanceGroupUserService attendanceGroupUserService;
@Resource
private PostMapper postMapper;
@Resource
private DictDataService dictDataService;
// 定义一些常量以提高代码的可读性和可维护性
@ -113,6 +117,27 @@ public class AttendanceServiceImpl implements AttendanceService {
*/
private static final Integer UP_WORK = 0;
private static final Integer DOWN_WORK = 1;
private static final String NAME = "姓名";
private static final String ATTENDANCE_GROUP = "考勤组";
private static final String DEPT = "部门";
private static final String POSITION = "职位";
private static final String DATE = "日期";
private static final String SHIFT = "班次";
private static final String UP_WORK_STR = "上班";
private static final String DOWN_WORK_STR = "下班";
private static final String CHECK_IN_TIME = "打卡时间";
private static final String CHECK_IN_RESULT = "打卡结果";
private static final String LENGTH_OF_WORK = "工作时长";
private static final String LENGTH_OF_LATENESS = "迟到时长";
private static final String EARLY_DEPARTURE_DURATION = "早退时长";
private static final String NUMBER_OF_LEAVE_REQUESTS_AND_MISSING_CARDS = "请假漏卡次数";
private static final String NUMBER_OF_ABSENCES_AT_WORK = "上班缺卡次数";
private static final String NUMBER_OF_MISSING_CARDS_AFTER_GET_OFF_WORK = "下班缺卡次数";
private static final String NUMBER_OF_DAYS_OF_ATTENDANCE = "出勤天数";
private static final String REST_DAYS = "休息天数";
private static final String NUMBER_OF_TIMES_LATE = "迟到次数";
private static final String NUMBER_OF_EARLY_DEPARTURES = "早退次数";
private static final String NUMBER_OF_DAYS_ABSENT_FROM_WORK = "旷工天数";
@Override
public AttendancePunchPageVO getPunchPage(AttendancePunchPageDTO dto) {
@ -452,7 +477,6 @@ public class AttendanceServiceImpl implements AttendanceService {
List<Integer> statusList = Arrays.asList(AttendanceOnTheDayDTO.PUNCH_STATUS_LATE,
AttendanceOnTheDayDTO.PUNCH_STATUS_LEAVE_EARLY,
AttendanceOnTheDayDTO.PUNCH_STATUS_MISS,
AttendanceOnTheDayDTO.REPLACEMENT_CARD,
AttendanceOnTheDayDTO.ASK_FOR_LEAVE
);
for (Map.Entry<String, List<AttendancePunchRecordDO>> entry : collect.entrySet()) {
@ -1038,7 +1062,9 @@ public class AttendanceServiceImpl implements AttendanceService {
List<List<String>> data = new ArrayList<>();
// -- 根据部门分组 - 根据考勤组分组
Map<Long, List<AttendancePunchRecordDO>> userPunchMap = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getUserId));
List<DictDataDO> bpmOaLeaveType = dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), "bpm_oa_leave_type");
//根据字典值分组
Map<String, String> leaveTypeMap = bpmOaLeaveType.stream().collect(Collectors.toMap(DictDataDO::getValue, DictDataDO::getLabel));
// -- 先计算下要循环几次 - 一个用户一个部门一个考勤组一个班次一个日期 最大的打卡次数 -
Map<String, List<AttendancePunchRecordDO>> map = list.stream().collect(Collectors.groupingBy(
a -> a.getUserId() + "_"
@ -1083,11 +1109,12 @@ public class AttendanceServiceImpl implements AttendanceService {
row.add(dateStr);
row.add(CollectionUtil.isEmpty(groupShiftEntry.getValue()) ? "休息" : groupShiftEntry.getValue().get(0).getAttendanceGroupShiftName());
Map<Long, List<AttendancePunchRecordDO>> workMap = groupShiftEntry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupShiftItemId, TreeMap::new, Collectors.toList()));
// TODO: 2024/7/2 这里可能会有排序问题 具体看数据在调试
for (Map.Entry<Long, List<AttendancePunchRecordDO>> groupShiftItemEntry : workMap.entrySet()) {
for (AttendancePunchRecordDO attendancePunchRecordDO : groupShiftItemEntry.getValue()) {
row.add(attendancePunchRecordDO.getPunchTime() == null ? "/" : attendancePunchRecordDO.getPunchTime().format(Constants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
row.add(this.statusToStr(attendancePunchRecordDO.getStatus()));
String statusStr = attendancePunchRecordDO.getStatus().equals(AttendanceOnTheDayDTO.ASK_FOR_LEAVE) ? "请假-" + leaveTypeMap.get(attendancePunchRecordDO.getLeaveType()) : this.statusToStr(attendancePunchRecordDO.getStatus());
row.add(statusStr);
}
}
if (maxSize > workMap.entrySet().size()) {
@ -1291,21 +1318,21 @@ public class AttendanceServiceImpl implements AttendanceService {
public static List<List<String>> generateHead(String headTitle, String detailedHead) {
List<List<String>> head = new ArrayList<>();
head.add(Arrays.asList(headTitle, detailedHead, "姓名", "姓名"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤组", "考勤组"));
head.add(Arrays.asList(headTitle, detailedHead, "部门", "部门"));
head.add(Arrays.asList(headTitle, detailedHead, "职位", "职位"));
head.add(Arrays.asList(headTitle, detailedHead, "出勤天数", "出勤天数"));
head.add(Arrays.asList(headTitle, detailedHead, "休息天数", "休息天数"));
head.add(Arrays.asList(headTitle, detailedHead, "工作时长", "工作时长"));
head.add(Arrays.asList(headTitle, detailedHead, "迟到次数", "迟到次数"));
head.add(Arrays.asList(headTitle, detailedHead, "迟到时长", "迟到时长"));
head.add(Arrays.asList(headTitle, detailedHead, "早退次数", "早退次数"));
head.add(Arrays.asList(headTitle, detailedHead, "早退时长", "早退时长"));
head.add(Arrays.asList(headTitle, detailedHead, "请假漏卡次数", "请假漏卡次数"));
head.add(Arrays.asList(headTitle, detailedHead, "上班缺卡次数", "上班缺卡次数"));
head.add(Arrays.asList(headTitle, detailedHead, "下班缺卡次数", "下班缺卡次数"));
head.add(Arrays.asList(headTitle, detailedHead, "旷工天数", "旷工天数"));
head.add(Arrays.asList(headTitle, detailedHead, NAME, NAME));
head.add(Arrays.asList(headTitle, detailedHead, ATTENDANCE_GROUP, ATTENDANCE_GROUP));
head.add(Arrays.asList(headTitle, detailedHead, DEPT, DEPT));
head.add(Arrays.asList(headTitle, detailedHead, POSITION, POSITION));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_DAYS_OF_ATTENDANCE, NUMBER_OF_DAYS_OF_ATTENDANCE));
head.add(Arrays.asList(headTitle, detailedHead, REST_DAYS, REST_DAYS));
head.add(Arrays.asList(headTitle, detailedHead, LENGTH_OF_WORK, LENGTH_OF_WORK));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_TIMES_LATE, NUMBER_OF_TIMES_LATE));
head.add(Arrays.asList(headTitle, detailedHead, LENGTH_OF_LATENESS, LENGTH_OF_LATENESS));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_EARLY_DEPARTURES, NUMBER_OF_EARLY_DEPARTURES));
head.add(Arrays.asList(headTitle, detailedHead, EARLY_DEPARTURE_DURATION, EARLY_DEPARTURE_DURATION));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_LEAVE_REQUESTS_AND_MISSING_CARDS, NUMBER_OF_LEAVE_REQUESTS_AND_MISSING_CARDS));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_ABSENCES_AT_WORK, NUMBER_OF_ABSENCES_AT_WORK));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_MISSING_CARDS_AFTER_GET_OFF_WORK, NUMBER_OF_MISSING_CARDS_AFTER_GET_OFF_WORK));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_DAYS_ABSENT_FROM_WORK, NUMBER_OF_DAYS_ABSENT_FROM_WORK));
// head.add(Arrays.asList(headTitle, detailedHead, "出差时长", "出差时长"));
// head.add(Arrays.asList(headTitle, detailedHead, "外出时长", "外出时长"));
// head.add(Arrays.asList(headTitle, detailedHead, "加班-审批单统计", "加班-审批单统计"));
@ -1327,29 +1354,29 @@ public class AttendanceServiceImpl implements AttendanceService {
public static List<List<String>> generateDailyHead(String headTitle, String detailedHead, int size) {
List<List<String>> head = new ArrayList<>();
head.add(Arrays.asList(headTitle, detailedHead, "姓名", "姓名"));
head.add(Arrays.asList(headTitle, detailedHead, "考勤组", "考勤组"));
head.add(Arrays.asList(headTitle, detailedHead, "部门", "部门"));
head.add(Arrays.asList(headTitle, detailedHead, "职位", "职位"));
head.add(Arrays.asList(headTitle, detailedHead, "日期", "日期"));
head.add(Arrays.asList(headTitle, detailedHead, "班次", "班次"));
head.add(Arrays.asList(headTitle, detailedHead, NAME, NAME));
head.add(Arrays.asList(headTitle, detailedHead, ATTENDANCE_GROUP, ATTENDANCE_GROUP));
head.add(Arrays.asList(headTitle, detailedHead, DEPT, DEPT));
head.add(Arrays.asList(headTitle, detailedHead, POSITION, POSITION));
head.add(Arrays.asList(headTitle, detailedHead, DATE, DATE));
head.add(Arrays.asList(headTitle, detailedHead, SHIFT, SHIFT));
for (int i = 1; i <= size; i++) {
head.add(Arrays.asList(headTitle, detailedHead, "上班" + i + "打卡时间", "上班" + i + "打卡时间"));
head.add(Arrays.asList(headTitle, detailedHead, "上班" + i + "打卡结果", "上班" + i + "打卡结果"));
head.add(Arrays.asList(headTitle, detailedHead, "下班" + i + "打卡时间", "下班" + i + "打卡时间"));
head.add(Arrays.asList(headTitle, detailedHead, "下班" + i + "打卡结果", "下班" + i + "打卡结果"));
head.add(Arrays.asList(headTitle, detailedHead, UP_WORK_STR + i + CHECK_IN_TIME, UP_WORK_STR + i + CHECK_IN_TIME));
head.add(Arrays.asList(headTitle, detailedHead, UP_WORK_STR + i + CHECK_IN_RESULT, UP_WORK_STR + i + CHECK_IN_RESULT));
head.add(Arrays.asList(headTitle, detailedHead, DOWN_WORK_STR + i + CHECK_IN_TIME, DOWN_WORK_STR + i + CHECK_IN_TIME));
head.add(Arrays.asList(headTitle, detailedHead, DOWN_WORK_STR + i + CHECK_IN_RESULT, DOWN_WORK_STR + i + CHECK_IN_RESULT));
}
// head.add(Arrays.asList(headTitle, detailedHead, "关联的审批单", "关联的审批单"));
// head.add(Arrays.asList(headTitle, detailedHead, "出勤天数", "出勤天数"));
// head.add(Arrays.asList(headTitle, detailedHead, "休息天数", "休息天数"));
head.add(Arrays.asList(headTitle, detailedHead, "工作时长", "工作时长"));
head.add(Arrays.asList(headTitle, detailedHead, LENGTH_OF_WORK, LENGTH_OF_WORK));
// head.add(Arrays.asList(headTitle, detailedHead, "迟到次数", "迟到次数"));
head.add(Arrays.asList(headTitle, detailedHead, "迟到时长", "迟到时长"));
head.add(Arrays.asList(headTitle, detailedHead, LENGTH_OF_LATENESS, LENGTH_OF_LATENESS));
// head.add(Arrays.asList(headTitle, detailedHead, "早退次数", "早退次数"));
head.add(Arrays.asList(headTitle, detailedHead, "早退时长", "早退时长"));
head.add(Arrays.asList(headTitle, detailedHead, "请假漏卡次数", "请假漏卡次数"));
head.add(Arrays.asList(headTitle, detailedHead, "上班缺卡次数", "上班缺卡次数"));
head.add(Arrays.asList(headTitle, detailedHead, "下班缺卡次数", "下班缺卡次数"));
head.add(Arrays.asList(headTitle, detailedHead, EARLY_DEPARTURE_DURATION, EARLY_DEPARTURE_DURATION));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_LEAVE_REQUESTS_AND_MISSING_CARDS, NUMBER_OF_LEAVE_REQUESTS_AND_MISSING_CARDS));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_ABSENCES_AT_WORK, NUMBER_OF_ABSENCES_AT_WORK));
head.add(Arrays.asList(headTitle, detailedHead, NUMBER_OF_MISSING_CARDS_AFTER_GET_OFF_WORK, NUMBER_OF_MISSING_CARDS_AFTER_GET_OFF_WORK));
// head.add(Arrays.asList(headTitle, detailedHead, "旷工天数", "旷工天数"));
return head;
}

View File

@ -256,6 +256,7 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
(dto.getEndTime().isAfter(shouldPunchTime) || dto.getEndTime().equals(shouldPunchTime))) {
attendancePunchRecordDO.setStatus(AttendanceOnTheDayDTO.ASK_FOR_LEAVE);
attendancePunchRecordDO.setLeaveId(dto.getId());
attendancePunchRecordDO.setLeaveType(dto.getType());
} else if (dto.getEndTime().isBefore(shouldPunchTime)) {
leaveIds.add(dto.getId().toString());
}
@ -325,7 +326,8 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
public void askingForLeaveAfterwardsToModifyAttendance(AttendancePunchRecordDTO dto) {
punchRecordMapper.update(new AttendancePunchRecordDO()
.setStatus(AttendanceOnTheDayDTO.ASK_FOR_LEAVE)
.setLeaveId(dto.getLeaveId()),
.setLeaveId(dto.getLeaveId())
.setLeaveType(dto.getLeaveType()),
new LambdaUpdateWrapper<AttendancePunchRecordDO>().eq(AttendancePunchRecordDO::getUserId, dto.getUserId())
.ge(AttendancePunchRecordDO::getShouldPunchTime, dto.getStartTime())
.le(AttendancePunchRecordDO::getShouldPunchTime, dto.getEndTime()));

View File

@ -169,6 +169,9 @@
#{date}
</foreach>
</if>
<if test="dto.nickName != null and dto.nickName != ''">
and c.nickname like concat('%', #{dto.nickName}, '%')
</if>
<if test="dto.type != null">
and b.type = #{dto.type}
</if>