diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java index 405817a4..795fff10 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java @@ -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 betweenDayList(Date beginTime, Date endTime) { List 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 dateTimes = DateUtil.rangeToList(beginTime, endTime, DateField.DAY_OF_MONTH); + for (DateTime dateTime : dateTimes) { + list.add(dateTime.toDateStr()); } return list; } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 38568cf1..9ed99c86 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -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, "模板不存在"); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/fixed/AttendanceFixedController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/fixed/AttendanceFixedController.java index 8730999d..5fffb4f8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/fixed/AttendanceFixedController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/fixed/AttendanceFixedController.java @@ -56,7 +56,6 @@ public class AttendanceFixedController { @GetMapping("/getListByGroupId") @Operation(summary = "根据考勤组ID获得固定班制考勤设置列表") - @PreAuthorize("@ss.hasPermission('attendance:fixed:query')") public CommonResult> getListByGroupId(@RequestParam Long attendanceGroupId) { List list = fixedService.getListByGroupId(attendanceGroupId); return success(list); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/group/AttendanceGroupController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/group/AttendanceGroupController.java index 48c1055f..56b2cea7 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/group/AttendanceGroupController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/group/AttendanceGroupController.java @@ -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')") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupuser/AttendanceGroupUserController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupuser/AttendanceGroupUserController.java index fb3052cf..395f40c9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupuser/AttendanceGroupUserController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupuser/AttendanceGroupUserController.java @@ -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 createGroupUser(@Valid @RequestBody AttendanceGroupUserSaveReqVO createReqVO) { - return success(groupUserService.createGroupUser(createReqVO)); + public CommonResult createOrDel(@RequestParam Long attendanceGroupId, + @Valid @RequestBody List 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> getUserIdsByGroupId(@RequestParam("id") Long id) { + List 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 list = groupUserService.getGroupUserPage(pageReqVO).getList(); // 导出 Excel ExcelUtils.write(response, "考勤组人员.xls", "数据", AttendanceGroupUserRespVO.class, - BeanUtils.toBean(list, AttendanceGroupUserRespVO.class)); + BeanUtils.toBean(list, AttendanceGroupUserRespVO.class)); } } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordPageReqVO.java index 17c6cdfc..d0fe2892 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordPageReqVO.java @@ -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; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordRespVO.java index a261d0dc..2cafcdf7 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordRespVO.java @@ -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; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordSaveReqVO.java index 35fa0aed..7ca7ae2b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/punchrecord/vo/AttendancePunchRecordSaveReqVO.java @@ -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; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/scheduling/AttendanceSchedulingController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/scheduling/AttendanceSchedulingController.java index 529ffe64..385ee4ba 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/scheduling/AttendanceSchedulingController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/scheduling/AttendanceSchedulingController.java @@ -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 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 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> getListByGroupId(@RequestParam("id") Long attendanceGroupId) { List 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> getSchedulingPage(@Valid AttendanceSchedulingPageReqVO pageReqVO) { PageResult 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 { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java index 02d09cb5..2db60a8b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/AttendanceController.java @@ -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 statistics(@RequestBody AttendanceStatisticsDTO dto) { - AttendanceStatisticsVO vo = attendanceService.statistics(dto); + @GetMapping("/statisticsByDay") + @Operation(summary = "统计按天") + public CommonResult>> statisticsByDay(@ModelAttribute AttendanceStatisticsByDayDTO dto) { + Map> vo = attendanceService.statisticsByDay(dto); + return success(vo); + } + + @GetMapping("/statisticsByCycle") + @Operation(summary = "统计按周期") + public CommonResult statisticsByCycle(@ModelAttribute @Valid AttendanceStatisticsByCycleDTO dto) { + AttendanceStatisticsVO vo = attendanceService.statisticsByCycle(dto); return success(vo); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsByCycleDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsByCycleDTO.java new file mode 100644 index 00000000..b128b2a7 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsByCycleDTO.java @@ -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; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsByDayDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsByDayDTO.java new file mode 100644 index 00000000..042a47fa --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsByDayDTO.java @@ -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(); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsDTO.java deleted file mode 100644 index 462b7975..00000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendanceStatisticsDTO.java +++ /dev/null @@ -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()); -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchStatisticsVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchStatisticsVO.java new file mode 100644 index 00000000..6bc66f06 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchStatisticsVO.java @@ -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; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java index 9a003d78..4159c795 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendanceStatisticsVO.java @@ -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 statisticsStatusByDayMap; - - @Schema(description = "按天响应对象 key为日期 yyyy-MM-dd value为状态 0正常 1异常") - private Map> statisticsDataByDayMap; + @Schema(description = "平均工作时间") + private List averageWorkingHours; + @Schema(description = "出勤天数") + private List attendanceDays; + @Schema(description = "迟到次数") + private List beLateNumber; + @Schema(description = "早退次数") + private List earlyDeparturesNumber; + @Schema(description = "缺卡次数") + private List missingCardsNumber; + @Schema(description = "矿工日") + private List minerDays; + @Schema(description = "外勤次数") + private List fieldServiceNumber; + @Schema(description = "休息日") + private List 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; + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/punchrecord/AttendancePunchRecordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/punchrecord/AttendancePunchRecordDO.java index e8614b22..5a406b88 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/punchrecord/AttendancePunchRecordDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/punchrecord/AttendancePunchRecordDO.java @@ -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; } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/AttendanceStatisticsJob.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/AttendanceStatisticsJob.java index 26ce0140..c5c1e71a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/AttendanceStatisticsJob.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/AttendanceStatisticsJob.java @@ -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 execute() throws Exception { + log.info("开始 考勤预设"); // 获取所有考勤组 List attendanceGroupDOS = attendanceGroupMapper.selectList(); // -- 根据考勤组ids 获取所有人员 @@ -71,9 +78,9 @@ public class AttendanceStatisticsJob { //将attendanceGroupUserDOS对象中的type相同的userId合并成一个数组 type作为key 用户id列表List作为value Map> 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 map = this.getAttendanceGroupShiftIdGroupByGroup(attendanceGroupDOS, tomorrowLocalDateTime); Map groupMap = attendanceGroupDOS.stream().collect(Collectors.toMap(AttendanceGroupDO::getId, v -> v)); @@ -85,8 +92,13 @@ public class AttendanceStatisticsJob { for (Map.Entry entry : map.entrySet()) { AttendanceGroupDO attendanceGroupDO = groupMap.get(entry.getKey()); List userIds = groupUserMap.get(entry.getKey()); - // + if (CollectionUtil.isEmpty(userIds)) { + continue; + } List attendanceGroupShiftItemDOS = itemMaps.get(entry.getValue()); + if (CollectionUtil.isEmpty(attendanceGroupShiftItemDOS)) { + continue; + } List 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; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java index bf78b09a..397c7e5f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceService.java @@ -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 buildAttendanceOnTheDay(List attendanceGroupShiftItemDOList); + /** - * 考勤统计 + * 按天查询 * * @param dto * @return */ - AttendanceStatisticsVO statistics(AttendanceStatisticsDTO dto); + Map> statisticsByDay(AttendanceStatisticsByDayDTO dto); - List buildAttendanceOnTheDay(List attendanceGroupShiftItemDOList); + /** + * 考勤统计按周期 + * + * @param dto + * @return + */ + AttendanceStatisticsVO statisticsByCycle(AttendanceStatisticsByCycleDTO dto); } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java index 1c3ea847..e7dc1c6d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/AttendanceServiceImpl.java @@ -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() + .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> statisticsByDay(AttendanceStatisticsByDayDTO dto) { + //获取当前天 所在月份所有日期 + List dateList = DateUtils.betweenDayList(DateUtil.beginOfMonth(dto.getTime()), + DateUtil.endOfMonth(dto.getTime())); + List list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper() + .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 dateList = DateUtils.betweenDayList(beginTime, endTime); + List list = attendancePunchRecordMapper.selectList(new LambdaQueryWrapper() + .eq(AttendancePunchRecordDO::getUserId, dto.getUserId()) + .in(AttendancePunchRecordDO::getDayTime, dateList) + .eq(AttendancePunchRecordDO::getNextDayFlag, Constants.FALSE) + .orderByAsc(AttendancePunchRecordDO::getWorkType) + .orderByAsc(AttendancePunchRecordDO::getLevel)); + // --- + Map> map = list.stream().collect(Collectors.groupingBy(AttendancePunchRecordDO::getDayTime)); + List averageWorkingHours = new ArrayList<>(); + List attendanceDays = new ArrayList<>(); + List beLateNumber = new ArrayList<>(); + List earlyDeparturesNumber = new ArrayList<>(); + List missingCardsNumber = new ArrayList<>(); + List minerDays = new ArrayList<>(); + List fieldServiceNumber = new ArrayList<>(); + AttendanceStatisticsVO.CalculateNum calculateNum = new AttendanceStatisticsVO.CalculateNum(); + + for (Map.Entry> entry : map.entrySet()) { + String day = entry.getKey(); + String weekChinese = dayOfWeekEnum(DateUtil.parse(entry.getKey())).toChinese(); + // -- 按照班次子表分组 + Map> 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 beLateList = this.calculateBeLate(day, weekChinese, workMap, calculateNum); + beLateNumber.addAll(beLateList); + // -- 早退计算 + List earlyDeparturesList = this.calculateEarlyDepartures(day, weekChinese, workMap, calculateNum); + earlyDeparturesNumber.addAll(earlyDeparturesList); + + // -- 缺卡计算 + List 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 fieldServiceList = this.calculateFieldService(day, weekChinese, workMap, calculateNum); + fieldServiceNumber.addAll(fieldServiceList); + } + // -- 休息计算 + List 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 calculateFieldService(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + List list = new ArrayList<>(); + int todayFieldService = 0; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 缺卡计算 + List 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 list, AttendanceStatisticsVO.CalculateNum calculateNum) { + AttendancePunchStatisticsVO vo = null; + List 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 calculateRestDayList(List dateList, List attendanceTime, AttendanceStatisticsVO.CalculateNum calculateNum) { + List list = new ArrayList<>(); + List 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 calculateMissingCardsList(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + List list = new ArrayList<>(); + int todayMissingCardsNumber = 0; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 缺卡计算 + List 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 calculateEarlyDepartures(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + List list = new ArrayList<>(); + int todayEarlyDeparturesNumber = 0; + long todayEarlyDeparturesTime = 0L; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 早退计算 + List 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 calculateBeLate(String day, String weekChinese, Map> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + List list = new ArrayList<>(); + int todayLateArrivalsNumber = 0; + long todayLateArrivalsTime = 0L; + for (Map.Entry> workEntry : workMap.entrySet()) { + if (CollectionUtil.isNotEmpty(workEntry.getValue())) { + // -- 迟到计算 + List 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> workMap, AttendanceStatisticsVO.CalculateNum calculateNum) { + AttendancePunchStatisticsVO vo = new AttendancePunchStatisticsVO(); + long todayWorkingHours = 0L; + for (Map.Entry> 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 list, AttendanceStatisticsVO.CalculateNum calculateNum) { + AttendancePunchStatisticsVO averageWorkingHourVO = null; + List 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; + } + + + } + + + + + + + + + + + + + + + + + + + + + + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/fixed/AttendanceFixedServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/fixed/AttendanceFixedServiceImpl.java index 100f9fe7..7f22be22 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/fixed/AttendanceFixedServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/fixed/AttendanceFixedServiceImpl.java @@ -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 getByGroupIdAndWeek(List attendanceGroupIds, Integer week) { return attendanceFixedMapper.selectList(new LambdaQueryWrapper() - .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 list = attendanceFixedMap.get(activationGroup.getId()); - if (!list.isEmpty()) { + if (CollectionUtil.isNotEmpty(list)){ attendanceFixedDO = list.get(0); } // -- 当前没有班次 - 不需要考勤 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupService.java index d361c296..5e43fbb4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupService.java @@ -59,4 +59,6 @@ public interface AttendanceGroupService { * @return */ AttendanceGroupDO getByUserId(Long userId); + + void test(); } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupServiceImpl.java index 7281d16d..b2d81445 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/group/AttendanceGroupServiceImpl.java @@ -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 attendanceGroupDOS = attendanceGroupMapper.selectList(); + // -- 根据考勤组ids 获取所有人员 + List attendanceGroupUserDOS = attendanceGroupUserMapper.selectList(); + //将attendanceGroupUserDOS对象中的type相同的userId合并成一个数组 type作为key 用户id列表List作为value + Map> 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 map = this.getAttendanceGroupShiftIdGroupByGroup(attendanceGroupDOS, tomorrowLocalDateTime); + Map groupMap = attendanceGroupDOS.stream().collect(Collectors.toMap(AttendanceGroupDO::getId, v -> v)); + // -- 获取班次子表列表 + if (MapUtil.isNotEmpty(map)) { + List attendanceGroupShiftItemDOList = attendanceGroupShiftItemService.getGroupShiftItemListByShiftIds(new ArrayList<>(map.values())); + Map> itemMaps = attendanceGroupShiftItemDOList.stream().collect(Collectors.groupingBy(AttendanceGroupShiftItemDO::getKqAttendanceGroupShiftId)); + List attendancePunchRecordDOList = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + AttendanceGroupDO attendanceGroupDO = groupMap.get(entry.getKey()); + List userIds = groupUserMap.get(entry.getKey()); + if (CollectionUtil.isEmpty(userIds)){ + continue; + } + List attendanceGroupShiftItemDOS = itemMaps.get(entry.getValue()); + if (CollectionUtil.isEmpty(attendanceGroupShiftItemDOS)){ + continue; + } + List 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 getAttendanceGroupShiftIdGroupByGroup(List attendanceGroupDOS, LocalDateTime localDateTime) { + Map map = new HashMap<>(); + List fixedList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(1)).collect(Collectors.toList()); + List schedulingList = attendanceGroupDOS.stream().filter(a -> a.getType().equals(2)).collect(Collectors.toList()); + if (!fixedList.isEmpty()) { + Map attendanceFixedMap = attendanceFixedService.getGroupToShiftIdMap(fixedList, localDateTime); + if (ObjectUtil.isNotEmpty(attendanceFixedMap)) { + map.putAll(attendanceFixedMap); + } + } + if (!schedulingList.isEmpty()) { + Map attendanceSchedulingMap = attendanceSchedulingService.getGroupToShiftIdMap(schedulingList, localDateTime); + if (ObjectUtil.isNotEmpty(attendanceSchedulingMap)) { + map.putAll(attendanceSchedulingMap); + } + } + return map; + } + } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftServiceImpl.java index b35af8da..b8e8797e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftServiceImpl.java @@ -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 ids = dos.stream().map(AttendanceGroupShiftDO::getId).collect(Collectors.toList()); Map> map = new HashMap<>(); if (!ids.isEmpty()) { - List attendanceGroupShiftItemDOS = groupShiftItemMapper.selectBatchIds(ids); + List attendanceGroupShiftItemDOS = groupShiftItemMapper.selectList(new LambdaQueryWrapper() + .in(AttendanceGroupShiftItemDO::getKqAttendanceGroupShiftId, ids)); map = attendanceGroupShiftItemDOS.stream().collect(Collectors.groupingBy(AttendanceGroupShiftItemDO::getKqAttendanceGroupShiftId)); } List vos = new ArrayList<>(); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserService.java index 44cbf7e2..9b13f92f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserService.java @@ -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 userIds); /** * 更新考勤组人员 @@ -50,4 +53,11 @@ public interface AttendanceGroupUserService { */ PageResult getGroupUserPage(AttendanceGroupUserPageReqVO pageReqVO); + /** + * 根据考勤组id获取考勤人员ids + * + * @param id + * @return + */ + List getUserIdsByGroupId(Long id); } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserServiceImpl.java index 19cc1edc..5cef78fb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupuser/AttendanceGroupUserServiceImpl.java @@ -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 userIds) { + List groupUserList = groupUserMapper.selectList(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId); + List 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 oldUserIds = groupUserList.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList()); + List delIds = new ArrayList<>(CollectionUtil.subtract(oldUserIds, userIds)); + List saveIds = new ArrayList<>(CollectionUtil.subtract(userIds, oldUserIds)); + if (CollectionUtil.isNotEmpty(delIds)) { + groupUserMapper.delete(new LambdaQueryWrapper().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 getUserIdsByGroupId(Long id) { + List list = groupUserMapper.selectList(new LambdaQueryWrapper() + .eq(AttendanceGroupUserDO::getAttendanceGroupId, id)); + return list.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList()); + } + } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordService.java index a1c758ea..bb833156 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordService.java @@ -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 getPunchRecordPage(AttendancePunchRecordPageReqVO pageReqVO); + /** + * 批量新增考勤 + * + * @param attendancePunchRecordDOList + */ + void saveBatch(List attendancePunchRecordDOList); } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordServiceImpl.java index 5d2078e1..1db24aad 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punchrecord/AttendancePunchRecordServiceImpl.java @@ -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 attendancePunchRecordDOList) { + punchRecordMapper.insertBatch(attendancePunchRecordDOList); + } + } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/scheduling/AttendanceSchedulingServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/scheduling/AttendanceSchedulingServiceImpl.java index b641c2d0..1cd6e83d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/scheduling/AttendanceSchedulingServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/scheduling/AttendanceSchedulingServiceImpl.java @@ -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 createReqVO) { @@ -167,6 +158,7 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ return map; } + @Override public List getListByGroupId(Long attendanceGroupId) { List respVOS = new ArrayList<>();