From cafd19803752cd00f039708cb8eceacd2aaa7191 Mon Sep 17 00:00:00 2001 From: aikai Date: Fri, 26 Apr 2024 17:58:09 +0800 Subject: [PATCH] =?UTF-8?q?=E8=80=83=E5=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/common/Constants.java | 43 +++ .../system/enums/ErrorCodeConstants.java | 6 + .../AttendanceStatisticsController.java | 93 ++++++ .../vo/AttendanceStatisticsPageReqVO.java | 47 +++ .../vo/AttendanceStatisticsRespVO.java | 56 ++++ .../vo/AttendanceStatisticsSaveReqVO.java | 40 +++ .../vo/AttendanceGroupShiftPageReqVO.java | 3 + .../vo/AttendanceGroupShiftRespVO.java | 4 + .../vo/AttendanceGroupShiftSaveReqVO.java | 3 + .../vo/AttendanceGroupShiftItemPageReqVO.java | 3 + .../vo/AttendanceGroupShiftItemRespVO.java | 4 + .../vo/AttendanceGroupShiftItemSaveReqVO.java | 4 + .../vo/AttendancePunchRecordPageReqVO.java | 32 +- .../vo/AttendancePunchRecordRespVO.java | 33 +- .../vo/AttendancePunchRecordSaveReqVO.java | 56 +++- .../admin/worklog/LogFormController.java | 2 - .../app/attendance/AttendanceController.java | 20 +- .../attendance/dto/AttendancePunchDTO.java | 40 +++ .../dto/AttendancePunchPageDTO.java | 14 +- .../attendance/vo/AttendancePunchPageVO.java | 50 ++- .../app/attendance/vo/AttendancePunchVO.java | 23 ++ .../attendance/group/AttendanceGroupDO.java | 6 + .../groupshift/AttendanceGroupShiftDO.java | 4 + .../AttendanceGroupShiftItemDO.java | 17 +- .../punchrecord/AttendancePunchRecordDO.java | 38 ++- .../statistics/AttendanceStatisticsDO.java | 63 ++++ .../AttendancePunchRecordMapper.java | 2 +- .../AttendanceSchedulingMapper.java | 6 +- .../AttendanceStatisticsMapper.java | 32 ++ .../attendance/AttendanceStatisticsJob.java | 28 ++ .../system/job/attendance/SchedulingJob.java | 47 +++ .../service/attendance/AttendanceService.java | 30 +- .../attendance/AttendanceServiceImpl.java | 291 +++++++++++++++++- .../fixed/AttendanceFixedServiceImpl.java | 48 +-- .../AttendanceGroupShiftService.java | 1 - .../AttendanceGroupShiftItemService.java | 8 + .../AttendanceGroupShiftItemServiceImpl.java | 9 + .../punch/dto/AttendanceOnTheDayDTO.java | 71 +++++ .../AttendanceSchedulingService.java | 26 +- .../AttendanceSchedulingServiceImpl.java | 62 +++- .../AttendanceStatisticsService.java | 55 ++++ .../AttendanceStatisticsServiceImpl.java | 59 ++++ .../src/main/resources/application-dev.yaml | 2 +- .../scheduling/AttendanceSchedulingMapper.xml | 7 + .../statistics/AttendanceStatisticsMapper.xml | 12 + 45 files changed, 1405 insertions(+), 95 deletions(-) create mode 100644 yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/Constants.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/AttendanceStatisticsController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendancePunchDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/statistics/AttendanceStatisticsDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/statistics/AttendanceStatisticsMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/AttendanceStatisticsJob.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/SchedulingJob.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punch/dto/AttendanceOnTheDayDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/statistics/AttendanceStatisticsService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/statistics/AttendanceStatisticsServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/statistics/AttendanceStatisticsMapper.xml diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/Constants.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/Constants.java new file mode 100644 index 00000000..2197dbf4 --- /dev/null +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/Constants.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.common; + +import java.time.format.DateTimeFormatter; + +public class Constants { + /** + * 空字符串 + */ + public static final String EMPTY_STRING = ""; + + /** + * 下划线 + */ + public static final String UNDERLINE = "_"; + + + /** + * 考勤前缀 + */ + public static final String ATTENDANCE = "attendance"; + + /** + * 排班制前缀 + */ + public static final String SCHEDULING = "scheduling"; + /** + * 零 + */ + public static final Integer ZERO = 0; + /** + * 一 + */ + public static final Integer ONE = 1; + /** + * 中文1 + */ + public static final String ONE_STR = "1"; + + /** + * yyyy-MM-dd格式 + */ + public static final DateTimeFormatter REPO_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); +} 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 20e503b2..40cc9286 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 @@ -183,6 +183,12 @@ public interface ErrorCodeConstants { ErrorCode GROUP_SHIFT_NOT_EXISTS = new ErrorCode(1_003_004_000, "考勤组班次不存在"); ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_003_005_000, "考勤组不存在"); ErrorCode FIXED_NOT_EXISTS = new ErrorCode(1_003_006_000, "固定班制考勤设置"); + ErrorCode NOT_IN_THE_ATTENDANCE_GROUP = new ErrorCode(1_003_007_000, "未在考勤组内"); + ErrorCode NO_ATTENDANCE_REQUIRED_ON_THE_DAY = new ErrorCode(1_003_008_000, "当天不需要考勤"); + + ErrorCode DID_NOT_ENTER_THE_ATTENDANCE_RANGE = new ErrorCode(1_003_009_000, "未进入到考勤范围"); + + ErrorCode ATTENDANCE_TIME_NOT_ARRIVED = new ErrorCode(1_003_010_000, "未到考勤时间"); ErrorCode LOG_FORM_NOT_USE = new ErrorCode(1_009_010_004, "你不用使用该日志模板"); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/AttendanceStatisticsController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/AttendanceStatisticsController.java new file mode 100644 index 00000000..a494d607 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/AttendanceStatisticsController.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.system.controller.admin.attendance; + +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.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceStatisticsPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceStatisticsRespVO; +import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceStatisticsSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.attendance.statistics.AttendanceStatisticsDO; +import cn.iocoder.yudao.module.system.service.attendance.statistics.AttendanceStatisticsService; +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 +@RequestMapping("/system.attendance/attendance-statistics") +@Validated +public class AttendanceStatisticsController { + + @Resource + private AttendanceStatisticsService attendanceStatisticsService; + + @PostMapping("/create") + @Operation(summary = "创建考勤统计") + @PreAuthorize("@ss.hasPermission('system.attendance:attendance-statistics:create')") + public CommonResult createAttendanceStatistics(@Valid @RequestBody AttendanceStatisticsSaveReqVO createReqVO) { + return success(attendanceStatisticsService.createAttendanceStatistics(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新考勤统计") + @PreAuthorize("@ss.hasPermission('system.attendance:attendance-statistics:update')") + public CommonResult updateAttendanceStatistics(@Valid @RequestBody AttendanceStatisticsSaveReqVO updateReqVO) { + attendanceStatisticsService.updateAttendanceStatistics(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除考勤统计") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system.attendance:attendance-statistics:delete')") + public CommonResult deleteAttendanceStatistics(@RequestParam("id") Long id) { + attendanceStatisticsService.deleteAttendanceStatistics(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得考勤统计") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system.attendance:attendance-statistics:query')") + public CommonResult getAttendanceStatistics(@RequestParam("id") Long id) { + AttendanceStatisticsDO attendanceStatistics = attendanceStatisticsService.getAttendanceStatistics(id); + return success(BeanUtils.toBean(attendanceStatistics, AttendanceStatisticsRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得考勤统计分页") + @PreAuthorize("@ss.hasPermission('system.attendance:attendance-statistics:query')") + public CommonResult> getAttendanceStatisticsPage(@Valid AttendanceStatisticsPageReqVO pageReqVO) { + PageResult pageResult = attendanceStatisticsService.getAttendanceStatisticsPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, AttendanceStatisticsRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出考勤统计 Excel") + @PreAuthorize("@ss.hasPermission('system.attendance:attendance-statistics:export')") + @OperateLog(type = EXPORT) + public void exportAttendanceStatisticsExcel(@Valid AttendanceStatisticsPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = attendanceStatisticsService.getAttendanceStatisticsPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "考勤统计.xls", "数据", AttendanceStatisticsRespVO.class, + BeanUtils.toBean(list, AttendanceStatisticsRespVO.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/attendance/vo/AttendanceStatisticsPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsPageReqVO.java new file mode 100644 index 00000000..1b459b38 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsPageReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.controller.admin.attendance.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 考勤统计分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class AttendanceStatisticsPageReqVO extends PageParam { + + @Schema(description = "考勤用户id", example = "7104") + private Long userId; + + @Schema(description = "考勤组id", example = "14983") + private Long attendanceGroupId; + + @Schema(description = "考勤组名称", example = "赵六") + private String attendanceGroupName; + + @Schema(description = "班次id", example = "14364") + private Long attendanceGroupShiftId; + + @Schema(description = "班次名称", example = "李四") + private String attendanceGroupShiftName; + + @Schema(description = "日期yyyy-MM-dd格式") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private String[] dayTime; + + @Schema(description = "是否异常 0否 1是") + private Integer abnormalFlag; + + @Schema(description = "工时(时间戳)") + private Long workingHours; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ 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/attendance/vo/AttendanceStatisticsRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsRespVO.java new file mode 100644 index 00000000..9c318b83 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsRespVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.system.controller.admin.attendance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 考勤统计 Response VO") +@Data +@ExcelIgnoreUnannotated +public class AttendanceStatisticsRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24107") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "考勤用户id", example = "7104") + @ExcelProperty("考勤用户id") + private Long userId; + + @Schema(description = "考勤组id", example = "14983") + @ExcelProperty("考勤组id") + private Long attendanceGroupId; + + @Schema(description = "考勤组名称", example = "赵六") + @ExcelProperty("考勤组名称") + private String attendanceGroupName; + + @Schema(description = "班次id", example = "14364") + @ExcelProperty("班次id") + private Long attendanceGroupShiftId; + + @Schema(description = "班次名称", example = "李四") + @ExcelProperty("班次名称") + private String attendanceGroupShiftName; + + @Schema(description = "日期yyyy-MM-dd格式") + @ExcelProperty("日期yyyy-MM-dd格式") + private String dayTime; + + @Schema(description = "是否异常 0否 1是") + @ExcelProperty("是否异常 0否 1是") + private Integer abnormalFlag; + + @Schema(description = "工时(时间戳)") + @ExcelProperty("工时(时间戳)") + private Long workingHours; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ 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/attendance/vo/AttendanceStatisticsSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsSaveReqVO.java new file mode 100644 index 00000000..943a9eaa --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendanceStatisticsSaveReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.admin.attendance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import java.util.*; + +@Schema(description = "管理后台 - 考勤统计新增/修改 Request VO") +@Data +public class AttendanceStatisticsSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24107") + private Long id; + + @Schema(description = "考勤用户id", example = "7104") + private Long userId; + + @Schema(description = "考勤组id", example = "14983") + private Long attendanceGroupId; + + @Schema(description = "考勤组名称", example = "赵六") + private String attendanceGroupName; + + @Schema(description = "班次id", example = "14364") + private Long attendanceGroupShiftId; + + @Schema(description = "班次名称", example = "李四") + private String attendanceGroupShiftName; + + @Schema(description = "日期yyyy-MM-dd格式") + private String dayTime; + + @Schema(description = "是否异常 0否 1是") + private Integer abnormalFlag; + + @Schema(description = "工时(时间戳)") + private Long workingHours; + +} \ 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/groupshift/vo/AttendanceGroupShiftPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftPageReqVO.java index 8e292dcd..67b49682 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftPageReqVO.java @@ -21,6 +21,9 @@ public class AttendanceGroupShiftPageReqVO extends PageParam { @Schema(description = "班次名称", example = "张三") private String name; + @Schema(description = "是否次日(开始时间 大于 结束时间)跨天 0否 1是") + private Integer nextDayFlag; + @Schema(description = "创建时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftRespVO.java index d1f14764..dda36bd6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftRespVO.java @@ -25,6 +25,10 @@ public class AttendanceGroupShiftRespVO { @ExcelProperty("班次名称") private String name; + @Schema(description = "是否次日(开始时间 大于 结束时间)跨天 0否 1是") + @ExcelProperty("是否次日(开始时间 大于 结束时间)跨天 0否 1是") + private Integer nextDayFlag; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftSaveReqVO.java index 9bb861a6..d1030aca 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshift/vo/AttendanceGroupShiftSaveReqVO.java @@ -19,4 +19,7 @@ public class AttendanceGroupShiftSaveReqVO { @Schema(description = "班次名称", example = "张三") private String name; + @Schema(description = "是否次日(开始时间 大于 结束时间)跨天 0否 1是") + private Integer nextDayFlag; + } \ 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/groupshiftitem/vo/AttendanceGroupShiftItemPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemPageReqVO.java index 04847ee3..b64b8d81 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemPageReqVO.java @@ -35,6 +35,9 @@ public class AttendanceGroupShiftItemPageReqVO extends PageParam { @Schema(description = "是否必须 0否 1是 (如果不是必须系统会自动打卡)") private Integer mustFlag; + @Schema(description = "是否次日(开始时间 大于 结束时间)跨天 0否 1是") + private Integer nextDayFlag; + @Schema(description = "上班前打卡时间(分钟) 默认 120分钟") private Integer beforePunchTimeUpWork; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemRespVO.java index 80be916b..2a20d2ab 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemRespVO.java @@ -41,6 +41,10 @@ public class AttendanceGroupShiftItemRespVO { @ExcelProperty("是否必须 0否 1是 (如果不是必须系统会自动打卡)") private Integer mustFlag; + @Schema(description = "是否次日(开始时间 大于 结束时间)跨天 0否 1是") + @ExcelProperty("是否次日(开始时间 大于 结束时间)跨天 0否 1是") + private Integer nextDayFlag; + @Schema(description = "上班前打卡时间(分钟) 默认 120分钟") @ExcelProperty("上班前打卡时间(分钟) 默认 120分钟") private Integer beforePunchTimeUpWork; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemSaveReqVO.java index fb260838..2facf36b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/groupshiftitem/vo/AttendanceGroupShiftItemSaveReqVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.groupshiftitem.vo; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.util.*; @@ -31,6 +32,9 @@ public class AttendanceGroupShiftItemSaveReqVO { @Schema(description = "是否必须 0否 1是 (如果不是必须系统会自动打卡)") private Integer mustFlag; + @Schema(description = "是否次日(开始时间 大于 结束时间)跨天 0否 1是") + private Integer nextDayFlag; + @Schema(description = "上班前打卡时间(分钟) 默认 120分钟") private Integer beforePunchTimeUpWork; 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 bdd7c654..ab5cc5a9 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 @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo; -import lombok.*; -import java.util.*; -import io.swagger.v3.oas.annotations.media.Schema; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; + import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -24,18 +26,27 @@ public class AttendancePunchRecordPageReqVO extends PageParam { @Schema(description = "班次id", example = "10780") private Long attendanceGroupShiftId; + @Schema(description = "班次子表id", example = "10780") + private Long attendanceGroupShiftItemId; + @Schema(description = "考勤类型 1固定班制 2排班制", example = "2") private Integer type; @Schema(description = "打卡类型 1考勤机 2小程序范围打卡", example = "2") private Integer punchType; - @Schema(description = "班次考勤时间json[{start_tiem:HH:mm,start_check_flag:true,end_time:HH:mm,end_check_flah: true}]") - private String attendanceTimeJson; + @Schema(description = "上下班类型 0上班 1下班", example = "1") + private Integer workType; - @Schema(description = "打卡状态 0正常 1迟到 2缺卡 3外勤 4补卡", example = "1") + @Schema(description = "级别 1到~", example = "1") + private Integer level; + + @Schema(description = "打卡状态 0正常 1迟到 2早退 3缺卡 4补卡", example = "1") private Integer status; + @Schema(description = "是否外勤 0否 1是", example = "1") + private Integer fieldServiceFlag; + @Schema(description = "日期yyyy-MM-dd格式") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private String[] dayTime; @@ -50,6 +61,15 @@ public class AttendancePunchRecordPageReqVO extends PageParam { @Schema(description = "图片") private String image; + @Schema(description = "用户打卡地点") + private String punchAddress; + + @Schema(description = "迟到时长时间戳") + private Long lateTime; + + @Schema(description = "早退时长时间戳") + private Long leaveEarlyTime; + @Schema(description = "创建时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; 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 15067d80..3dfe6214 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 @@ -29,6 +29,10 @@ public class AttendancePunchRecordRespVO { @ExcelProperty("班次id") private Long attendanceGroupShiftId; + @Schema(description = "班次子表id", example = "10780") + @ExcelProperty("班次子表id") + private Long attendanceGroupShiftItemId; + @Schema(description = "考勤类型 1固定班制 2排班制", example = "2") @ExcelProperty("考勤类型 1固定班制 2排班制") private Integer type; @@ -37,14 +41,22 @@ public class AttendancePunchRecordRespVO { @ExcelProperty("打卡类型 1考勤机 2小程序范围打卡") private Integer punchType; - @Schema(description = "班次考勤时间json[{start_tiem:HH:mm,start_check_flag:true,end_time:HH:mm,end_check_flah: true}]") - @ExcelProperty("班次考勤时间json[{start_tiem:HH:mm,start_check_flag:true,end_time:HH:mm,end_check_flah: true}]") - private String attendanceTimeJson; + @Schema(description = "上下班类型 0上班 1下班", example = "1") + @ExcelProperty("上下班类型 0上班 1下班") + private Integer workType; - @Schema(description = "打卡状态 0正常 1迟到 2缺卡 3外勤 4补卡", example = "1") - @ExcelProperty("打卡状态 0正常 1迟到 2缺卡 3外勤 4补卡") + @Schema(description = "级别 1到~", example = "1") + @ExcelProperty("级别 1到~") + private Integer level; + + @Schema(description = "打卡状态 0正常 1迟到 2早退 3缺卡 4补卡", example = "1") + @ExcelProperty("打卡状态 0正常 1迟到 2早退 3缺卡 4补卡") private Integer status; + @Schema(description = "是否外勤 0否 1是", example = "1") + @ExcelProperty("是否外勤 0否 1是") + private Integer fieldServiceFlag; + @Schema(description = "日期yyyy-MM-dd格式") @ExcelProperty("日期yyyy-MM-dd格式") private String dayTime; @@ -61,6 +73,17 @@ public class AttendancePunchRecordRespVO { @ExcelProperty("图片") private String image; + @Schema(description = "用户打卡地点") + private String punchAddress; + + @Schema(description = "迟到时长时间戳") + @ExcelProperty("迟到时长时间戳") + private Long lateTime; + + @Schema(description = "早退时长时间戳") + @ExcelProperty("早退时长时间戳") + private Long leaveEarlyTime; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; 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 397e7019..29992b36 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,17 +1,15 @@ package cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo; +import cn.hutool.core.date.LocalDateTimeUtil; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import javax.validation.constraints.*; -import java.util.*; -import org.springframework.format.annotation.DateTimeFormat; +import lombok.Data; + import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; @Schema(description = "管理后台 - 用户打卡记录新增/修改 Request VO") @Data public class AttendancePunchRecordSaveReqVO { - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "65") private Long id; @@ -24,21 +22,33 @@ public class AttendancePunchRecordSaveReqVO { @Schema(description = "班次id", example = "10780") private Long attendanceGroupShiftId; + @Schema(description = "班次子表id", example = "10780") + private Long attendanceGroupShiftItemId; + @Schema(description = "考勤类型 1固定班制 2排班制", example = "2") private Integer type; @Schema(description = "打卡类型 1考勤机 2小程序范围打卡", example = "2") private Integer punchType; - @Schema(description = "班次考勤时间json[{start_tiem:HH:mm,start_check_flag:true,end_time:HH:mm,end_check_flah: true}]") - private String attendanceTimeJson; + @Schema(description = "上下班类型 0上班 1下班", example = "1") + private Integer workType; - @Schema(description = "打卡状态 0正常 1迟到 2缺卡 3外勤 4补卡", example = "1") + @Schema(description = "级别 1到~", example = "1") + private Integer level; + + @Schema(description = "打卡状态 0正常 1迟到 2早退 3缺卡 4补卡", example = "1") private Integer status; + @Schema(description = "是否外勤 0否 1是", example = "1") + private Integer fieldServiceFlag; + @Schema(description = "日期yyyy-MM-dd格式") private String dayTime; + @Schema(description = "应打卡时间") + private LocalDateTime shouldPunchTime; + @Schema(description = "打卡时间") private LocalDateTime punchTime; @@ -48,4 +58,32 @@ public class AttendancePunchRecordSaveReqVO { @Schema(description = "图片") private String image; + @Schema(description = "用户打卡地点") + private String punchAddress; + + + @Schema(description = "迟到时长时间戳") + private Long lateTime = (status == 1 ? LocalDateTimeUtil.between(shouldPunchTime, punchTime, ChronoUnit.MILLIS) : 0L); + + @Schema(description = "早退时长时间戳") + private Long leaveEarlyTime = (status == 2 ? LocalDateTimeUtil.between(shouldPunchTime, punchTime, ChronoUnit.MILLIS) : 0L); + + + /** + * 打卡类型(0上班卡 1下班卡 2迟到卡 3早退卡 4未到打卡时间) 转 打卡状态 0正常 1迟到 2早退 3缺卡 4补卡 + * + * @param punchType + * @return + */ + public static Integer convertStatus(Integer punchType) { + if (punchType == 0 || punchType == 1) { + return 0; + } else if (punchType == 2) { + return 1; + } else if (punchType == 3) { + return 2; + } + return null; + } + } \ 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/worklog/LogFormController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/worklog/LogFormController.java index 6089b595..f2585544 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/worklog/LogFormController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/worklog/LogFormController.java @@ -87,7 +87,6 @@ public class LogFormController { @GetMapping("/page") @Operation(summary = "获得动态模板分页") - @PreAuthorize("@ss.hasPermission('worklog:form:query')") public CommonResult> getFormPage(@Valid LogFormPageReqVO pageVO) { PageResult pageResult = formService.getFormPage(pageVO); return success(LogFormConvert.INSTANCE.convertPage(pageResult)); @@ -95,7 +94,6 @@ public class LogFormController { @GetMapping("/page-by-rule") @Operation(summary = "获得我可以使用的模板分页") - @PreAuthorize("@ss.hasPermission('worklog:form:query')") public CommonResult> getFormPageByRule(@Valid LogFormPageReqVO pageVO) { PageResult pageResult = formService.getFormPageByRule(pageVO); 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 e41f8770..6c322c7e 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,17 +1,15 @@ package cn.iocoder.yudao.module.system.controller.app.attendance; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +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.vo.AttendancePunchPageVO; +import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchVO; import cn.iocoder.yudao.module.system.service.attendance.AttendanceService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -22,15 +20,21 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @RequestMapping("/system/attendance") @Validated public class AttendanceController { - @Resource private AttendanceService attendanceService; @GetMapping("/getPunchPage") @Operation(summary = "获取考勤页面") public CommonResult getPunchPage(@ModelAttribute AttendancePunchPageDTO dto) { - Long userId = WebFrameworkUtils.getLoginUserId(); - AttendancePunchPageVO vo = attendanceService.getPunchPage(dto.setUserId(userId)); + AttendancePunchPageVO vo = attendanceService.getPunchPage(dto); + return success(vo); + } + + + @PostMapping("/punch") + @Operation(summary = "打卡") + public CommonResult punch(@RequestBody AttendancePunchDTO dto) { + AttendancePunchVO vo = attendanceService.punch(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/AttendancePunchDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendancePunchDTO.java new file mode 100644 index 00000000..8676cb79 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendancePunchDTO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.app.attendance.dto; + +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Data +@Accessors(chain = true) +public class AttendancePunchDTO { + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "用户打卡地点") + private String punchAddress; + + @Schema(description = "照片") + private String image; + + @Schema(description = "备注") + private String remark; + + /** + * 当前用户id + */ + private Long userId = getLoginUserId(); + /** + * 当前时间 + */ + private LocalDateTime localDateTime = LocalDateTime.now(); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendancePunchPageDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendancePunchPageDTO.java index 9f3b334c..143fdeb6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendancePunchPageDTO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/dto/AttendancePunchPageDTO.java @@ -5,6 +5,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.experimental.Accessors; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + @Data @Accessors(chain = true) public class AttendancePunchPageDTO { @@ -18,10 +22,18 @@ public class AttendancePunchPageDTO { /** * 当前用户id */ - private Long userId; + private Long userId = getLoginUserId(); + /** + * 是否返回考勤组考勤班次信息 + */ + private Boolean flag = false; /** * 考勤组 */ private AttendanceGroupDO activationGroup; + /** + * 当前时间 + */ + private LocalDateTime localDateTime = LocalDateTime.now(); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchPageVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchPageVO.java index 5fed6a46..a68b4c97 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchPageVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchPageVO.java @@ -1,9 +1,15 @@ package 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.service.attendance.punch.dto.AttendanceOnTheDayDTO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import java.util.List; + @Data @Accessors(chain = true) public class AttendancePunchPageVO { @@ -14,12 +20,40 @@ public class AttendancePunchPageVO { @Schema(description = "是否允许外勤打卡 0否 1是") private Integer fieldworkFlag; @Schema(description = "是否在打卡点 0否 1是") - private Integer checkInPoint; - @Schema(description = "打卡页面顶部 当天打卡记录 已打卡 0/4") - private String checkInRecordToday; - @Schema(description = "打卡类型(0上班卡 1下班卡 2迟到卡 3外勤卡)") - private String punchType; - //打卡状态 0正常 1迟到 2缺卡 3外勤 4补卡 5早退 - @Schema(description = "考勤规则/打卡记录 JSON格式 [{name:上班 09:00,punchTime:yyyy-MM-dd HH:mm:ss,status:1},{name:下班 12:00,punchTime:yyyy-MM-dd HH:mm:ss,status:2}]") - private String punchJson; + private Integer punchPoint; + @Schema(description = "打卡类型(0上班卡 1下班卡 2迟到卡 3早退卡 4未到打卡时间)") + private Integer punchType = 4; + @Schema(description = "当天考勤列表") + private List attendanceOnTheDayDTOS; + + /** + * redisKey + */ + private String redisKey; + /** + * 打卡数组当前下标 + */ + private Integer index; + /** + * 类型 0上班 1下班 + */ + private Integer type; + /** + * 应打卡时间 + */ + private LocalDateTime shouldPunchTime; + /** + * 考勤组 + */ + private AttendanceGroupDO activationGroup; + + /** + * 考勤组班次 + */ + private AttendanceGroupShiftDO attendanceGroupShiftDO; + + /** + * 考勤组班次子表 + */ + private Long attendanceGroupShiftItemId; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchVO.java new file mode 100644 index 00000000..2ed8da46 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/attendance/vo/AttendancePunchVO.java @@ -0,0 +1,23 @@ +package 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.service.attendance.punch.dto.AttendanceOnTheDayDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +@Data +@Accessors(chain = true) +public class AttendancePunchVO { + @Schema(description = "考勤组") + private AttendanceGroupDO activationGroup; + + @Schema(description = "考勤组班次") + private AttendanceGroupShiftDO attendanceGroupShiftDO; + + @Schema(description = "当天考勤列表") + private List attendanceOnTheDayDTOS; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/group/AttendanceGroupDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/group/AttendanceGroupDO.java index 599ef82f..58b2a110 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/group/AttendanceGroupDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/group/AttendanceGroupDO.java @@ -25,6 +25,12 @@ public class AttendanceGroupDO extends BaseDO { */ public static final Integer FALSE = 0; public static final Integer TRUE = 1; + /** + * 打卡类型 1考勤机 2小程序范围打卡 + */ + public static final Integer PUNCH_TYPE_ATTENDANCE_MACHINE = 1; + public static final Integer PUNCH_TYPE_MI_NI_APP = 2; + /** * 编号 */ diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshift/AttendanceGroupShiftDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshift/AttendanceGroupShiftDO.java index 8212872b..baacd05b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshift/AttendanceGroupShiftDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshift/AttendanceGroupShiftDO.java @@ -35,4 +35,8 @@ public class AttendanceGroupShiftDO extends BaseDO { * 班次名称 */ private String name; + /** + * 是否次日(开始时间 大于 结束时间)跨天 0否 1是 + */ + private Integer nextDayFlag; } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshiftitem/AttendanceGroupShiftItemDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshiftitem/AttendanceGroupShiftItemDO.java index 4ce6141d..6bcb435b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshiftitem/AttendanceGroupShiftItemDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/groupshiftitem/AttendanceGroupShiftItemDO.java @@ -1,11 +1,10 @@ package cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem; -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** * 考勤组班次子表 DO @@ -40,17 +39,21 @@ public class AttendanceGroupShiftItemDO extends BaseDO { */ private Integer level; /** - * 开始打卡时间 + * 开始打卡时间 HH:mm */ private String beginTime; /** - * 结束打卡时间 + * 结束打卡时间 HH:mm */ private String endTime; /** * 是否必须 0否 1是 (如果不是必须系统会自动打卡) */ private Integer mustFlag; + /** + * 是否次日(开始时间 大于 结束时间)跨天 0否 1是 + */ + private Integer nextDayFlag; /** * 上班前打卡时间(分钟) 默认 120分钟 */ 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 373aad5c..9e10718a 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 @@ -1,10 +1,13 @@ package cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; + import java.util.*; import java.time.LocalDateTime; import java.time.LocalDateTime; import java.time.LocalDateTime; + import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @@ -40,6 +43,10 @@ public class AttendancePunchRecordDO extends BaseDO { * 班次id */ private Long attendanceGroupShiftId; + /** + * 班次子表id + */ + private Long attendanceGroupShiftItemId; /** * 考勤类型 1固定班制 2排班制 */ @@ -48,14 +55,25 @@ public class AttendancePunchRecordDO extends BaseDO { * 打卡类型 1考勤机 2小程序范围打卡 */ private Integer punchType; + /** - * 班次考勤时间json[{start_tiem:HH:mm,start_check_flag:true,end_time:HH:mm,end_check_flah: true}] + * 上下班类型 0上班 1下班 */ - private String attendanceTimeJson; + private Integer workType; + /** - * 打卡状态 0正常 1迟到 2缺卡 3外勤 4补卡 + * 级别 1到~ + */ + private Integer level; + + /** + * 打卡状态 0正常 1迟到 2早退 3缺卡 4补卡 */ private Integer status; + /** + * 是否外勤 0否 1是 + */ + private Integer fieldServiceFlag; /** * 日期yyyy-MM-dd格式 */ @@ -73,4 +91,18 @@ public class AttendancePunchRecordDO extends BaseDO { */ private String image; + /** + * 用户打卡地点 + */ + private String punchAddress; + + /** + * 迟到时长(分) + */ + private String lateTime; + + /** + * 早退时长(分) + */ + private String 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/dal/dataobject/attendance/statistics/AttendanceStatisticsDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/statistics/AttendanceStatisticsDO.java new file mode 100644 index 00000000..ce5510f5 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/attendance/statistics/AttendanceStatisticsDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.attendance.statistics; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 考勤统计 DO + * + * @author 艾楷 + */ +@TableName("kq_attendance_statistics") +@KeySequence("kq_attendance_statistics_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AttendanceStatisticsDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 考勤用户id + */ + private Long userId; + /** + * 考勤组id + */ + private Long attendanceGroupId; + /** + * 考勤组名称 + */ + private String attendanceGroupName; + /** + * 班次id + */ + private Long attendanceGroupShiftId; + /** + * 班次名称 + */ + private String attendanceGroupShiftName; + /** + * 日期yyyy-MM-dd格式 + */ + private String dayTime; + /** + * 是否异常 0否 1是 + */ + private Integer abnormalFlag; + /** + * 工时(时间戳) + */ + private Long workingHours; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/punchrecord/AttendancePunchRecordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/punchrecord/AttendancePunchRecordMapper.java index 0cc3c806..fd8043bc 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/punchrecord/AttendancePunchRecordMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/punchrecord/AttendancePunchRecordMapper.java @@ -22,8 +22,8 @@ public interface AttendancePunchRecordMapper extends BaseMapperX countGroupId(); } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/statistics/AttendanceStatisticsMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/statistics/AttendanceStatisticsMapper.java new file mode 100644 index 00000000..ae90b87d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/attendance/statistics/AttendanceStatisticsMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.dal.mysql.attendance.statistics; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceStatisticsPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.attendance.statistics.AttendanceStatisticsDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 考勤统计 Mapper + * + * @author 艾楷 + */ +@Mapper +public interface AttendanceStatisticsMapper extends BaseMapperX { + + default PageResult selectPage(AttendanceStatisticsPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(AttendanceStatisticsDO::getUserId, reqVO.getUserId()) + .eqIfPresent(AttendanceStatisticsDO::getAttendanceGroupId, reqVO.getAttendanceGroupId()) + .likeIfPresent(AttendanceStatisticsDO::getAttendanceGroupName, reqVO.getAttendanceGroupName()) + .eqIfPresent(AttendanceStatisticsDO::getAttendanceGroupShiftId, reqVO.getAttendanceGroupShiftId()) + .likeIfPresent(AttendanceStatisticsDO::getAttendanceGroupShiftName, reqVO.getAttendanceGroupShiftName()) + .betweenIfPresent(AttendanceStatisticsDO::getDayTime, reqVO.getDayTime()) + .eqIfPresent(AttendanceStatisticsDO::getAbnormalFlag, reqVO.getAbnormalFlag()) + .eqIfPresent(AttendanceStatisticsDO::getWorkingHours, reqVO.getWorkingHours()) + .betweenIfPresent(AttendanceStatisticsDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(AttendanceStatisticsDO::getId)); + } + +} \ 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 new file mode 100644 index 00000000..e3bf4e34 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/AttendanceStatisticsJob.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.job.attendance; + +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.system.dal.mysql.attendance.statistics.AttendanceStatisticsMapper; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +@Component +@Slf4j +public class AttendanceStatisticsJob { + @Resource + private AttendanceStatisticsMapper attendanceStatisticsMapper; + + // TODO: 2024/4/22 - 每天晚上24点执行 + @XxlJob("attendanceStatisticsJob") + @TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意 + public ReturnT execute() throws Exception { + // -- 获取所有考勤内人员 - + + // 返回执行成功 + return ReturnT.SUCCESS; + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/SchedulingJob.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/SchedulingJob.java new file mode 100644 index 00000000..2b40cad1 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/attendance/SchedulingJob.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.job.attendance; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.Constants; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +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; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +@Component +@Slf4j +public class SchedulingJob { + @Resource + private AttendanceSchedulingService attendanceSchedulingService; + @Resource + private StringRedisTemplate stringRedisTemplate; + + // TODO: 2024/4/22 - 每天晚上24点执行 + @XxlJob("schedulingCycleIncrementJob") + @TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意 + public ReturnT execute() throws Exception { + // -- 获取每个排班考勤组 有多少数量(也就是周期多少日) + Map map = attendanceSchedulingService.countGroupId(); + if (MapUtil.isEmpty(map)) { + return ReturnT.SUCCESS; + } + for (Map.Entry entry : map.entrySet()) { + String schedulingKey = Constants.SCHEDULING + Constants.UNDERLINE + entry.getKey(); + String value = stringRedisTemplate.opsForValue().get(schedulingKey); + // -- 如果大于等于周期数 则重置为1 + if (StrUtil.isNotEmpty(value) && Integer.parseInt(value) >= entry.getValue()) { + stringRedisTemplate.opsForValue().set(schedulingKey, "1"); + } else { + stringRedisTemplate.opsForValue().increment(schedulingKey); + } + } + // 返回执行成功 + 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 07c263e6..8a8c04f0 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 @@ -1,8 +1,11 @@ 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.vo.AttendancePunchPageVO; +import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchVO; +import java.time.LocalDateTime; import java.util.Date; /** @@ -12,15 +15,36 @@ import java.util.Date; */ public interface AttendanceService { - + /** + * 获取打卡页面 + * + * @param attendancePunchPageDTO + * @return + */ AttendancePunchPageVO getPunchPage(AttendancePunchPageDTO attendancePunchPageDTO); /** * 判断当前传如时间是否是 节假日(节假日分 补班/放假) 补班的话返回false 放假的话返回 true * 如果不是节假日的话返回null * - * @param date + * @param localDateTime * @return */ - Boolean isHoliday(Date date); + Boolean isHoliday(LocalDateTime localDateTime); + + /** + * 计算考勤信息 + * + * @param vo + * @param dto + */ + void calculatePunch(AttendancePunchPageDTO dto, AttendancePunchPageVO vo); + + /** + * 打卡 + * + * @param attendancePunchDTO + * @return + */ + AttendancePunchVO punch(AttendancePunchDTO attendancePunchDTO); } \ 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 821fab94..b782ec80 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,25 +1,48 @@ package cn.iocoder.yudao.module.system.service.attendance; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.framework.common.Constants; import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.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.vo.AttendancePunchPageVO; +import cn.iocoder.yudao.module.system.controller.app.attendance.vo.AttendancePunchVO; import cn.iocoder.yudao.module.system.controller.app.attendance.vo.HolidayVO; 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.handler.PunchHandler; import cn.iocoder.yudao.module.system.service.attendance.group.AttendanceGroupService; +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 cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO; +import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.Date; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + /** * 考勤 实现类 */ @@ -32,6 +55,29 @@ public class AttendanceServiceImpl implements AttendanceService { private AttendanceGroupService attendanceGroupService; @Resource private StringRedisTemplate stringRedisTemplate; + @Resource + private AttendanceGroupShiftService attendanceGroupShiftService; + @Resource + private AttendanceGroupShiftItemService attendanceGroupShiftItemService; + + @Resource + private AttendancePunchRecordService attendancePunchRecordService; + + // 定义一些常量以提高代码的可读性和可维护性 + /** + * 打卡类型(0上班卡 1下班卡 2迟到卡 3早退卡 4未到打卡时间) + */ + private static final Integer PUNCH_TYPE_UP_WORK = 0; + private static final Integer PUNCH_TYPE_DOWN_WORK = 1; + private static final Integer PUNCH_TYPE_BE_LATE = 2; + private static final Integer PUNCH_TYPE_LEAVE_EARLY = 3; + private static final Integer PUNCH_TYPE_NOT_COME_YET = 4; + + /** + * 上下班标识 0上班 1下班 + */ + private static final Integer UP_WORK = 0; + private static final Integer DOWN_WORK = 1; @Override public AttendancePunchPageVO getPunchPage(AttendancePunchPageDTO dto) { @@ -43,14 +89,79 @@ public class AttendanceServiceImpl implements AttendanceService { vo.setInGroup(AttendanceGroupDO.FALSE); return vo; } + if (dto.getFlag()) { + vo.setActivationGroup(activationGroup); + } // 策略模式 - 将不同考勤类型的 分散开逻辑 - 后续好拓展 PunchService punchService = punchHandler.getResource(AttendanceGroupDO.getCodeByType(activationGroup.getType())); return punchService.getPunchPage(dto.setActivationGroup(activationGroup)); } @Override - public Boolean isHoliday(Date date) { - String dateStr = DateUtils.dateFormat(date, "yyyy-MM-dd"); + @Transactional(rollbackFor = Exception.class) + public AttendancePunchVO punch(AttendancePunchDTO dto) { + AttendancePunchPageVO pageVO = this.getPunchPage(new AttendancePunchPageDTO().setLongitude(dto.getLongitude()) + .setLatitude(dto.getLatitude()).setFlag(true).setLocalDateTime(dto.getLocalDateTime()).setUserId(dto.getUserId())); + // -- 获取当天的考勤记录 + if (AttendanceGroupDO.FALSE.equals(pageVO.getInGroup())) { + throw exception(NOT_IN_THE_ATTENDANCE_GROUP); + } + if (AttendanceGroupDO.FALSE.equals(pageVO.getTodayNeedAttendance())) { + throw exception(NO_ATTENDANCE_REQUIRED_ON_THE_DAY); + } + if (AttendanceGroupDO.FALSE.equals(pageVO.getFieldworkFlag()) && AttendanceGroupDO.FALSE.equals(pageVO.getPunchPoint())) { + throw exception(DID_NOT_ENTER_THE_ATTENDANCE_RANGE); + } + if (PUNCH_TYPE_NOT_COME_YET.equals(pageVO.getPunchType())) { + throw exception(ATTENDANCE_TIME_NOT_ARRIVED); + } + AttendancePunchVO vo = new AttendancePunchVO(); + // -- 插入数据到数据库中 - 如果插入成功 更新redis + List attendanceOnTheDayDTOS = pageVO.getAttendanceOnTheDayDTOS(); + AttendanceOnTheDayDTO dayDTO = attendanceOnTheDayDTOS.get(pageVO.getIndex()); + AttendancePunchRecordSaveReqVO attendancePunchRecordSaveReqVO = new AttendancePunchRecordSaveReqVO() + .setUserId(dto.getUserId()) + .setAttendanceGroupId(pageVO.getActivationGroup().getId()) + .setAttendanceGroupShiftId(pageVO.getAttendanceGroupShiftDO().getId()) + .setAttendanceGroupShiftItemId(pageVO.getAttendanceGroupShiftItemId()) + .setType(pageVO.getActivationGroup().getType()) + .setPunchType(AttendanceGroupDO.PUNCH_TYPE_MI_NI_APP) + .setWorkType(pageVO.getType()) + .setLevel(dayDTO.getLevel()) + .setStatus(AttendancePunchRecordSaveReqVO.convertStatus(pageVO.getPunchType())) + .setFieldServiceFlag( + (AttendanceGroupDO.TRUE.equals(pageVO.getFieldworkFlag()) && AttendanceGroupDO.FALSE.equals(pageVO.getPunchPoint())) + ? AttendanceGroupDO.TRUE : AttendanceGroupDO.FALSE) + .setDayTime(dto.getLocalDateTime().format(Constants.REPO_DATE_FORMAT)) + .setShouldPunchTime(pageVO.getShouldPunchTime()) + .setPunchTime(dto.getLocalDateTime()) + .setRemark(dto.getRemark()) + .setImage(dto.getImage()) + .setPunchAddress(dto.getPunchAddress()); + Long id = attendancePunchRecordService.createPunchRecord(attendancePunchRecordSaveReqVO); + // -- 新增成功后更新redis + if (id != null) { + dayDTO.setPunchTime(dto.getLocalDateTime().format(Constants.REPO_DATE_FORMAT)); + dayDTO.setPunchStatus(attendancePunchRecordSaveReqVO.getStatus()); + dayDTO.setFieldServiceFlag(attendancePunchRecordSaveReqVO.getFieldServiceFlag()); + dayDTO.setPunchAddress(dto.getPunchAddress()); + dayDTO.setRemark(dto.getRemark()); + dayDTO.setImage(dto.getImage()); + dayDTO.setShouldPunchTime(pageVO.getShouldPunchTime()); + dayDTO.setPunchLocalDateTime(dto.getLocalDateTime()); + String mapKey = dto.getUserId().toString(); + stringRedisTemplate.opsForHash().put(pageVO.getRedisKey(), mapKey, JSONUtil.toJsonStr(attendanceOnTheDayDTOS)); + } + vo.setActivationGroup(pageVO.getActivationGroup()); + vo.setAttendanceGroupShiftDO(pageVO.getAttendanceGroupShiftDO()); + vo.setAttendanceOnTheDayDTOS(attendanceOnTheDayDTOS); + return vo; + } + + + @Override + public Boolean isHoliday(LocalDateTime localDateTime) { + String dateStr = localDateTime.format(Constants.REPO_DATE_FORMAT); String year = dateStr.substring(0, 4); String key = "holiday_" + year; Boolean flag = stringRedisTemplate.hasKey(key); @@ -65,7 +176,179 @@ public class AttendanceServiceImpl implements AttendanceService { String lastKey = "holiday_" + (Integer.parseInt(year) - 1); stringRedisTemplate.delete(lastKey); } - return (Boolean) stringRedisTemplate.opsForHash().get(key, date); + return (Boolean) stringRedisTemplate.opsForHash().get(key, dateStr); } + + @Override + public void calculatePunch(AttendancePunchPageDTO dto, AttendancePunchPageVO vo) { + LocalDateTime localDateTime = dto.getLocalDateTime(); + AttendanceGroupDO activationGroup = dto.getActivationGroup(); + vo.setFieldworkFlag(activationGroup.getFieldworkFlag()); + // - 根据经纬度判断是否在对应班组的打卡点上 + vo.setPunchPoint(GeoUtil.distance(Double.parseDouble(dto.getLatitude()), Double.parseDouble(dto.getLongitude()) + , Double.parseDouble(activationGroup.getLatitude()), Double.parseDouble(activationGroup.getLongitude()), activationGroup.getScope())); + + // -- 获取班次 + AttendanceGroupShiftDO attendanceGroupShiftDO = attendanceGroupShiftService.getGroupShift(dto.getActivationGroup().getId()); + // -- 获取班次item + List attendanceGroupShiftItemDOList = attendanceGroupShiftItemService.getGroupShiftItemListByShiftId(dto.getActivationGroup().getId()); + + String key = Constants.ATTENDANCE + Constants.UNDERLINE + activationGroup.getId() + Constants.UNDERLINE; // + 时间 + String mapKey = dto.getUserId().toString(); + + + String yesterdayStr = LocalDateTimeUtil.offset(localDateTime, -1, ChronoUnit.DAYS).format(Constants.REPO_DATE_FORMAT); + String toDayStr = localDateTime.format(Constants.REPO_DATE_FORMAT); + String targetDayStr = null; + if (attendanceGroupShiftDO.getNextDayFlag() == null || AttendanceGroupDO.FALSE.equals(attendanceGroupShiftDO.getNextDayFlag())) { + targetDayStr = toDayStr; + } else { + // 如果跨天的话 所以不能够直接通过判断是否跨天来取redis 数据 - 而是应该获取最晚打下班卡时间判断当前时间是否在最晚打卡下班时间之后 - 如果是的话 插入今天的数据 + targetDayStr = yesterdayStr; + // -- 获取最后一个元素 + AttendanceGroupShiftItemDO attendanceOnTheDayDTO = CollUtil.getLast(attendanceGroupShiftItemDOList); + // -- 获取最晚下班打卡时间 + LocalDateTime endTime = LocalDateTime.ofInstant(DateUtils.buildHHmmTime(attendanceOnTheDayDTO.getEndTime()).toInstant(), ZoneId.systemDefault()).plusMinutes(attendanceOnTheDayDTO.getAfterPunchTimeDownWork()); + if (localDateTime.isAfter(endTime)) { + targetDayStr = toDayStr; + } + } + List attendanceOnTheDayDTOS = this.getAttendanceOnTheDay(key, mapKey, targetDayStr, attendanceGroupShiftItemDOList); + // -- 这里没有的情况 只可能是redis 数据库崩了/或者班次子表没数据 - 暂时先返回不需要考勤 + if (attendanceOnTheDayDTOS.isEmpty()) { + vo.setTodayNeedAttendance(AttendanceGroupDO.FALSE); + return; + } + + // 定义是否需要更新redis - 默认不需要更新 + boolean updateRedis = false; + int index = 0; + for (AttendanceOnTheDayDTO attendanceOnTheDayDTO : attendanceOnTheDayDTOS) { + if (AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH.equals(attendanceOnTheDayDTO.getPunchStatus())) { + LocalDateTime time = LocalDateTime.ofInstant(DateUtils.buildHHmmTime(attendanceOnTheDayDTO.getTime()).toInstant(), ZoneId.systemDefault()); + LocalDateTime lastTime = time.minusMinutes(attendanceOnTheDayDTO.getBeforePunchTime()); + LocalDateTime endTime = time.plusMinutes(attendanceOnTheDayDTO.getAfterPunchTime()); + // 确保beforePunchTime/AfterPunchTime是正数 + if (attendanceOnTheDayDTO.getBeforePunchTime() <= Constants.ZERO || attendanceOnTheDayDTO.getAfterPunchTime() <= Constants.ZERO) { + continue; // 跳过当前循环,避免错误 - 如果所有的都错了话 那么返回默认的 未到打卡时间 + } + if (LocalDateTimeUtil.isIn(localDateTime, lastTime, endTime)) { + int punchType = this.determinePunchType(localDateTime, time, UP_WORK.equals(attendanceOnTheDayDTO.getType())); + vo.setPunchType(punchType); + if (dto.getFlag()) { + vo.setType(attendanceOnTheDayDTO.getType()); + vo.setShouldPunchTime(time); + vo.setAttendanceGroupShiftItemId(attendanceOnTheDayDTO.getId()); + vo.setIndex(index); + } + break; + } else { + // 如果是未打卡 - 判断当前时间是否在打卡区间内 - 如果不在的话直接set缺卡 + // - 定时任务还没来得及刷新redis 数据 - 这里需要手动刷新 + updateRedis = true; + attendanceOnTheDayDTO.setPunchStatus(AttendanceOnTheDayDTO.PUNCH_STATUS_MISS); + } + } + index++; + } + vo.setAttendanceOnTheDayDTOS(attendanceOnTheDayDTOS); + if (dto.getFlag()) { + vo.setRedisKey(key + targetDayStr); + vo.setAttendanceGroupShiftDO(attendanceGroupShiftDO); + } + // 更新redis + if (updateRedis) { + stringRedisTemplate.opsForHash().put(key + targetDayStr, mapKey, JSONUtil.toJsonStr(attendanceOnTheDayDTOS)); + } + } + + + /** + * 确定打卡类型 - 上班打卡 忽略秒 比如 8点上班 8点0分59秒打卡不算迟到 + * + * @param localDateTime + * @param time + * @param isUpWork + * @return + */ + private int determinePunchType(LocalDateTime localDateTime, LocalDateTime time, boolean isUpWork) { + if (localDateTime.isAfter(time.plusMinutes(Constants.ONE)) && isUpWork) { + return PUNCH_TYPE_BE_LATE; + } else if (time.plusMinutes(1).isAfter(localDateTime) && isUpWork) { + return PUNCH_TYPE_UP_WORK; + } else if (localDateTime.isAfter(time) && !isUpWork) { + return PUNCH_TYPE_DOWN_WORK; + } else { + return PUNCH_TYPE_LEAVE_EARLY; + } + } + + private List getAttendanceOnTheDay(String key, String mapKey, String targetDayStr, List attendanceGroupShiftItemDOList) { + List attendanceOnTheDayDTOS = new ArrayList<>(); + // 尝试从Redis获取数据 + try { + attendanceOnTheDayDTOS = this.loadFromRedis(key, targetDayStr, mapKey); + } catch (Exception e) { + // Redis操作异常处理逻辑 + log.error("Load from Redis failed.", e); + } + + // 如果Redis中没有,则从数据库加载并存入Redis + if (attendanceOnTheDayDTOS.isEmpty()) { + attendanceOnTheDayDTOS = this.buildAttendanceOnTheDay(attendanceGroupShiftItemDOList); + this.saveToRedis(key, targetDayStr, mapKey, attendanceOnTheDayDTOS); + } + return attendanceOnTheDayDTOS; + } + + private List loadFromRedis(String key, String targetDayStr, String mapKey) { + Object o = stringRedisTemplate.opsForHash().get(key + targetDayStr, mapKey); + return o != null ? JSONUtil.toList(o.toString(), AttendanceOnTheDayDTO.class) : new ArrayList<>(); + } + + /** + * 考勤数据设置两天过期 + * + * @param key + * @param targetDayStr + * @param mapKey + * @param attendanceOnTheDayDTOS + */ + private void saveToRedis(String key, String targetDayStr, String mapKey, List attendanceOnTheDayDTOS) { + stringRedisTemplate.opsForHash().put(key + targetDayStr, mapKey, JSONUtil.toJsonStr(attendanceOnTheDayDTOS)); + //设置缓存 2天 + stringRedisTemplate.expire(key + targetDayStr, 2, TimeUnit.DAYS); + } + + private List buildAttendanceOnTheDay(List attendanceGroupShiftItemDOList) { + List attendanceOnTheDayDTOS = new ArrayList<>(); + //上下班时间 + for (AttendanceGroupShiftItemDO attendanceGroupShiftItemDO : attendanceGroupShiftItemDOList) { + AttendanceOnTheDayDTO dto = new AttendanceOnTheDayDTO(); + dto.setId(attendanceGroupShiftItemDO.getId()); + dto.setTime(attendanceGroupShiftItemDO.getBeginTime()); + dto.setPunchTime(StringUtils.EMPTY); + dto.setType(UP_WORK); + dto.setLevel(attendanceGroupShiftItemDO.getLevel()); + dto.setBeforePunchTime(attendanceGroupShiftItemDO.getBeforePunchTimeUpWork()); + dto.setAfterPunchTime(attendanceGroupShiftItemDO.getAfterPunchTimeUpWork()); + dto.setPunchStatus(AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH); + dto.setFieldServiceFlag(AttendanceGroupDO.FALSE); + attendanceOnTheDayDTOS.add(dto); + + dto = new AttendanceOnTheDayDTO(); + dto.setId(attendanceGroupShiftItemDO.getId()); + dto.setTime(attendanceGroupShiftItemDO.getEndTime()); + dto.setPunchTime(StringUtils.EMPTY); + dto.setType(DOWN_WORK); + dto.setLevel(attendanceGroupShiftItemDO.getLevel()); + dto.setBeforePunchTime(attendanceGroupShiftItemDO.getBeforePunchTimeDownWork()); + dto.setAfterPunchTime(attendanceGroupShiftItemDO.getAfterPunchTimeDownWork()); + dto.setPunchStatus(AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH); + dto.setFieldServiceFlag(AttendanceGroupDO.FALSE); + attendanceOnTheDayDTOS.add(dto); + } + return attendanceOnTheDayDTOS; + } } 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 05c018b4..fe7af87c 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 @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.service.attendance.fixed; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import cn.iocoder.yudao.framework.common.util.distance.GeoUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.controller.admin.fixed.vo.AttendanceFixedPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.fixed.vo.AttendanceFixedSaveReqVO; @@ -12,14 +11,18 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.fixed.Attendance import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO; import cn.iocoder.yudao.module.system.dal.mysql.attendance.fixed.AttendanceFixedMapper; 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 lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.time.LocalDateTime; import java.util.Date; import java.util.List; @@ -33,20 +36,19 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.FIXED_NOT_ */ @Service("fixed") @Validated +@Slf4j public class AttendanceFixedServiceImpl implements AttendanceFixedService, PunchService { @Resource - private AttendanceFixedMapper fixedMapper; + private AttendanceFixedMapper attendanceFixedMapper; @Resource @Lazy // 避免依赖循环 private AttendanceService attendanceService; - @Resource - private StringRedisTemplate stringRedisTemplate; @Override public Long createFixed(AttendanceFixedSaveReqVO createReqVO) { // 插入 AttendanceFixedDO fixed = BeanUtils.toBean(createReqVO, AttendanceFixedDO.class); - fixedMapper.insert(fixed); + attendanceFixedMapper.insert(fixed); // 返回 return fixed.getId(); } @@ -57,7 +59,7 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch validateFixedExists(updateReqVO.getId()); // 更新 AttendanceFixedDO updateObj = BeanUtils.toBean(updateReqVO, AttendanceFixedDO.class); - fixedMapper.updateById(updateObj); + attendanceFixedMapper.updateById(updateObj); } @Override @@ -65,28 +67,28 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch // 校验存在 validateFixedExists(id); // 删除 - fixedMapper.deleteById(id); + attendanceFixedMapper.deleteById(id); } private void validateFixedExists(Long id) { - if (fixedMapper.selectById(id) == null) { + if (attendanceFixedMapper.selectById(id) == null) { throw exception(FIXED_NOT_EXISTS); } } @Override public AttendanceFixedDO getFixed(Long id) { - return fixedMapper.selectById(id); + return attendanceFixedMapper.selectById(id); } @Override public PageResult getFixedPage(AttendanceFixedPageReqVO pageReqVO) { - return fixedMapper.selectPage(pageReqVO); + return attendanceFixedMapper.selectPage(pageReqVO); } @Override public AttendanceFixedDO getByGroupIdAndWeek(Long attendanceGroupId, Integer week) { - List list = fixedMapper.selectList(new LambdaQueryWrapper() + List list = attendanceFixedMapper.selectList(new LambdaQueryWrapper() .eq(attendanceGroupId != null, AttendanceFixedDO::getAttendanceGroupId, attendanceGroupId) .eq(week != null, AttendanceFixedDO::getWeekTime, week)); if (!list.isEmpty()) { @@ -98,39 +100,23 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch @Override public AttendancePunchPageVO getPunchPage(AttendancePunchPageDTO dto) { AttendancePunchPageVO vo = new AttendancePunchPageVO(); - Date thisDate = new Date(); AttendanceGroupDO activationGroup = dto.getActivationGroup(); // -- 判断是否根据节假日自动排班 - 如果是的话 - 根据排班的来 Boolean isHolidayFlag = AttendanceGroupDO.TRUE.equals(activationGroup.getAutoHolidaysFlag()) ? - attendanceService.isHoliday(thisDate) : null; + attendanceService.isHoliday(dto.getLocalDateTime()) : null; // -- 当前是节假日 并且是放假 if (isHolidayFlag != null && isHolidayFlag) { return vo.setTodayNeedAttendance(AttendanceGroupDO.FALSE); } //获取到当天是周几 - int week = DateUtils.dayOfWeek(thisDate); + int week = dto.getLocalDateTime().getDayOfWeek().getValue(); AttendanceFixedDO attendanceFixedDO = this.getByGroupIdAndWeek(activationGroup.getId(), week); // -- 当前没有班次 - 不需要考勤 if (attendanceFixedDO == null || attendanceFixedDO.getAttendanceGroupShiftId() == null) { return vo.setTodayNeedAttendance(AttendanceGroupDO.FALSE); } - vo.setFieldworkFlag(activationGroup.getFieldworkFlag()); - // - 根据经纬度判断是否在对应班组的打卡点上 - vo.setCheckInPoint(GeoUtil.distance(Double.parseDouble(dto.getLatitude()), Double.parseDouble(dto.getLongitude()) - , Double.parseDouble(activationGroup.getLatitude()), Double.parseDouble(activationGroup.getLongitude()), activationGroup.getScope())); - - - - String key = "attendance" + "_" + activationGroup.getId(); - // -- 这里的key 有个情况 - 就是上班时间和下班时间夸天了 - 所以 这里要判断下上下班时间 - - // 是否夸天 - 如果是的话 判断当前是上班卡还是下班卡 - 如果是下班卡的话 当前时间需要减去一天 - String mapKey = dto.getUserId() + "_" + DateUtils.dateFormat(thisDate, DateUtils.FORMAT_YEAR_MONTH_DAY); - Object value = stringRedisTemplate.opsForHash().get(key, mapKey); - if (value != null) { - - } - - return null; + attendanceService.calculatePunch(dto, vo); + return vo; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftService.java index b7909c1a..0c5ecd61 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshift/AttendanceGroupShiftService.java @@ -49,5 +49,4 @@ public interface AttendanceGroupShiftService { * @return 考勤组班次分页 */ PageResult getGroupShiftPage(AttendanceGroupShiftPageReqVO pageReqVO); - } \ 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/groupshiftitem/AttendanceGroupShiftItemService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshiftitem/AttendanceGroupShiftItemService.java index fb2b1b53..fedb6161 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshiftitem/AttendanceGroupShiftItemService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshiftitem/AttendanceGroupShiftItemService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.groupshiftitem.vo.Attenda import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO; import javax.validation.Valid; +import java.util.List; /** * 考勤组班次子表 Service 接口 @@ -52,4 +53,11 @@ public interface AttendanceGroupShiftItemService { */ PageResult getAttendanceGroupShiftItemPage(AttendanceGroupShiftItemPageReqVO pageReqVO); + /** + * 通过班次id获取班次列表 (按级别升序) + * + * @param attendanceGroupShiftId + * @return + */ + List getGroupShiftItemListByShiftId(Long attendanceGroupShiftId); } \ 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/groupshiftitem/AttendanceGroupShiftItemServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshiftitem/AttendanceGroupShiftItemServiceImpl.java index f01e20d4..7d0ba6ca 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshiftitem/AttendanceGroupShiftItemServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/groupshiftitem/AttendanceGroupShiftItemServiceImpl.java @@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.system.controller.admin.groupshiftitem.vo.Attenda import cn.iocoder.yudao.module.system.controller.admin.groupshiftitem.vo.AttendanceGroupShiftItemSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO; 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; import javax.annotation.Resource; +import java.util.List; /** * 考勤组班次子表 Service 实现类 @@ -56,4 +58,11 @@ public class AttendanceGroupShiftItemServiceImpl implements AttendanceGroupShift return attendanceGroupShiftItemMapper.selectPage(pageReqVO); } + @Override + public List getGroupShiftItemListByShiftId(Long attendanceGroupShiftId) { + return attendanceGroupShiftItemMapper.selectList(new LambdaQueryWrapper() + .eq(AttendanceGroupShiftItemDO::getKqAttendanceGroupShiftId, attendanceGroupShiftId) + .orderByAsc(AttendanceGroupShiftItemDO::getLevel)); + } + } \ 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/punch/dto/AttendanceOnTheDayDTO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punch/dto/AttendanceOnTheDayDTO.java new file mode 100644 index 00000000..ec8745af --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/punch/dto/AttendanceOnTheDayDTO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.system.service.attendance.punch.dto; + +import cn.hutool.core.date.LocalDateTimeUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +@Data +public class AttendanceOnTheDayDTO { + + /** + * 打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) + */ + public static final Integer PUNCH_STATUS_NORMAL = 0; + public static final Integer PUNCH_STATUS_LATE = 1; + public static final Integer PUNCH_STATUS_LEAVE_EARLY = 2; + public static final Integer PUNCH_STATUS_MISS = 3; + public static final Integer PUNCH_STATUS_UN_PUNCH = 4; + + @Schema(description = "子表id") + private Long id; + + @Schema(description = "类型 0上班 1下班") + private Integer type; + + @Schema(description = "级别 从1到~ 排序用") + private Integer level; + + @Schema(description = "应该打卡时间 HH:mm") + private String time; + + @Schema(description = "打卡时间 HH:mm") + private String punchTime; + + @Schema(description = "前打卡时间(分钟) 默认 120分钟") + private Integer beforePunchTime; + + @Schema(description = "后打卡时间(分钟) 默认 120分钟") + private Integer afterPunchTime; + + @Schema(description = "打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间)") + private Integer punchStatus; + + @Schema(description = "是否外勤 0否 1是", example = "1") + private Integer fieldServiceFlag; + + @Schema(description = "用户打卡地点") + private String punchAddress; + + @Schema(description = "打卡备注", example = "你说的对") + private String remark; + + @Schema(description = "图片") + private String image; + + @Schema(description = "应打卡时间") + private LocalDateTime shouldPunchTime; + + @Schema(description = "打卡时间") + private LocalDateTime punchLocalDateTime; + + + @Schema(description = "迟到时长时间戳") + private Long lateTime = (punchStatus == 1 ? LocalDateTimeUtil.between(shouldPunchTime, punchLocalDateTime, ChronoUnit.MILLIS) : 0L); + + @Schema(description = "早退时长时间戳") + private Long leaveEarlyTime = (punchStatus == 2 ? LocalDateTimeUtil.between(shouldPunchTime, punchLocalDateTime, ChronoUnit.MILLIS) : 0L); + +} \ 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/AttendanceSchedulingService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/scheduling/AttendanceSchedulingService.java index 2b49e784..4d16faa6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/scheduling/AttendanceSchedulingService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/scheduling/AttendanceSchedulingService.java @@ -1,9 +1,12 @@ package cn.iocoder.yudao.module.system.service.attendance.scheduling; -import javax.validation.*; -import cn.iocoder.yudao.module.system.controller.admin.scheduling.vo.*; -import cn.iocoder.yudao.module.system.dal.dataobject.attendance.scheduling.AttendanceSchedulingDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.scheduling.vo.AttendanceSchedulingPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.scheduling.vo.AttendanceSchedulingSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.attendance.scheduling.AttendanceSchedulingDO; + +import javax.validation.Valid; +import java.util.Map; /** * 排班制考勤设置 Service 接口 @@ -50,4 +53,21 @@ public interface AttendanceSchedulingService { */ PageResult getSchedulingPage(AttendanceSchedulingPageReqVO pageReqVO); + /** + * 通过班次id和第几天获取排班制考勤设置 + * + * @param attendanceGroupId + * @param indexDay + * @return + */ + AttendanceSchedulingDO getSchedulingByIndexDay(Long attendanceGroupId, Integer indexDay); + + Integer getCycleDay(Long attendanceGroupId); + + /** + * 获取每个排班考勤组 有多少数量(也就是周期多少日) + * + * @return + */ + Map countGroupId(); } \ 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 3f3c213a..2c605d50 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 @@ -1,18 +1,29 @@ package cn.iocoder.yudao.module.system.service.attendance.scheduling; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.Constants; 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.scheduling.vo.AttendanceSchedulingPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.scheduling.vo.AttendanceSchedulingSaveReqVO; import cn.iocoder.yudao.module.system.controller.app.attendance.dto.AttendancePunchPageDTO; 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.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; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SCHEDULING_NOT_EXISTS; @@ -28,6 +39,15 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ @Resource private AttendanceSchedulingMapper schedulingMapper; + @Resource + private StringRedisTemplate stringRedisTemplate; + @Resource + private AttendanceGroupShiftService attendanceGroupShiftService; + @Resource + private AttendanceGroupShiftItemService attendanceGroupShiftItemService; + @Resource + @Lazy + private AttendanceService attendanceService; @Override public Long createScheduling(AttendanceSchedulingSaveReqVO createReqVO) { @@ -72,7 +92,47 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ } @Override - public AttendancePunchPageVO getPunchPage(AttendancePunchPageDTO dto) { + public AttendanceSchedulingDO getSchedulingByIndexDay(Long attendanceGroupId, Integer indexDay) { + List list = schedulingMapper.selectList(new LambdaQueryWrapper() + .eq(AttendanceSchedulingDO::getAttendanceGroupShiftId, attendanceGroupId) + .eq(AttendanceSchedulingDO::getIndexDay, indexDay)); + if (!list.isEmpty()) { + return list.get(0); + } return null; } + + @Override + public Integer getCycleDay(Long attendanceGroupId) { + return Math.toIntExact(schedulingMapper.selectCount(new LambdaQueryWrapper() + .eq(AttendanceSchedulingDO::getAttendanceGroupShiftId, attendanceGroupId))); + } + + @Override + public Map countGroupId() { + return schedulingMapper.countGroupId(); + } + + @Override + public AttendancePunchPageVO getPunchPage(AttendancePunchPageDTO dto) { + AttendancePunchPageVO vo = new AttendancePunchPageVO(); + AttendanceGroupDO activationGroup = dto.getActivationGroup(); + //获取到当天是第几天 + String schedulingKey = Constants.SCHEDULING + Constants.UNDERLINE + activationGroup.getId(); + String indexDayObj = stringRedisTemplate.opsForValue().get(schedulingKey); + if (StrUtil.isEmpty(indexDayObj)) { + // 当作第一天来 + indexDayObj = Constants.ONE_STR; + } + Integer indexDay = Integer.valueOf(indexDayObj); + AttendanceSchedulingDO attendanceSchedulingDO = this.getSchedulingByIndexDay(activationGroup.getId(), indexDay); + // -- 当前没有班次 - 不需要考勤 + if (attendanceSchedulingDO == null || Constants.ONE.equals(attendanceSchedulingDO.getRestFlag()) || attendanceSchedulingDO.getAttendanceGroupShiftId() == null) { + return vo.setTodayNeedAttendance(AttendanceGroupDO.FALSE); + } + attendanceService.calculatePunch(dto, vo); + return vo; + } + + } \ 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/statistics/AttendanceStatisticsService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/statistics/AttendanceStatisticsService.java new file mode 100644 index 00000000..75acd571 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/statistics/AttendanceStatisticsService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.service.attendance.statistics; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceStatisticsPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceStatisticsSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.attendance.statistics.AttendanceStatisticsDO; + +import javax.validation.Valid; + +/** + * 考勤统计 Service 接口 + * + * @author 艾楷 + */ +public interface AttendanceStatisticsService { + + /** + * 创建考勤统计 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAttendanceStatistics(@Valid AttendanceStatisticsSaveReqVO createReqVO); + + /** + * 更新考勤统计 + * + * @param updateReqVO 更新信息 + */ + void updateAttendanceStatistics(@Valid AttendanceStatisticsSaveReqVO updateReqVO); + + /** + * 删除考勤统计 + * + * @param id 编号 + */ + void deleteAttendanceStatistics(Long id); + + /** + * 获得考勤统计 + * + * @param id 编号 + * @return 考勤统计 + */ + AttendanceStatisticsDO getAttendanceStatistics(Long id); + + /** + * 获得考勤统计分页 + * + * @param pageReqVO 分页查询 + * @return 考勤统计分页 + */ + PageResult getAttendanceStatisticsPage(AttendanceStatisticsPageReqVO pageReqVO); + +} \ 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/statistics/AttendanceStatisticsServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/statistics/AttendanceStatisticsServiceImpl.java new file mode 100644 index 00000000..79926a76 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/attendance/statistics/AttendanceStatisticsServiceImpl.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.system.service.attendance.statistics; + +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.attendance.vo.AttendanceStatisticsPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceStatisticsSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.attendance.statistics.AttendanceStatisticsDO; +import cn.iocoder.yudao.module.system.dal.mysql.attendance.statistics.AttendanceStatisticsMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 考勤统计 Service 实现类 + * + * @author 艾楷 + */ +@Service +@Validated +public class AttendanceStatisticsServiceImpl implements AttendanceStatisticsService { + + @Resource + private AttendanceStatisticsMapper attendanceStatisticsMapper; + + @Override + public Long createAttendanceStatistics(AttendanceStatisticsSaveReqVO createReqVO) { + // 插入 + AttendanceStatisticsDO attendanceStatistics = BeanUtils.toBean(createReqVO, AttendanceStatisticsDO.class); + attendanceStatisticsMapper.insert(attendanceStatistics); + // 返回 + return attendanceStatistics.getId(); + } + + @Override + public void updateAttendanceStatistics(AttendanceStatisticsSaveReqVO updateReqVO) { + // 更新 + AttendanceStatisticsDO updateObj = BeanUtils.toBean(updateReqVO, AttendanceStatisticsDO.class); + attendanceStatisticsMapper.updateById(updateObj); + } + + @Override + public void deleteAttendanceStatistics(Long id) { + // 删除 + attendanceStatisticsMapper.deleteById(id); + } + + + @Override + public AttendanceStatisticsDO getAttendanceStatistics(Long id) { + return attendanceStatisticsMapper.selectById(id); + } + + @Override + public PageResult getAttendanceStatisticsPage(AttendanceStatisticsPageReqVO pageReqVO) { + return attendanceStatisticsMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml index 9227a5fa..3e19b2c2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml @@ -80,7 +80,7 @@ xxl: job: enabled: true # 是否开启调度中心,默认为 true 开启 admin: - addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + addresses: http://192.168.1.105:9090/xxl-job-admin # 调度中心部署跟地址 executor: appname: ${spring.application.name} # 执行器 AppName ip: # 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务"; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/scheduling/AttendanceSchedulingMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/scheduling/AttendanceSchedulingMapper.xml index 3612b9c7..af09595b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/scheduling/AttendanceSchedulingMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/scheduling/AttendanceSchedulingMapper.xml @@ -9,4 +9,11 @@ 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ --> + \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/statistics/AttendanceStatisticsMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/statistics/AttendanceStatisticsMapper.xml new file mode 100644 index 00000000..015614eb --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/statistics/AttendanceStatisticsMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file