Merge branch 'dev' into frx

This commit is contained in:
furongxin 2024-05-28 10:14:32 +08:00
commit 9c4d7b8a40
28 changed files with 867 additions and 147 deletions

View File

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

View File

@ -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, "模板不存在");

View File

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

View File

@ -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')")

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
// -- 当前没有班次 - 不需要考勤

View File

@ -59,4 +59,6 @@ public interface AttendanceGroupService {
* @return
*/
AttendanceGroupDO getByUserId(Long userId);
void test();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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