Merge branch 'dev' into frx
This commit is contained in:
commit
9c4d7b8a40
@ -1,5 +1,7 @@
|
||||
package cn.iocoder.yudao.framework.common.util.date;
|
||||
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
@ -262,10 +264,9 @@ public class DateUtils {
|
||||
*/
|
||||
public static List<String> betweenDayList(Date beginTime, Date endTime) {
|
||||
List<String> list = new ArrayList<>();
|
||||
int num = (int) DateUtil.betweenDay(beginTime, endTime, true);
|
||||
for (int i = 0; i <= num; i++) {
|
||||
Date time = DateUtil.offsetDay(beginTime, i).toJdkDate();
|
||||
list.add(DateUtil.format(time, "yyyy-MM-dd"));
|
||||
List<DateTime> dateTimes = DateUtil.rangeToList(beginTime, endTime, DateField.DAY_OF_MONTH);
|
||||
for (DateTime dateTime : dateTimes) {
|
||||
list.add(dateTime.toDateStr());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
@ -193,6 +193,8 @@ public interface ErrorCodeConstants {
|
||||
|
||||
ErrorCode ATTENDANCE_TIME_NOT_ARRIVED = new ErrorCode(1_003_010_000, "未到考勤时间");
|
||||
|
||||
ErrorCode THE_START_TIME_CANNOT_BE_GREATER_THAN_THE_END_TIME = new ErrorCode(1_003_011_000, "开始时间不可大于结束时间!");
|
||||
|
||||
ErrorCode LOG_FORM_NOT_USE = new ErrorCode(1_009_010_004, "你不用使用该日志模板");
|
||||
|
||||
ErrorCode LOG_USE_NOT_EXISTS = new ErrorCode(1_009_010_005, "模板不存在");
|
||||
|
@ -56,7 +56,6 @@ public class AttendanceFixedController {
|
||||
|
||||
@GetMapping("/getListByGroupId")
|
||||
@Operation(summary = "根据考勤组ID获得固定班制考勤设置列表")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:fixed:query')")
|
||||
public CommonResult<List<AttendanceFixedRespVO>> getListByGroupId(@RequestParam Long attendanceGroupId) {
|
||||
List<AttendanceFixedRespVO> list = fixedService.getListByGroupId(attendanceGroupId);
|
||||
return success(list);
|
||||
|
@ -70,6 +70,15 @@ public class AttendanceGroupController {
|
||||
return success(BeanUtils.toBean(group, AttendanceGroupRespVO.class));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/test")
|
||||
@Operation(summary = "测试")
|
||||
public CommonResult test() {
|
||||
groupService.test();
|
||||
return success("ok");
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得考勤组分页")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:group:query')")
|
||||
|
@ -1,32 +1,31 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.groupuser;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import javax.validation.*;
|
||||
import javax.servlet.http.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
|
||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
|
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.*;
|
||||
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.AttendanceGroupUserSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
||||
import cn.iocoder.yudao.module.system.service.attendance.groupuser.AttendanceGroupUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||
|
||||
@Tag(name = "管理后台 - 考勤组人员")
|
||||
@RestController
|
||||
@ -37,11 +36,13 @@ public class AttendanceGroupUserController {
|
||||
@Resource
|
||||
private AttendanceGroupUserService groupUserService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建考勤组人员")
|
||||
@PostMapping("/createOrDel")
|
||||
@Operation(summary = "创建删除考勤组人员")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:group-user:create')")
|
||||
public CommonResult<Long> createGroupUser(@Valid @RequestBody AttendanceGroupUserSaveReqVO createReqVO) {
|
||||
return success(groupUserService.createGroupUser(createReqVO));
|
||||
public CommonResult createOrDel(@RequestParam Long attendanceGroupId,
|
||||
@Valid @RequestBody List<Long> userIds) {
|
||||
groupUserService.createOrDel(attendanceGroupId, userIds);
|
||||
return success("ok");
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@ -70,6 +71,15 @@ public class AttendanceGroupUserController {
|
||||
return success(BeanUtils.toBean(groupUser, AttendanceGroupUserRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/getUserIdsByGroupId")
|
||||
@Operation(summary = "通过考勤组id获得考勤组人员Ids")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:group-user:query')")
|
||||
public CommonResult<List<Long>> getUserIdsByGroupId(@RequestParam("id") Long id) {
|
||||
List<Long> userIds = groupUserService.getUserIdsByGroupId(id);
|
||||
return success(userIds);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得考勤组人员分页")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:group-user:query')")
|
||||
@ -83,12 +93,12 @@ public class AttendanceGroupUserController {
|
||||
@PreAuthorize("@ss.hasPermission('attendance:group-user:export')")
|
||||
@OperateLog(type = EXPORT)
|
||||
public void exportGroupUserExcel(@Valid AttendanceGroupUserPageReqVO pageReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
HttpServletResponse response) throws IOException {
|
||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<AttendanceGroupUserDO> list = groupUserService.getGroupUserPage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "考勤组人员.xls", "数据", AttendanceGroupUserRespVO.class,
|
||||
BeanUtils.toBean(list, AttendanceGroupUserRespVO.class));
|
||||
BeanUtils.toBean(list, AttendanceGroupUserRespVO.class));
|
||||
}
|
||||
|
||||
}
|
@ -44,6 +44,9 @@ public class AttendancePunchRecordPageReqVO extends PageParam {
|
||||
@Schema(description = "打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) 5补卡", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "明天的打卡 0否 1是 (业务需要 先把明天的打卡统计出来)", example = "1")
|
||||
private Integer nextDayFlag;
|
||||
|
||||
@Schema(description = "是否外勤 0否 1是", example = "1")
|
||||
private Integer fieldServiceFlag;
|
||||
|
||||
|
@ -53,6 +53,10 @@ public class AttendancePunchRecordRespVO {
|
||||
@ExcelProperty("打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) 5补卡")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "明天的打卡 0否 1是 (业务需要 先把明天的打卡统计出来)", example = "1")
|
||||
@ExcelProperty("明天的打卡 0否 1是 (业务需要 先把明天的打卡统计出来)")
|
||||
private Integer nextDayFlag;
|
||||
|
||||
@Schema(description = "是否外勤 0否 1是", example = "1")
|
||||
@ExcelProperty("是否外勤 0否 1是")
|
||||
private Integer fieldServiceFlag;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@ -40,6 +41,9 @@ public class AttendancePunchRecordSaveReqVO {
|
||||
@Schema(description = "打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) 5补卡", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "明天的打卡 0否 1是 (业务需要 先把明天的打卡统计出来)", example = "1")
|
||||
private Integer nextDayFlag;
|
||||
|
||||
@Schema(description = "是否外勤 0否 1是", example = "1")
|
||||
private Integer fieldServiceFlag;
|
||||
|
||||
|
@ -38,7 +38,6 @@ public class AttendanceSchedulingController {
|
||||
|
||||
@PostMapping("/batchCreateOrUpdate")
|
||||
@Operation(summary = "批量新增修改排班制考勤设置")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:scheduling:create')")
|
||||
public CommonResult batchCreateOrUpdate(@RequestParam Long attendanceGroupId,
|
||||
@Valid @RequestBody List<AttendanceSchedulingSaveReqVO> createReqVO) {
|
||||
schedulingService.batchCreateOrUpdate(attendanceGroupId, createReqVO);
|
||||
@ -48,7 +47,6 @@ public class AttendanceSchedulingController {
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得排班制考勤设置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:scheduling:query')")
|
||||
public CommonResult<AttendanceSchedulingRespVO> getScheduling(@RequestParam("id") Long id) {
|
||||
AttendanceSchedulingDO scheduling = schedulingService.getScheduling(id);
|
||||
return success(BeanUtils.toBean(scheduling, AttendanceSchedulingRespVO.class));
|
||||
@ -56,7 +54,6 @@ public class AttendanceSchedulingController {
|
||||
|
||||
@GetMapping("/getListByGroupId")
|
||||
@Operation(summary = "根据考勤id获取排版制设置列表")
|
||||
@PreAuthorize("@ss.getListByGroupId('attendance:scheduling:query')")
|
||||
public CommonResult<List<AttendanceSchedulingRespVO>> getListByGroupId(@RequestParam("id") Long attendanceGroupId) {
|
||||
List<AttendanceSchedulingRespVO> vos = schedulingService.getListByGroupId(attendanceGroupId);
|
||||
return success(vos);
|
||||
@ -64,7 +61,6 @@ public class AttendanceSchedulingController {
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得排班制考勤设置分页")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:scheduling:query')")
|
||||
public CommonResult<PageResult<AttendanceSchedulingRespVO>> getSchedulingPage(@Valid AttendanceSchedulingPageReqVO pageReqVO) {
|
||||
PageResult<AttendanceSchedulingDO> pageResult = schedulingService.getSchedulingPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AttendanceSchedulingRespVO.class));
|
||||
@ -72,7 +68,6 @@ public class AttendanceSchedulingController {
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出排班制考勤设置 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('attendance:scheduling:export')")
|
||||
@OperateLog(type = EXPORT)
|
||||
public void exportSchedulingExcel(@Valid AttendanceSchedulingPageReqVO pageReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
|
@ -1,12 +1,16 @@
|
||||
package cn.iocoder.yudao.module.system.controller.app.attendance;
|
||||
|
||||
import cn.hutool.json.JSON;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
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.AttendanceStatisticsDTO;
|
||||
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.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
|
||||
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@ -14,9 +18,11 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "考勤 App - 考勤管理")
|
||||
@RestController
|
||||
@ -40,10 +46,17 @@ public class AttendanceController {
|
||||
return success(vo);
|
||||
}
|
||||
|
||||
@PostMapping("/statistics")
|
||||
@Operation(summary = "统计")
|
||||
public CommonResult<AttendanceStatisticsVO> statistics(@RequestBody AttendanceStatisticsDTO dto) {
|
||||
AttendanceStatisticsVO vo = attendanceService.statistics(dto);
|
||||
@GetMapping("/statisticsByDay")
|
||||
@Operation(summary = "统计按天")
|
||||
public CommonResult<Map<String, List<AttendancePunchRecordDO>>> statisticsByDay(@ModelAttribute AttendanceStatisticsByDayDTO dto) {
|
||||
Map<String, List<AttendancePunchRecordDO>> vo = attendanceService.statisticsByDay(dto);
|
||||
return success(vo);
|
||||
}
|
||||
|
||||
@GetMapping("/statisticsByCycle")
|
||||
@Operation(summary = "统计按周期")
|
||||
public CommonResult<AttendanceStatisticsVO> statisticsByCycle(@ModelAttribute @Valid AttendanceStatisticsByCycleDTO dto) {
|
||||
AttendanceStatisticsVO vo = attendanceService.statisticsByCycle(dto);
|
||||
return success(vo);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
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.NonNull;
|
||||
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 AttendanceStatisticsByCycleDTO {
|
||||
@Schema(description = "用户id")
|
||||
private Long userId = getLoginUserId();
|
||||
|
||||
@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;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
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 AttendanceStatisticsByDayDTO {
|
||||
@Schema(description = "用户id")
|
||||
private Long userId = getLoginUserId();
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT)
|
||||
@Schema(description = "当前查看的时间 (默认当天 按周或者按月 传周/月 开始时间过来即可)")
|
||||
private Date time = new Date();
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package cn.iocoder.yudao.module.system.controller.app.attendance.dto;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AttendanceStatisticsDTO {
|
||||
/**
|
||||
* 类型 0按天(默认) 1按周 2按月
|
||||
*/
|
||||
public static final Integer TYPE_DAY = 0;
|
||||
public static final Integer TYPE_WEEK = 1;
|
||||
public static final Integer TYPE_MONTH = 2;
|
||||
|
||||
@Schema(description = "类型 0按天(默认) 1按周 2按月")
|
||||
private Integer type = 0;
|
||||
|
||||
@Schema(description = "当前查看的时间 (默认当天 按周或者按月 传周/月 开始时间过来即可)")
|
||||
private String time = DatePattern.NORM_DATE_FORMAT.format(LocalDateTime.now());
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
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 AttendancePunchStatisticsVO {
|
||||
@Schema(description = "日期 yyyy-MM-dd")
|
||||
private String day;
|
||||
|
||||
@Schema(description = "周几")
|
||||
private String week;
|
||||
|
||||
@Schema(description = "应打卡时间 HH:mm")
|
||||
private String shouldPunchTime;
|
||||
|
||||
@Schema(description = "业务时间 前端直接展示即可 例子:(11.5小时 / 上班迟到1小时14分钟)")
|
||||
private String time;
|
||||
}
|
@ -5,15 +5,54 @@ import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AttendanceStatisticsVO {
|
||||
@Schema(description = "按天响应对象 key为日期 yyyy-MM-dd value为状态 0正常 1异常")
|
||||
private Map<String, Integer> statisticsStatusByDayMap;
|
||||
|
||||
@Schema(description = "按天响应对象 key为日期 yyyy-MM-dd value为状态 0正常 1异常")
|
||||
private Map<String, List<AttendancePunchVO>> statisticsDataByDayMap;
|
||||
@Schema(description = "平均工作时间")
|
||||
private List<AttendancePunchStatisticsVO> averageWorkingHours;
|
||||
@Schema(description = "出勤天数")
|
||||
private List<AttendancePunchStatisticsVO> attendanceDays;
|
||||
@Schema(description = "迟到次数")
|
||||
private List<AttendancePunchStatisticsVO> beLateNumber;
|
||||
@Schema(description = "早退次数")
|
||||
private List<AttendancePunchStatisticsVO> earlyDeparturesNumber;
|
||||
@Schema(description = "缺卡次数")
|
||||
private List<AttendancePunchStatisticsVO> missingCardsNumber;
|
||||
@Schema(description = "矿工日")
|
||||
private List<AttendancePunchStatisticsVO> minerDays;
|
||||
@Schema(description = "外勤次数")
|
||||
private List<AttendancePunchStatisticsVO> fieldServiceNumber;
|
||||
@Schema(description = "休息日")
|
||||
private List<AttendancePunchStatisticsVO> restDays;
|
||||
@Schema(description = "头部次数")
|
||||
private CalculateNum calculateNum;
|
||||
|
||||
@Data
|
||||
public static class CalculateNum {
|
||||
// 总考勤时间
|
||||
long totalWorkingHours = 0L;
|
||||
// 总出勤天数
|
||||
int totalAttendanceDays = 0;
|
||||
// 总休息天数
|
||||
int totalRestDays = 0;
|
||||
// 迟到总次数
|
||||
int totalLateArrivalsNumber = 0;
|
||||
// 迟到总时间
|
||||
long totalLateArrivalsTime = 0L;
|
||||
// 早退总次数
|
||||
int totalEarlyDeparturesNumber = 0;
|
||||
// 早退总时间
|
||||
long totalEarlyDeparturesTime = 0L;
|
||||
// 缺卡总次数
|
||||
int totalMissingCardsNumber = 0;
|
||||
// 矿工总天数
|
||||
int totalMinerDays = 0;
|
||||
// 外勤次数
|
||||
int totalFieldServiceNumber = 0;
|
||||
// 平均工时
|
||||
long averageWorkingHours = 0L;
|
||||
// 平均工时
|
||||
String averageWorkingHoursStr;
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,12 @@ public class AttendancePunchRecordDO extends BaseDO {
|
||||
* 打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) 5补卡
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 明天的打卡 0否 1是 (业务需要 先把明天的打卡统计出来)
|
||||
*/
|
||||
private Integer nextDayFlag;
|
||||
|
||||
/**
|
||||
* 是否外勤 0否 1是
|
||||
*/
|
||||
@ -101,12 +107,12 @@ public class AttendancePunchRecordDO extends BaseDO {
|
||||
private String punchAddress;
|
||||
|
||||
/**
|
||||
* 迟到时长(分)
|
||||
* 迟到时长时间戳
|
||||
*/
|
||||
private String lateTime;
|
||||
private Long lateTime;
|
||||
|
||||
/**
|
||||
* 早退时长(分)
|
||||
* 早退时长时间戳
|
||||
*/
|
||||
private String leaveEarlyTime;
|
||||
private Long leaveEarlyTime;
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package cn.iocoder.yudao.module.system.job.attendance;
|
||||
|
||||
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.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.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO;
|
||||
@ -15,6 +17,7 @@ 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.scheduling.AttendanceSchedulingService;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
@ -23,6 +26,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
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;
|
||||
@ -60,10 +64,13 @@ public class AttendanceStatisticsJob {
|
||||
private AttendanceSchedulingService attendanceSchedulingService;
|
||||
@Resource
|
||||
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
|
||||
@Resource
|
||||
private AttendancePunchRecordService attendancePunchRecordService;
|
||||
|
||||
@XxlJob("attendanceStatisticsJob")
|
||||
@TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
|
||||
public ReturnT<String> execute() throws Exception {
|
||||
log.info("开始 考勤预设");
|
||||
// 获取所有考勤组
|
||||
List<AttendanceGroupDO> attendanceGroupDOS = attendanceGroupMapper.selectList();
|
||||
// -- 根据考勤组ids 获取所有人员
|
||||
@ -71,9 +78,9 @@ public class AttendanceStatisticsJob {
|
||||
//将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);
|
||||
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));
|
||||
@ -85,8 +92,13 @@ public class AttendanceStatisticsJob {
|
||||
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) {
|
||||
@ -101,14 +113,19 @@ public class AttendanceStatisticsJob {
|
||||
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()).toInstant(), ZoneId.systemDefault());
|
||||
attendancePunchRecordDO.setShouldPunchTime(shouldPunchTime);
|
||||
attendancePunchRecordDOList.add(attendancePunchRecordDO);
|
||||
// TODO: 2024/5/24
|
||||
// TODO: 2024/5/24
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// -- 批量
|
||||
attendancePunchRecordService.saveBatch(attendancePunchRecordDOList);
|
||||
}
|
||||
log.info("结束 考勤预设");
|
||||
// 返回执行成功
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
@ -2,15 +2,18 @@ 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.AttendanceStatisticsDTO;
|
||||
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.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
|
||||
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 考勤 Service 接口
|
||||
@ -52,13 +55,21 @@ public interface AttendanceService {
|
||||
*/
|
||||
AttendancePunchVO punch(AttendancePunchDTO attendancePunchDTO);
|
||||
|
||||
List<AttendanceOnTheDayDTO> buildAttendanceOnTheDay(List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOList);
|
||||
|
||||
/**
|
||||
* 考勤统计
|
||||
* 按天查询
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
AttendanceStatisticsVO statistics(AttendanceStatisticsDTO dto);
|
||||
Map<String, List<AttendancePunchRecordDO>> statisticsByDay(AttendanceStatisticsByDayDTO dto);
|
||||
|
||||
List<AttendanceOnTheDayDTO> buildAttendanceOnTheDay(List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOList);
|
||||
/**
|
||||
* 考勤统计按周期
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
AttendanceStatisticsVO statisticsByCycle(AttendanceStatisticsByCycleDTO dto);
|
||||
}
|
@ -1,7 +1,12 @@
|
||||
package cn.iocoder.yudao.module.system.service.attendance;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.BetweenFormatter;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
@ -11,14 +16,14 @@ 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.AttendanceStatisticsDTO;
|
||||
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.HolidayVO;
|
||||
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.*;
|
||||
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.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
|
||||
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;
|
||||
@ -26,6 +31,9 @@ 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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@ -35,13 +43,16 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.hutool.core.date.DateUtil.dayOfWeekEnum;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
@ -64,6 +75,8 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
|
||||
@Resource
|
||||
private AttendancePunchRecordService attendancePunchRecordService;
|
||||
@Resource
|
||||
private AttendancePunchRecordMapper attendancePunchRecordMapper;
|
||||
|
||||
// 定义一些常量以提高代码的可读性和可维护性
|
||||
/**
|
||||
@ -120,6 +133,8 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
AttendanceOnTheDayDTO dayDTO = attendanceOnTheDayDTOS.get(pageVO.getIndex());
|
||||
Integer status = AttendancePunchRecordSaveReqVO.convertStatus(pageVO.getPunchType());
|
||||
|
||||
|
||||
//更新预打卡记录 - update 如果修改数量为0 则新增
|
||||
AttendancePunchRecordSaveReqVO attendancePunchRecordSaveReqVO = new AttendancePunchRecordSaveReqVO()
|
||||
.setUserId(dto.getUserId())
|
||||
.setAttendanceGroupId(pageVO.getActivationGroup().getId())
|
||||
@ -130,6 +145,7 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
.setWorkType(pageVO.getType())
|
||||
.setLevel(dayDTO.getLevel())
|
||||
.setStatus(status)
|
||||
.setNextDayFlag(Constants.FALSE)
|
||||
.setFieldServiceFlag(
|
||||
(Constants.TRUE.equals(pageVO.getFieldworkFlag()) && Constants.FALSE.equals(pageVO.getPunchPoint()))
|
||||
? Constants.TRUE : Constants.FALSE)
|
||||
@ -142,9 +158,23 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
.setRemark(dto.getRemark())
|
||||
.setImage(dto.getImage())
|
||||
.setPunchAddress(dto.getPunchAddress());
|
||||
Long id = attendancePunchRecordService.createPunchRecord(attendancePunchRecordSaveReqVO);
|
||||
AttendancePunchRecordDO attendancePunchRecordDO = new AttendancePunchRecordDO();
|
||||
BeanUtil.copyProperties(attendancePunchRecordSaveReqVO, attendancePunchRecordDO);
|
||||
|
||||
int updateNum = attendancePunchRecordMapper.update(attendancePunchRecordDO, new LambdaUpdateWrapper<AttendancePunchRecordDO>()
|
||||
.eq(AttendancePunchRecordDO::getUserId, dto.getUserId())
|
||||
.eq(AttendancePunchRecordDO::getDayTime, pageVO.getTargetDayStr())
|
||||
.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE)
|
||||
.eq(AttendancePunchRecordDO::getStatus, AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH)
|
||||
.eq(AttendancePunchRecordDO::getWorkType, attendancePunchRecordSaveReqVO.getWorkType())
|
||||
.eq(AttendancePunchRecordDO::getAttendanceGroupShiftItemId, attendancePunchRecordSaveReqVO.getAttendanceGroupShiftItemId())
|
||||
);
|
||||
Long id = null;
|
||||
if (updateNum <= 0) {
|
||||
id = attendancePunchRecordService.createPunchRecord(attendancePunchRecordSaveReqVO);
|
||||
}
|
||||
// -- 新增成功后更新redis
|
||||
if (id != null) {
|
||||
if (updateNum > 0 || id != null) {
|
||||
dayDTO.setPunchTime(dto.getLocalDateTime().format(Constants.REPO_DATE_FORMAT));
|
||||
dayDTO.setPunchStatus(attendancePunchRecordSaveReqVO.getStatus());
|
||||
dayDTO.setFieldServiceFlag(attendancePunchRecordSaveReqVO.getFieldServiceFlag());
|
||||
@ -165,16 +195,6 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttendanceStatisticsVO statistics(AttendanceStatisticsDTO dto) {
|
||||
// TODO: 2024/5/23
|
||||
if (AttendanceStatisticsDTO.TYPE_DAY.equals(dto.getType())) {
|
||||
// 按天
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Boolean isHoliday(LocalDateTime localDateTime) {
|
||||
@ -372,4 +392,356 @@ public class AttendanceServiceImpl implements AttendanceService {
|
||||
}
|
||||
return attendanceOnTheDayDTOS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<AttendancePunchRecordDO>> statisticsByDay(AttendanceStatisticsByDayDTO dto) {
|
||||
//获取当前天 所在月份所有日期
|
||||
List<String> dateList = DateUtils.betweenDayList(DateUtil.beginOfMonth(dto.getTime()),
|
||||
DateUtil.endOfMonth(dto.getTime()));
|
||||
List<AttendancePunchRecordDO> list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper<AttendancePunchRecordDO>()
|
||||
.eq(AttendancePunchRecordDO::getUserId, dto.getUserId())
|
||||
.in(AttendancePunchRecordDO::getDayTime, dateList)
|
||||
.orderByAsc(AttendancePunchRecordDO::getWorkType)
|
||||
.orderByAsc(AttendancePunchRecordDO::getLevel));
|
||||
// list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime));
|
||||
return list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttendanceStatisticsVO statisticsByCycle(AttendanceStatisticsByCycleDTO dto) {
|
||||
AttendanceStatisticsVO vo = new AttendanceStatisticsVO();
|
||||
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::getUserId, dto.getUserId())
|
||||
.in(AttendancePunchRecordDO::getDayTime, dateList)
|
||||
.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.FALSE)
|
||||
.orderByAsc(AttendancePunchRecordDO::getWorkType)
|
||||
.orderByAsc(AttendancePunchRecordDO::getLevel));
|
||||
// ---
|
||||
Map<String, List<AttendancePunchRecordDO>> map = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime));
|
||||
List<AttendancePunchStatisticsVO> averageWorkingHours = new ArrayList<>();
|
||||
List<AttendancePunchStatisticsVO> attendanceDays = new ArrayList<>();
|
||||
List<AttendancePunchStatisticsVO> beLateNumber = new ArrayList<>();
|
||||
List<AttendancePunchStatisticsVO> earlyDeparturesNumber = new ArrayList<>();
|
||||
List<AttendancePunchStatisticsVO> missingCardsNumber = new ArrayList<>();
|
||||
List<AttendancePunchStatisticsVO> minerDays = new ArrayList<>();
|
||||
List<AttendancePunchStatisticsVO> fieldServiceNumber = new ArrayList<>();
|
||||
AttendanceStatisticsVO.CalculateNum calculateNum = new AttendanceStatisticsVO.CalculateNum();
|
||||
|
||||
for (Map.Entry<String, List<AttendancePunchRecordDO>> entry : map.entrySet()) {
|
||||
String day = entry.getKey();
|
||||
String weekChinese = dayOfWeekEnum(DateUtil.parse(entry.getKey())).toChinese();
|
||||
// -- 按照班次子表分组
|
||||
Map<Long, List<AttendancePunchRecordDO>> workMap = entry.getValue().stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getAttendanceGroupShiftItemId));
|
||||
// -- 出勤天数计算
|
||||
AttendancePunchStatisticsVO attendanceDayVO = this.calculateAttendanceDays(day, weekChinese, entry.getValue(), calculateNum);
|
||||
if (attendanceDayVO != null) {
|
||||
attendanceDays.add(attendanceDayVO);
|
||||
}
|
||||
// -- 考勤工时计算
|
||||
AttendancePunchStatisticsVO averageWorkingHourVO = this.calculateAverageWorkingHour(day, weekChinese, workMap, calculateNum);
|
||||
averageWorkingHours.add(averageWorkingHourVO);
|
||||
|
||||
// -- 迟到计算
|
||||
List<AttendancePunchStatisticsVO> beLateList = this.calculateBeLate(day, weekChinese, workMap, calculateNum);
|
||||
beLateNumber.addAll(beLateList);
|
||||
// -- 早退计算
|
||||
List<AttendancePunchStatisticsVO> earlyDeparturesList = this.calculateEarlyDepartures(day, weekChinese, workMap, calculateNum);
|
||||
earlyDeparturesNumber.addAll(earlyDeparturesList);
|
||||
|
||||
// -- 缺卡计算
|
||||
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);
|
||||
}
|
||||
// -- 外勤计算
|
||||
List<AttendancePunchStatisticsVO> fieldServiceList = this.calculateFieldService(day, weekChinese, workMap, calculateNum);
|
||||
fieldServiceNumber.addAll(fieldServiceList);
|
||||
}
|
||||
// -- 休息计算
|
||||
List<AttendancePunchStatisticsVO> restDays = this.calculateRestDayList(dateList, map.keySet().stream().distinct().collect(Collectors.toList()), calculateNum);
|
||||
|
||||
calculateNum.setAverageWorkingHours(calculateNum.getTotalAttendanceDays() == 0 ? 0 : calculateNum.getTotalWorkingHours() / calculateNum.getTotalAttendanceDays());
|
||||
calculateNum.setAverageWorkingHoursStr(DateUtil.formatBetween(calculateNum.getAverageWorkingHours(), BetweenFormatter.Level.MINUTE));
|
||||
vo.setAttendanceDays(attendanceDays);
|
||||
vo.setAverageWorkingHours(averageWorkingHours);
|
||||
vo.setBeLateNumber(beLateNumber);
|
||||
vo.setEarlyDeparturesNumber(earlyDeparturesNumber);
|
||||
vo.setMissingCardsNumber(missingCardsNumber);
|
||||
vo.setMinerDays(minerDays);
|
||||
vo.setFieldServiceNumber(fieldServiceNumber);
|
||||
vo.setRestDays(restDays);
|
||||
vo.setCalculateNum(calculateNum);
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 外勤计算
|
||||
*
|
||||
* @param day
|
||||
* @param weekChinese
|
||||
* @param workMap
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private List<AttendancePunchStatisticsVO> calculateFieldService(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
|
||||
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
|
||||
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();
|
||||
for (AttendancePunchRecordDO attendancePunchRecordDO : fieldServiceList) {
|
||||
AttendancePunchStatisticsVO vo = new AttendancePunchStatisticsVO();
|
||||
vo.setDay(day);
|
||||
vo.setWeek(weekChinese);
|
||||
vo.setShouldPunchTime(attendancePunchRecordDO.getShouldPunchTime().format(DateTimeFormatter.ofPattern("HH:mm")));
|
||||
list.add(vo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
calculateNum.setTotalFieldServiceNumber(calculateNum.getTotalFieldServiceNumber() + todayFieldService);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算矿工
|
||||
*
|
||||
* @param day
|
||||
* @param weekChinese
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private AttendancePunchStatisticsVO calculateMiner(String day, String weekChinese, List<AttendancePunchRecordDO> list, AttendanceStatisticsVO.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()) {
|
||||
vo = new AttendancePunchStatisticsVO();
|
||||
vo.setDay(day);
|
||||
vo.setWeek(weekChinese);
|
||||
calculateNum.setTotalMinerDays(calculateNum.getTotalMinerDays() + 1);
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 休息时间计算
|
||||
*
|
||||
* @param dateList
|
||||
* @param attendanceTime
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private List<AttendancePunchStatisticsVO> calculateRestDayList(List<String> dateList, List<String> attendanceTime, AttendanceStatisticsVO.CalculateNum calculateNum) {
|
||||
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
|
||||
List<String> subtract = new ArrayList<>(CollectionUtil.subtract(dateList, attendanceTime));
|
||||
for (String timeStr : subtract) {
|
||||
AttendancePunchStatisticsVO vo = new AttendancePunchStatisticsVO();
|
||||
vo.setDay(timeStr);
|
||||
vo.setWeek(dayOfWeekEnum(DateUtil.parse(timeStr)).toChinese());
|
||||
list.add(vo);
|
||||
}
|
||||
calculateNum.setTotalRestDays(list.size());
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param day
|
||||
* @param weekChinese
|
||||
* @param workMap
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private List<AttendancePunchStatisticsVO> calculateMissingCardsList(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
|
||||
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
|
||||
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();
|
||||
for (AttendancePunchRecordDO attendancePunchRecordDO : missingCardsList) {
|
||||
AttendancePunchStatisticsVO earlyDepartures = new AttendancePunchStatisticsVO();
|
||||
earlyDepartures.setDay(day);
|
||||
earlyDepartures.setWeek(weekChinese);
|
||||
earlyDepartures.setShouldPunchTime(attendancePunchRecordDO.getShouldPunchTime().format(DateTimeFormatter.ofPattern("HH:mm")));
|
||||
list.add(earlyDepartures);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
calculateNum.setTotalMissingCardsNumber(calculateNum.getTotalMissingCardsNumber() + todayMissingCardsNumber);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 早退计算
|
||||
*
|
||||
* @param day
|
||||
* @param weekChinese
|
||||
* @param workMap
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private List<AttendancePunchStatisticsVO> calculateEarlyDepartures(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
|
||||
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
|
||||
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();
|
||||
for (AttendancePunchRecordDO attendancePunchRecordDO : earlyDeparturesList) {
|
||||
AttendancePunchStatisticsVO earlyDepartures = new AttendancePunchStatisticsVO();
|
||||
earlyDepartures.setDay(day);
|
||||
earlyDepartures.setWeek(weekChinese);
|
||||
earlyDepartures.setShouldPunchTime(attendancePunchRecordDO.getShouldPunchTime().format(DateTimeFormatter.ofPattern("HH:mm")));
|
||||
earlyDepartures.setTime("下班早退" + DateUtil.formatBetween(attendancePunchRecordDO.getLeaveEarlyTime(), BetweenFormatter.Level.MINUTE));
|
||||
list.add(earlyDepartures);
|
||||
}
|
||||
todayEarlyDeparturesTime += earlyDeparturesList.stream().mapToLong(AttendancePunchRecordDO::getLeaveEarlyTime).sum();
|
||||
}
|
||||
}
|
||||
}
|
||||
calculateNum.setTotalEarlyDeparturesNumber(calculateNum.getTotalEarlyDeparturesNumber() + todayEarlyDeparturesNumber);
|
||||
calculateNum.setTotalEarlyDeparturesTime(calculateNum.getTotalEarlyDeparturesTime() + todayEarlyDeparturesTime);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算迟到
|
||||
*
|
||||
* @param day
|
||||
* @param weekChinese
|
||||
* @param workMap
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private List<AttendancePunchStatisticsVO> calculateBeLate(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
|
||||
List<AttendancePunchStatisticsVO> list = new ArrayList<>();
|
||||
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();
|
||||
for (AttendancePunchRecordDO attendancePunchRecordDO : beLateList) {
|
||||
AttendancePunchStatisticsVO beLateDay = new AttendancePunchStatisticsVO();
|
||||
beLateDay.setDay(day);
|
||||
beLateDay.setWeek(weekChinese);
|
||||
beLateDay.setShouldPunchTime(attendancePunchRecordDO.getShouldPunchTime().format(DateTimeFormatter.ofPattern("HH:mm")));
|
||||
beLateDay.setTime("上班迟到" + DateUtil.formatBetween(attendancePunchRecordDO.getLateTime(), BetweenFormatter.Level.MINUTE));
|
||||
//将时间戳lateTime 转换成 **小时**分格式 不满1小时的时间不显小时
|
||||
list.add(beLateDay);
|
||||
}
|
||||
todayLateArrivalsTime += beLateList.stream().mapToLong(AttendancePunchRecordDO::getLateTime).sum();
|
||||
}
|
||||
}
|
||||
}
|
||||
calculateNum.setTotalLateArrivalsNumber(calculateNum.getTotalLateArrivalsNumber() + todayLateArrivalsNumber);
|
||||
calculateNum.setTotalLateArrivalsTime(calculateNum.getTotalLateArrivalsTime() + todayLateArrivalsTime);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算考勤工时
|
||||
*
|
||||
* @param day
|
||||
* @param weekChinese
|
||||
* @param workMap
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private AttendancePunchStatisticsVO calculateAverageWorkingHour(String day, String weekChinese, Map<Long, List<AttendancePunchRecordDO>> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) {
|
||||
AttendancePunchStatisticsVO vo = new AttendancePunchStatisticsVO();
|
||||
long todayWorkingHours = 0L;
|
||||
for (Map.Entry<Long, List<AttendancePunchRecordDO>> workEntry : workMap.entrySet()) {
|
||||
if (CollectionUtil.isNotEmpty(workEntry.getValue())) {
|
||||
// -- 工时计算 - 有上班和下班两个卡 才计算到工时里面
|
||||
if (workEntry.getValue().size() >= 2) {
|
||||
AttendancePunchRecordDO first = CollectionUtil.getFirst(workEntry.getValue());
|
||||
AttendancePunchRecordDO last = CollectionUtil.getLast(workEntry.getValue());
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算出勤天数
|
||||
*
|
||||
* @param day
|
||||
* @param weekChinese
|
||||
* @param list
|
||||
* @param calculateNum
|
||||
* @return
|
||||
*/
|
||||
private AttendancePunchStatisticsVO calculateAttendanceDays(String day, String weekChinese, List<AttendancePunchRecordDO> list, AttendanceStatisticsVO.CalculateNum calculateNum) {
|
||||
AttendancePunchStatisticsVO averageWorkingHourVO = null;
|
||||
List<AttendancePunchRecordDO> collect = list.stream().filter(a -> ObjectUtil.isNotEmpty(a.getPunchTime())).collect(Collectors.toList());
|
||||
if (CollectionUtil.isNotEmpty(collect)) {
|
||||
averageWorkingHourVO = new AttendancePunchStatisticsVO();
|
||||
averageWorkingHourVO.setDay(day);
|
||||
averageWorkingHourVO.setWeek(weekChinese);
|
||||
calculateNum.setTotalAttendanceDays(calculateNum.getTotalAttendanceDays() + 1);
|
||||
}
|
||||
return averageWorkingHourVO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.service.attendance.fixed;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.common.Constants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
@ -131,7 +132,7 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
|
||||
@Override
|
||||
public List<AttendanceFixedDO> getByGroupIdAndWeek(List<Long> attendanceGroupIds, Integer week) {
|
||||
return attendanceFixedMapper.selectList(new LambdaQueryWrapper<AttendanceFixedDO>()
|
||||
.eq(CollectionUtil.isNotEmpty(attendanceGroupIds), AttendanceFixedDO::getAttendanceGroupId, attendanceGroupIds)
|
||||
.in(CollectionUtil.isNotEmpty(attendanceGroupIds), AttendanceFixedDO::getAttendanceGroupId, attendanceGroupIds)
|
||||
.eq(week != null, AttendanceFixedDO::getWeekTime, week));
|
||||
}
|
||||
|
||||
@ -153,7 +154,7 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
|
||||
}
|
||||
AttendanceFixedDO attendanceFixedDO = null;
|
||||
List<AttendanceFixedDO> list = attendanceFixedMap.get(activationGroup.getId());
|
||||
if (!list.isEmpty()) {
|
||||
if (CollectionUtil.isNotEmpty(list)){
|
||||
attendanceFixedDO = list.get(0);
|
||||
}
|
||||
// -- 当前没有班次 - 不需要考勤
|
||||
|
@ -59,4 +59,6 @@ public interface AttendanceGroupService {
|
||||
* @return
|
||||
*/
|
||||
AttendanceGroupDO getByUserId(Long userId);
|
||||
|
||||
void test();
|
||||
}
|
@ -1,16 +1,40 @@
|
||||
package cn.iocoder.yudao.module.system.service.attendance.group;
|
||||
|
||||
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.iocoder.yudao.framework.common.Constants;
|
||||
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.module.system.controller.admin.group.vo.AttendanceGroupPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.group.vo.AttendanceGroupSaveReqVO;
|
||||
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.scheduling.AttendanceSchedulingService;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
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.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.GROUP_NOT_EXISTS;
|
||||
@ -26,6 +50,22 @@ public class AttendanceGroupServiceImpl implements AttendanceGroupService {
|
||||
|
||||
@Resource
|
||||
private AttendanceGroupMapper groupMapper;
|
||||
@Resource
|
||||
private AttendancePunchRecordService attendancePunchRecordService;
|
||||
@Resource
|
||||
private AttendanceGroupMapper attendanceGroupMapper;
|
||||
@Resource
|
||||
private AttendanceGroupUserMapper attendanceGroupUserMapper;
|
||||
@Resource
|
||||
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
|
||||
@Resource
|
||||
@Lazy // 避免依赖循环
|
||||
private AttendanceService attendanceService;
|
||||
@Resource
|
||||
private AttendanceFixedService attendanceFixedService;
|
||||
@Resource
|
||||
private AttendanceSchedulingService attendanceSchedulingService;
|
||||
|
||||
|
||||
@Override
|
||||
public Long createGroup(AttendanceGroupSaveReqVO createReqVO) {
|
||||
@ -78,4 +118,81 @@ public class AttendanceGroupServiceImpl implements AttendanceGroupService {
|
||||
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 = LocalDateTimeUtil.offset(LocalDateTime.now(), 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.setAttendanceGroupShiftId(attendanceOnTheDayDTO.getKqAttendanceGroupShiftId());
|
||||
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.setDayTime(time);
|
||||
LocalDateTime shouldPunchTime = LocalDateTime.ofInstant(DateUtils.buildHHmmTime(attendanceOnTheDayDTO.getTime()).toInstant(), ZoneId.systemDefault());
|
||||
attendancePunchRecordDO.setShouldPunchTime(shouldPunchTime);
|
||||
attendancePunchRecordDOList.add(attendancePunchRecordDO);
|
||||
// TODO: 2024/5/24
|
||||
}
|
||||
}
|
||||
}
|
||||
// -- 批量
|
||||
attendancePunchRecordService.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;
|
||||
}
|
||||
|
||||
}
|
@ -10,6 +10,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.mysql.attendance.groupshift.AttendanceGroupShiftMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupshiftitem.AttendanceGroupShiftItemMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@ -106,7 +107,8 @@ public class AttendanceGroupShiftServiceImpl implements AttendanceGroupShiftServ
|
||||
List<Long> ids = dos.stream().map(AttendanceGroupShiftDO::getId).collect(Collectors.toList());
|
||||
Map<Long, List<AttendanceGroupShiftItemDO>> map = new HashMap<>();
|
||||
if (!ids.isEmpty()) {
|
||||
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOS = groupShiftItemMapper.selectBatchIds(ids);
|
||||
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOS = groupShiftItemMapper.selectList(new LambdaQueryWrapper<AttendanceGroupShiftItemDO>()
|
||||
.in(AttendanceGroupShiftItemDO::getKqAttendanceGroupShiftId, ids));
|
||||
map = attendanceGroupShiftItemDOS.stream().collect(Collectors.groupingBy(AttendanceGroupShiftItemDO::getKqAttendanceGroupShiftId));
|
||||
}
|
||||
List<AttendanceGroupShiftVO> vos = new ArrayList<>();
|
||||
|
@ -1,9 +1,12 @@
|
||||
package cn.iocoder.yudao.module.system.service.attendance.groupuser;
|
||||
|
||||
import javax.validation.*;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.*;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
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.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 考勤组人员 Service 接口
|
||||
@ -13,12 +16,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
public interface AttendanceGroupUserService {
|
||||
|
||||
/**
|
||||
* 创建考勤组人员
|
||||
* 创建删除考勤组人员
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
* @param attendanceGroupId
|
||||
* @param userIds
|
||||
*/
|
||||
Long createGroupUser(@Valid AttendanceGroupUserSaveReqVO createReqVO);
|
||||
void createOrDel(Long attendanceGroupId, List<Long> userIds);
|
||||
|
||||
/**
|
||||
* 更新考勤组人员
|
||||
@ -50,4 +53,11 @@ public interface AttendanceGroupUserService {
|
||||
*/
|
||||
PageResult<AttendanceGroupUserDO> getGroupUserPage(AttendanceGroupUserPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 根据考勤组id获取考勤人员ids
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
List<Long> getUserIdsByGroupId(Long id);
|
||||
}
|
@ -1,18 +1,23 @@
|
||||
package cn.iocoder.yudao.module.system.service.attendance.groupuser;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.*;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
|
||||
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.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.GROUP_USER_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 考勤组人员 Service 实现类
|
||||
@ -27,12 +32,37 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
|
||||
private AttendanceGroupUserMapper groupUserMapper;
|
||||
|
||||
@Override
|
||||
public Long createGroupUser(AttendanceGroupUserSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
AttendanceGroupUserDO groupUser = BeanUtils.toBean(createReqVO, AttendanceGroupUserDO.class);
|
||||
groupUserMapper.insert(groupUser);
|
||||
// 返回
|
||||
return groupUser.getId();
|
||||
public void createOrDel(Long attendanceGroupId, List<Long> userIds) {
|
||||
List<AttendanceGroupUserDO> groupUserList = groupUserMapper.selectList(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId);
|
||||
List<AttendanceGroupUserDO> list = new ArrayList<>();
|
||||
if (CollectionUtil.isEmpty(groupUserList)) {
|
||||
if (CollectionUtil.isNotEmpty(userIds)) {
|
||||
for (Long userId : userIds) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,4 +98,11 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
|
||||
return groupUserMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getUserIdsByGroupId(Long id) {
|
||||
List<AttendanceGroupUserDO> list = groupUserMapper.selectList(new LambdaQueryWrapper<AttendanceGroupUserDO>()
|
||||
.eq(AttendanceGroupUserDO::getAttendanceGroupId, id));
|
||||
return list.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
package cn.iocoder.yudao.module.system.service.attendance.punchrecord;
|
||||
|
||||
import javax.validation.*;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.*;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
|
||||
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.AttendancePunchRecordSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户打卡记录 Service 接口
|
||||
@ -50,4 +53,10 @@ public interface AttendancePunchRecordService {
|
||||
*/
|
||||
PageResult<AttendancePunchRecordDO> getPunchRecordPage(AttendancePunchRecordPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 批量新增考勤
|
||||
*
|
||||
* @param attendancePunchRecordDOList
|
||||
*/
|
||||
void saveBatch(List<AttendancePunchRecordDO> attendancePunchRecordDOList);
|
||||
}
|
@ -1,18 +1,20 @@
|
||||
package cn.iocoder.yudao.module.system.service.attendance.punchrecord;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.*;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
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.AttendancePunchRecordSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.PUNCH_RECORD_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 用户打卡记录 Service 实现类
|
||||
@ -68,4 +70,10 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
|
||||
return punchRecordMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveBatch(List<AttendancePunchRecordDO> attendancePunchRecordDOList) {
|
||||
punchRecordMapper.insertBatch(attendancePunchRecordDOList);
|
||||
}
|
||||
|
||||
}
|
@ -13,11 +13,9 @@ import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePu
|
||||
import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchPageVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.scheduling.AttendanceSchedulingDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupshift.AttendanceGroupShiftMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.attendance.scheduling.AttendanceSchedulingMapper;
|
||||
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
|
||||
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.punch.PunchService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
@ -50,16 +48,9 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
|
||||
@Resource
|
||||
private AttendanceGroupShiftService attendanceGroupShiftService;
|
||||
@Resource
|
||||
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private AttendanceService attendanceService;
|
||||
|
||||
@Resource
|
||||
private AttendanceGroupShiftMapper attendanceGroupShiftMapper;
|
||||
@Resource
|
||||
private AttendanceGroupShiftItemService groupShiftItemService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchCreateOrUpdate(Long attendanceGroupId, List<AttendanceSchedulingSaveReqVO> createReqVO) {
|
||||
@ -167,6 +158,7 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<AttendanceSchedulingRespVO> getListByGroupId(Long attendanceGroupId) {
|
||||
List<AttendanceSchedulingRespVO> respVOS = new ArrayList<>();
|
||||
|
Loading…
Reference in New Issue
Block a user