施工人员考勤列表、考勤记录相关接口
This commit is contained in:
		| @ -2,22 +2,18 @@ package org.dromara.project.controller; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaCheckPermission; | ||||
| import jakarta.servlet.http.HttpServletResponse; | ||||
| import jakarta.validation.constraints.NotEmpty; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.dromara.common.core.domain.R; | ||||
| import org.dromara.common.core.validate.AddGroup; | ||||
| import org.dromara.common.core.validate.EditGroup; | ||||
| import org.dromara.common.excel.utils.ExcelUtil; | ||||
| import org.dromara.common.idempotent.annotation.RepeatSubmit; | ||||
| import org.dromara.common.log.annotation.Log; | ||||
| import org.dromara.common.log.enums.BusinessType; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.common.web.core.BaseController; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceCreateReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceQueryReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceUpdateReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceQueryTwoWeekReq; | ||||
| import org.dromara.project.domain.resp.attendance.AttendanceClockDateForTwoWeekResp; | ||||
| import org.dromara.project.domain.vo.BusAttendanceVo; | ||||
| import org.dromara.project.service.IBusAttendanceService; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| @ -29,7 +25,7 @@ import java.util.List; | ||||
|  * 考勤 | ||||
|  * | ||||
|  * @author lcj | ||||
|  * @date 2025-03-26 | ||||
|  * @date 2025-04-07 | ||||
|  */ | ||||
| @Validated | ||||
| @RequiredArgsConstructor | ||||
| @ -48,6 +44,15 @@ public class BusAttendanceController extends BaseController { | ||||
|         return busAttendanceService.queryPageList(req, pageQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询近两周考勤列表 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendance:list") | ||||
|     @GetMapping("/list/clockDate/twoWeek") | ||||
|     public R<List<AttendanceClockDateForTwoWeekResp>> listClockDateForTwoWeek(AttendanceQueryTwoWeekReq req) { | ||||
|         return R.ok(busAttendanceService.listClockDateForTwoWeek(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 导出考勤列表 | ||||
|      */ | ||||
| @ -71,38 +76,4 @@ public class BusAttendanceController extends BaseController { | ||||
|         return R.ok(busAttendanceService.queryById(id)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增考勤 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendance:add") | ||||
|     @Log(title = "考勤", businessType = BusinessType.INSERT) | ||||
|     @RepeatSubmit() | ||||
|     @PostMapping() | ||||
|     public R<Long> add(@Validated(AddGroup.class) @RequestBody AttendanceCreateReq req) { | ||||
|         return R.ok(busAttendanceService.insertByBo(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendance:edit") | ||||
|     @Log(title = "考勤", businessType = BusinessType.UPDATE) | ||||
|     @RepeatSubmit() | ||||
|     @PutMapping() | ||||
|     public R<Void> edit(@Validated(EditGroup.class) @RequestBody AttendanceUpdateReq req) { | ||||
|         return toAjax(busAttendanceService.updateByBo(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除考勤 | ||||
|      * | ||||
|      * @param ids 主键串 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendance:remove") | ||||
|     @Log(title = "考勤", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{ids}") | ||||
|     public R<Void> remove(@NotEmpty(message = "主键不能为空") | ||||
|                           @PathVariable Long[] ids) { | ||||
|         return toAjax(busAttendanceService.deleteWithValidByIds(List.of(ids), true)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -17,6 +17,8 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.common.web.core.BaseController; | ||||
| import org.dromara.project.domain.exportvo.BusConstructionUserExportVo; | ||||
| import org.dromara.project.domain.req.constructionuser.*; | ||||
| import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceMonthResp; | ||||
| import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceTotalResp; | ||||
| import org.dromara.project.domain.vo.BusConstructionUserVo; | ||||
| import org.dromara.project.service.IBusConstructionUserService; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| @ -47,6 +49,25 @@ public class BusConstructionUserController extends BaseController { | ||||
|         return busConstructionUserService.queryPageList(req, pageQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询每个施工人员总的考勤列表 | ||||
|      */ | ||||
|     @SaCheckPermission("project:attendance:list") | ||||
|     @GetMapping("/list/attendance/total") | ||||
|     public TableDataInfo<ConstructionUserAttendanceTotalResp> listAttendanceTotal(ConstructionUserAttendanceQueryReq req, | ||||
|                                                                                   PageQuery pageQuery) { | ||||
|         return busConstructionUserService.queryPageAttendanceList(req, pageQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询施工人员月份考勤列表 | ||||
|      */ | ||||
|     @SaCheckPermission("project:constructionUser:list") | ||||
|     @GetMapping("/list/attendance/month") | ||||
|     public R<List<ConstructionUserAttendanceMonthResp>> listAttendanceMonth(ConstructionUserAttendanceMonthReq req) { | ||||
|         return R.ok(busConstructionUserService.queryAttendanceMonthList(req)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 导出施工人员列表 | ||||
|      */ | ||||
|  | ||||
| @ -14,7 +14,7 @@ import java.util.Date; | ||||
|  * 考勤对象 bus_attendance | ||||
|  * | ||||
|  * @author lcj | ||||
|  * @date 2025-03-26 | ||||
|  * @date 2025-04-07 | ||||
|  */ | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ -51,19 +51,24 @@ public class BusAttendance extends BaseEntity { | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 打卡时间 | ||||
|      * 上班打卡时间 | ||||
|      */ | ||||
|     private String clockTime; | ||||
|     private Date clockTime; | ||||
|  | ||||
|     /** | ||||
|      * 1正常,2迟到,3早退,4缺勤,5补卡 | ||||
|      * 打卡日期 | ||||
|      */ | ||||
|     private Date clockDate; | ||||
|  | ||||
|     /** | ||||
|      * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) | ||||
|      */ | ||||
|     private String clockStatus; | ||||
|  | ||||
|     /** | ||||
|      * 代打人员id | ||||
|      */ | ||||
|     private String pinchUserId; | ||||
|     private Long pinchUserId; | ||||
|  | ||||
|     /** | ||||
|      * 多次打卡时间记录 | ||||
| @ -75,6 +80,26 @@ public class BusAttendance extends BaseEntity { | ||||
|      */ | ||||
|     private String commuter; | ||||
|  | ||||
|     /** | ||||
|      * 打卡范围 | ||||
|      */ | ||||
|     private String punchRange; | ||||
|  | ||||
|     /** | ||||
|      * 日薪 | ||||
|      */ | ||||
|     private Long dailyWage; | ||||
|  | ||||
|     /** | ||||
|      * 经度 | ||||
|      */ | ||||
|     private String lng; | ||||
|  | ||||
|     /** | ||||
|      * 纬度 | ||||
|      */ | ||||
|     private String lat; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|  | ||||
| @ -0,0 +1,46 @@ | ||||
| package org.dromara.project.domain.enums; | ||||
|  | ||||
| import lombok.Getter; | ||||
| import org.dromara.common.core.utils.ObjectUtils; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 11:31 | ||||
|  */ | ||||
| @Getter | ||||
| public enum ConstructionUserAttendanceClockStatusEnum { | ||||
|  | ||||
|     NORMAL("正常", "1"), | ||||
|     LATE("迟到", "2"), | ||||
|     LEAVEEARLY("早退", "3"), | ||||
|     UNCLOCK("缺卡", "4"), | ||||
|     REISSUE("补卡", "5"); | ||||
|  | ||||
|     private final String text; | ||||
|  | ||||
|     private final String value; | ||||
|  | ||||
|     ConstructionUserAttendanceClockStatusEnum(String text, String value) { | ||||
|         this.text = text; | ||||
|         this.value = value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据 value 获取枚举 | ||||
|      * | ||||
|      * @param value 项目成员岗位枚举值 | ||||
|      * @return 项目成员岗位枚举 | ||||
|      */ | ||||
|     public static ConstructionUserAttendanceClockStatusEnum getEnumByValue(String value) { | ||||
|         if (ObjectUtils.isEmpty(value)) { | ||||
|             return null; | ||||
|         } | ||||
|         for (ConstructionUserAttendanceClockStatusEnum anEnum : ConstructionUserAttendanceClockStatusEnum.values()) { | ||||
|             if (anEnum.value.equals(value)) { | ||||
|                 return anEnum; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,43 @@ | ||||
| package org.dromara.project.domain.enums; | ||||
|  | ||||
| import lombok.Getter; | ||||
| import org.dromara.common.core.utils.ObjectUtils; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 12:29 | ||||
|  */ | ||||
| @Getter | ||||
| public enum ConstructionUserAttendanceCommuterEnum { | ||||
|  | ||||
|     CLOCKIN("上班", "1"), | ||||
|     CLOCKOUT("下班", "2"); | ||||
|  | ||||
|     private final String text; | ||||
|  | ||||
|     private final String value; | ||||
|  | ||||
|     ConstructionUserAttendanceCommuterEnum(String text, String value) { | ||||
|         this.text = text; | ||||
|         this.value = value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据 value 获取枚举 | ||||
|      * | ||||
|      * @param value 项目成员岗位枚举值 | ||||
|      * @return 项目成员岗位枚举 | ||||
|      */ | ||||
|     public static ConstructionUserAttendanceCommuterEnum getEnumByValue(String value) { | ||||
|         if (ObjectUtils.isEmpty(value)) { | ||||
|             return null; | ||||
|         } | ||||
|         for (ConstructionUserAttendanceCommuterEnum anEnum : ConstructionUserAttendanceCommuterEnum.values()) { | ||||
|             if (anEnum.value.equals(value)) { | ||||
|                 return anEnum; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| package org.dromara.project.domain.enums; | ||||
|  | ||||
| import lombok.Getter; | ||||
| import org.dromara.common.core.utils.ObjectUtils; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 15:38 | ||||
|  */ | ||||
| @Getter | ||||
| public enum ConstructionUserAttendanceStatusEnum { | ||||
|  | ||||
|     NORMAL("全天考勤正常", "1"), | ||||
|     ERROR("当天存在异常迟到、早退、缺卡", "2"), | ||||
|     REISSUE("当天提交过补卡申请", "3"); | ||||
|  | ||||
|     private final String text; | ||||
|  | ||||
|     private final String value; | ||||
|  | ||||
|     ConstructionUserAttendanceStatusEnum(String text, String value) { | ||||
|         this.text = text; | ||||
|         this.value = value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据 value 获取枚举 | ||||
|      * | ||||
|      * @param value 项目成员岗位枚举值 | ||||
|      * @return 项目成员岗位枚举 | ||||
|      */ | ||||
|     public static ConstructionUserAttendanceStatusEnum getEnumByValue(String value) { | ||||
|         if (ObjectUtils.isEmpty(value)) { | ||||
|             return null; | ||||
|         } | ||||
|         for (ConstructionUserAttendanceStatusEnum anEnum : ConstructionUserAttendanceStatusEnum.values()) { | ||||
|             if (anEnum.value.equals(value)) { | ||||
|                 return anEnum; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -1,57 +0,0 @@ | ||||
| package org.dromara.project.domain.req.attendance; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/3/26 9:46 | ||||
|  */ | ||||
| @Data | ||||
| public class AttendanceCreateReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1906706006468828948L; | ||||
|  | ||||
|     /** | ||||
|      * 人员id | ||||
|      */ | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
|      * 人脸照 | ||||
|      */ | ||||
|     private String facePic; | ||||
|  | ||||
|     /** | ||||
|      * 项目id | ||||
|      */ | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 1正常,2迟到,3早退,4缺勤,5补卡 | ||||
|      */ | ||||
|     private String clockStatus; | ||||
|  | ||||
|     /** | ||||
|      * 代打人员id | ||||
|      */ | ||||
|     private String pinchUserId; | ||||
|  | ||||
|     /** | ||||
|      * 多次打卡时间记录 | ||||
|      */ | ||||
|     private String clockRecord; | ||||
|  | ||||
|     /** | ||||
|      * 上下班(1上班,2下班) | ||||
|      */ | ||||
|     private String commuter; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
| } | ||||
| @ -1,9 +1,12 @@ | ||||
| package org.dromara.project.domain.req.attendance; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
| import org.springframework.format.annotation.DateTimeFormat; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
| @ -15,16 +18,6 @@ public class AttendanceQueryReq implements Serializable { | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -7188085233824968862L; | ||||
|  | ||||
|     /** | ||||
|      * 主键id | ||||
|      */ | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 人员id | ||||
|      */ | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
|      * 人员姓名 | ||||
|      */ | ||||
| @ -33,26 +26,23 @@ public class AttendanceQueryReq implements Serializable { | ||||
|     /** | ||||
|      * 项目id | ||||
|      */ | ||||
|     @NotNull(message = "项目id不能为空") | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 1正常,2迟到,3早退,4缺勤,5补卡 | ||||
|      * 班组id | ||||
|      */ | ||||
|     private Long teamId; | ||||
|  | ||||
|     /** | ||||
|      * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) | ||||
|      */ | ||||
|     private String clockStatus; | ||||
|  | ||||
|     /** | ||||
|      * 代打人员id | ||||
|      * 打卡日期 | ||||
|      */ | ||||
|     private String pinchUserId; | ||||
|  | ||||
|     /** | ||||
|      * 上下班(1上班,2下班) | ||||
|      */ | ||||
|     private String commuter; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
|     @DateTimeFormat(pattern = "yyyy-MM-dd") | ||||
|     private Date clockDate; | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,25 @@ | ||||
| package org.dromara.project.domain.req.attendance; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 9:53 | ||||
|  */ | ||||
| @Data | ||||
| public class AttendanceQueryTwoWeekReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 3193787736889938829L; | ||||
|  | ||||
|     /** | ||||
|      * 项目id | ||||
|      */ | ||||
|     @NotNull(message = "项目id不能为空") | ||||
|     private Long projectId; | ||||
|  | ||||
| } | ||||
| @ -1,72 +0,0 @@ | ||||
| package org.dromara.project.domain.req.attendance; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/3/26 9:47 | ||||
|  */ | ||||
| @Data | ||||
| public class AttendanceUpdateReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 3159243618168476248L; | ||||
|  | ||||
|     /** | ||||
|      * 主键id | ||||
|      */ | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 人员id | ||||
|      */ | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
|      * 人员姓名 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 人脸照 | ||||
|      */ | ||||
|     private String facePic; | ||||
|  | ||||
|     /** | ||||
|      * 项目id | ||||
|      */ | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 打卡时间 | ||||
|      */ | ||||
|     private String clockTime; | ||||
|  | ||||
|     /** | ||||
|      * 1正常,2迟到,3早退,4缺勤,5补卡 | ||||
|      */ | ||||
|     private String clockStatus; | ||||
|  | ||||
|     /** | ||||
|      * 代打人员id | ||||
|      */ | ||||
|     private String pinchUserId; | ||||
|  | ||||
|     /** | ||||
|      * 多次打卡时间记录 | ||||
|      */ | ||||
|     private String clockRecord; | ||||
|  | ||||
|     /** | ||||
|      * 上下班(1上班,2下班) | ||||
|      */ | ||||
|     private String commuter; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
| } | ||||
| @ -0,0 +1,30 @@ | ||||
| package org.dromara.project.domain.req.constructionuser; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 15:04 | ||||
|  */ | ||||
| @Data | ||||
| public class ConstructionUserAttendanceMonthReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -1496942176392426636L; | ||||
|  | ||||
|     /** | ||||
|      * id | ||||
|      */ | ||||
|     @NotNull(message = "用户主键不能为空") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 打卡月份 | ||||
|      */ | ||||
|     private String clockMonth; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,45 @@ | ||||
| package org.dromara.project.domain.req.constructionuser; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 10:52 | ||||
|  */ | ||||
| @Data | ||||
| public class ConstructionUserAttendanceQueryReq implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -6634291825924626633L; | ||||
|  | ||||
|     /** | ||||
|      * 人员姓名 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 项目id | ||||
|      */ | ||||
|     @NotNull(message = "项目id不能为空") | ||||
|     private Long projectId; | ||||
|  | ||||
|     /** | ||||
|      * 班组id | ||||
|      */ | ||||
|     private Long teamId; | ||||
|  | ||||
|     /** | ||||
|      * 工种 | ||||
|      */ | ||||
|     private String typeOfWork; | ||||
|  | ||||
|     /** | ||||
|      * 打卡月份 | ||||
|      */ | ||||
|     private String clockMonth; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,43 @@ | ||||
| package org.dromara.project.domain.resp.attendance; | ||||
|  | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 9:55 | ||||
|  */ | ||||
| @Data | ||||
| public class AttendanceClockDateForTwoWeekResp implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -2762312533060742243L; | ||||
|  | ||||
|     /** | ||||
|      * 打卡日期 | ||||
|      */ | ||||
|     @JsonFormat(shape = JsonFormat.Shape.STRING, | ||||
|         pattern = "yyyy-MM-dd", | ||||
|         timezone = "GMT+8") | ||||
|     private Date clockDate; | ||||
|  | ||||
|     /** | ||||
|      * 出勤人数 | ||||
|      */ | ||||
|     private Integer attendance; | ||||
|  | ||||
|     /** | ||||
|      * 半勤人数 | ||||
|      */ | ||||
|     private Integer halfAttendance; | ||||
|  | ||||
|     /** | ||||
|      * 缺勤人数 | ||||
|      */ | ||||
|     private Integer absenteeism; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,45 @@ | ||||
| package org.dromara.project.domain.resp.attendance; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import org.dromara.project.domain.BusAttendance; | ||||
|  | ||||
| import java.util.Date; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 15:27 | ||||
|  */ | ||||
| @Data | ||||
| @AllArgsConstructor | ||||
| @NoArgsConstructor | ||||
| public class AttendanceListByDay { | ||||
|  | ||||
|     /** | ||||
|      * 上下班(1上班,2下班) | ||||
|      */ | ||||
|     private String commuter; | ||||
|  | ||||
|     /** | ||||
|      * 打卡时间 | ||||
|      */ | ||||
|     private Date clockTime; | ||||
|  | ||||
|     /** | ||||
|      * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) | ||||
|      */ | ||||
|     private String clockStatus; | ||||
|  | ||||
|     public static AttendanceListByDay build(BusAttendance attendance) { | ||||
|         if (attendance == null) { | ||||
|             return null; | ||||
|         } | ||||
|         AttendanceListByDay attendanceListByDay = new AttendanceListByDay(); | ||||
|         attendanceListByDay.setCommuter(attendance.getCommuter()); | ||||
|         attendanceListByDay.setClockTime(attendance.getClockTime()); | ||||
|         attendanceListByDay.setClockStatus(attendance.getClockStatus()); | ||||
|         return attendanceListByDay; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,45 @@ | ||||
| package org.dromara.project.domain.resp.constructionuser; | ||||
|  | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||||
| import lombok.Data; | ||||
| import org.dromara.project.domain.resp.attendance.AttendanceListByDay; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 15:06 | ||||
|  */ | ||||
| @Data | ||||
| public class ConstructionUserAttendanceMonthResp implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = -413447291128760025L; | ||||
|  | ||||
|     /** | ||||
|      * 主键id | ||||
|      */ | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 打卡日期 | ||||
|      */ | ||||
|     @JsonFormat(shape = JsonFormat.Shape.STRING, | ||||
|         pattern = "yyyy-MM-dd", | ||||
|         timezone = "GMT+8") | ||||
|     private Date clockDate; | ||||
|  | ||||
|     /** | ||||
|      * 当天打卡状态 | ||||
|      */ | ||||
|     private String Status; | ||||
|  | ||||
|     /** | ||||
|      * 当天打卡记录 | ||||
|      */ | ||||
|     private List<AttendanceListByDay> attendanceList; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,64 @@ | ||||
| package org.dromara.project.domain.resp.constructionuser; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/4/7 10:16 | ||||
|  */ | ||||
| @Data | ||||
| public class ConstructionUserAttendanceTotalResp implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1335094839733429171L; | ||||
|  | ||||
|     /** | ||||
|      * 主键id | ||||
|      */ | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 人员姓名 | ||||
|      */ | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 班组id | ||||
|      */ | ||||
|     private Long teamId; | ||||
|  | ||||
|     /** | ||||
|      * 班组名称 | ||||
|      */ | ||||
|     private String teamName; | ||||
|  | ||||
|     /** | ||||
|      * 工种 | ||||
|      */ | ||||
|     private String typeOfWork; | ||||
|  | ||||
|     /** | ||||
|      * 出勤天数 | ||||
|      */ | ||||
|     private Integer attendanceDays; | ||||
|  | ||||
|     /** | ||||
|      * 迟到天数 | ||||
|      */ | ||||
|     private Integer lateDays; | ||||
|  | ||||
|     /** | ||||
|      * 早退天数 | ||||
|      */ | ||||
|     private Integer leaveEarlyDays; | ||||
|  | ||||
|     /** | ||||
|      * 缺卡天数 | ||||
|      */ | ||||
|     private Integer unClockDays; | ||||
|  | ||||
| } | ||||
| @ -2,6 +2,7 @@ package org.dromara.project.domain.vo; | ||||
|  | ||||
| import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | ||||
| import com.alibaba.excel.annotation.ExcelProperty; | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||||
| import io.github.linpeilie.annotations.AutoMapper; | ||||
| import lombok.Data; | ||||
| import org.dromara.common.excel.annotation.ExcelDictFormat; | ||||
| @ -10,13 +11,14 @@ import org.dromara.project.domain.BusAttendance; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * 考勤视图对象 bus_attendance | ||||
|  * | ||||
|  * @author lcj | ||||
|  * @date 2025-03-26 | ||||
|  * @date 2025-04-07 | ||||
|  */ | ||||
| @Data | ||||
| @ExcelIgnoreUnannotated | ||||
| @ -29,13 +31,11 @@ public class BusAttendanceVo implements Serializable { | ||||
|     /** | ||||
|      * 主键id | ||||
|      */ | ||||
|     @ExcelProperty(value = "主键id") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 人员id | ||||
|      */ | ||||
|     @ExcelProperty(value = "人员id") | ||||
|     private Long userId; | ||||
|  | ||||
|     /** | ||||
| @ -44,10 +44,21 @@ public class BusAttendanceVo implements Serializable { | ||||
|     @ExcelProperty(value = "人员姓名") | ||||
|     private String userName; | ||||
|  | ||||
|     /** | ||||
|      * 班组id | ||||
|      */ | ||||
|     private Long teamId; | ||||
|  | ||||
|     /** | ||||
|      * 工种 | ||||
|      */ | ||||
|     @ExcelProperty(value = "工种", converter = ExcelDictConvert.class) | ||||
|     @ExcelDictFormat(dictType = "type_of_work") | ||||
|     private String typeOfWork; | ||||
|  | ||||
|     /** | ||||
|      * 人脸照 | ||||
|      */ | ||||
|     @ExcelProperty(value = "人脸照") | ||||
|     private String facePic; | ||||
|  | ||||
|     /** | ||||
| @ -60,20 +71,28 @@ public class BusAttendanceVo implements Serializable { | ||||
|      * 打卡时间 | ||||
|      */ | ||||
|     @ExcelProperty(value = "打卡时间") | ||||
|     private String clockTime; | ||||
|     private Date clockTime; | ||||
|  | ||||
|     /** | ||||
|      * 1正常,2迟到,3早退,4缺勤,5补卡 | ||||
|      * 打卡日期 | ||||
|      */ | ||||
|     @ExcelProperty(value = "1正常,2迟到,3早退,4缺勤,5补卡", converter = ExcelDictConvert.class) | ||||
|     @JsonFormat(shape = JsonFormat.Shape.STRING, | ||||
|         pattern = "yyyy-MM-dd", | ||||
|         timezone = "GMT+8") | ||||
|     @ExcelProperty(value = "打卡日期") | ||||
|     private Date clockDate; | ||||
|  | ||||
|     /** | ||||
|      * 打卡状态(1正常,2迟到,3早退,4缺勤,5补卡) | ||||
|      */ | ||||
|     @ExcelProperty(value = "打卡状态", converter = ExcelDictConvert.class) | ||||
|     @ExcelDictFormat(dictType = "clock_status_type") | ||||
|     private String clockStatus; | ||||
|  | ||||
|     /** | ||||
|      * 代打人员id | ||||
|      */ | ||||
|     @ExcelProperty(value = "代打人员id") | ||||
|     private String pinchUserId; | ||||
|     private Long pinchUserId; | ||||
|  | ||||
|     /** | ||||
|      * 多次打卡时间记录 | ||||
| @ -88,11 +107,34 @@ public class BusAttendanceVo implements Serializable { | ||||
|     @ExcelDictFormat(dictType = "commuter_type") | ||||
|     private String commuter; | ||||
|  | ||||
|     /** | ||||
|      * 打卡范围 | ||||
|      */ | ||||
|     @ExcelProperty(value = "打卡范围") | ||||
|     private String punchRange; | ||||
|  | ||||
|     /** | ||||
|      * 日薪 | ||||
|      */ | ||||
|     @ExcelProperty(value = "日薪") | ||||
|     private Long dailyWage; | ||||
|  | ||||
|     /** | ||||
|      * 经度 | ||||
|      */ | ||||
|     @ExcelProperty(value = "经度") | ||||
|     private String lng; | ||||
|  | ||||
|     /** | ||||
|      * 纬度 | ||||
|      */ | ||||
|     @ExcelProperty(value = "纬度") | ||||
|     private String lat; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     @ExcelProperty(value = "备注") | ||||
|     private String remark; | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; | ||||
|  * 考勤Mapper接口 | ||||
|  * | ||||
|  * @author lcj | ||||
|  * @date 2025-03-26 | ||||
|  * @date 2025-04-07 | ||||
|  */ | ||||
| public interface BusAttendanceMapper extends BaseMapperPlus<BusAttendance, BusAttendanceVo> { | ||||
|  | ||||
|  | ||||
| @ -6,19 +6,18 @@ import com.baomidou.mybatisplus.extension.service.IService; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.project.domain.BusAttendance; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceCreateReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceQueryReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceUpdateReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceQueryTwoWeekReq; | ||||
| import org.dromara.project.domain.resp.attendance.AttendanceClockDateForTwoWeekResp; | ||||
| import org.dromara.project.domain.vo.BusAttendanceVo; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 考勤Service接口 | ||||
|  * | ||||
|  * @author lcj | ||||
|  * @date 2025-03-26 | ||||
|  * @date 2025-04-07 | ||||
|  */ | ||||
| public interface IBusAttendanceService extends IService<BusAttendance> { | ||||
|  | ||||
| @ -39,6 +38,14 @@ public interface IBusAttendanceService extends IService<BusAttendance> { | ||||
|      */ | ||||
|     TableDataInfo<BusAttendanceVo> queryPageList(AttendanceQueryReq req, PageQuery pageQuery); | ||||
|  | ||||
|     /** | ||||
|      * 查询两周内的考勤列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 考勤列表 | ||||
|      */ | ||||
|     List<AttendanceClockDateForTwoWeekResp> listClockDateForTwoWeek(AttendanceQueryTwoWeekReq req); | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的考勤列表 | ||||
|      * | ||||
| @ -47,31 +54,6 @@ public interface IBusAttendanceService extends IService<BusAttendance> { | ||||
|      */ | ||||
|     List<BusAttendanceVo> queryList(AttendanceQueryReq req); | ||||
|  | ||||
|     /** | ||||
|      * 新增考勤 | ||||
|      * | ||||
|      * @param req 考勤 | ||||
|      * @return 新增考勤id | ||||
|      */ | ||||
|     Long insertByBo(AttendanceCreateReq req); | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤 | ||||
|      * | ||||
|      * @param req 考勤 | ||||
|      * @return 是否修改成功 | ||||
|      */ | ||||
|     Boolean updateByBo(AttendanceUpdateReq req); | ||||
|  | ||||
|     /** | ||||
|      * 校验并批量删除考勤信息 | ||||
|      * | ||||
|      * @param ids     待删除的主键集合 | ||||
|      * @param isValid 是否进行有效性校验 | ||||
|      * @return 是否删除成功 | ||||
|      */ | ||||
|     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); | ||||
|  | ||||
|     /** | ||||
|      * 获取考勤视图对象 | ||||
|      * | ||||
| @ -95,4 +77,5 @@ public interface IBusAttendanceService extends IService<BusAttendance> { | ||||
|      * @return 考勤分页对象视图 | ||||
|      */ | ||||
|     Page<BusAttendanceVo> getVoPage(Page<BusAttendance> attendancePage); | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -8,6 +8,8 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.project.domain.BusConstructionUser; | ||||
| import org.dromara.project.domain.exportvo.BusConstructionUserExportVo; | ||||
| import org.dromara.project.domain.req.constructionuser.*; | ||||
| import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceMonthResp; | ||||
| import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceTotalResp; | ||||
| import org.dromara.project.domain.vo.BusConstructionUserVo; | ||||
|  | ||||
| import java.util.Collection; | ||||
| @ -38,6 +40,23 @@ public interface IBusConstructionUserService extends IService<BusConstructionUse | ||||
|      */ | ||||
|     TableDataInfo<BusConstructionUserVo> queryPageList(ConstructionUserQueryReq req, PageQuery pageQuery); | ||||
|  | ||||
|     /** | ||||
|      * 分页查询施工人员考勤列表 | ||||
|      * | ||||
|      * @param req       查询条件 | ||||
|      * @param pageQuery 分页参数 | ||||
|      * @return 施工人员考勤分页列表 | ||||
|      */ | ||||
|     TableDataInfo<ConstructionUserAttendanceTotalResp> queryPageAttendanceList(ConstructionUserAttendanceQueryReq req, PageQuery pageQuery); | ||||
|  | ||||
|     /** | ||||
|      * 查询施工人员月考勤列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 施工人员考勤月列表 | ||||
|      */ | ||||
|     List<ConstructionUserAttendanceMonthResp> queryAttendanceMonthList(ConstructionUserAttendanceMonthReq req); | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的施工人员列表 | ||||
|      * | ||||
| @ -134,4 +153,14 @@ public interface IBusConstructionUserService extends IService<BusConstructionUse | ||||
|      * @return 施工人员分页对象视图 | ||||
|      */ | ||||
|     Page<BusConstructionUserVo> getVoPage(Page<BusConstructionUser> constructionUserPage); | ||||
|  | ||||
|     /** | ||||
|      * 获取施工人员考勤分页对象视图 | ||||
|      * | ||||
|      * @param req 施工人员考勤分页查询条件 | ||||
|      * @return 施工人员考勤分页对象视图 | ||||
|      */ | ||||
|     Page<ConstructionUserAttendanceTotalResp> getAttendanceTotalVoPage(ConstructionUserAttendanceQueryReq req, | ||||
|                                                                        PageQuery pageQuery); | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
| import jakarta.annotation.Resource; | ||||
| import org.dromara.common.core.constant.HttpStatus; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.utils.ObjectUtils; | ||||
| @ -11,29 +12,41 @@ import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.project.domain.BusAttendance; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceCreateReq; | ||||
| import org.dromara.project.domain.BusProjectTeamMember; | ||||
| import org.dromara.project.domain.enums.ConstructionUserAttendanceClockStatusEnum; | ||||
| import org.dromara.project.domain.enums.ConstructionUserAttendanceCommuterEnum; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceQueryReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceUpdateReq; | ||||
| import org.dromara.project.domain.req.attendance.AttendanceQueryTwoWeekReq; | ||||
| import org.dromara.project.domain.resp.attendance.AttendanceClockDateForTwoWeekResp; | ||||
| import org.dromara.project.domain.vo.BusAttendanceVo; | ||||
| import org.dromara.project.mapper.BusAttendanceMapper; | ||||
| import org.dromara.project.service.IBusAttendanceService; | ||||
| import org.dromara.project.service.IBusProjectService; | ||||
| import org.dromara.project.service.IBusProjectTeamMemberService; | ||||
| import org.springframework.beans.BeanUtils; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.time.LocalDate; | ||||
| import java.time.ZoneId; | ||||
| import java.util.*; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
|  * 考勤Service业务层处理 | ||||
|  * | ||||
|  * @author lcj | ||||
|  * @date 2025-03-26 | ||||
|  * @date 2025-04-07 | ||||
|  */ | ||||
| @Service | ||||
| public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, BusAttendance> | ||||
|     implements IBusAttendanceService { | ||||
|  | ||||
|     @Resource | ||||
|     private IBusProjectService projectService; | ||||
|  | ||||
|     @Resource | ||||
|     private IBusProjectTeamMemberService projectTeamMemberService; | ||||
|  | ||||
|     /** | ||||
|      * 查询考勤 | ||||
|      * | ||||
| @ -62,6 +75,75 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B | ||||
|         return TableDataInfo.build(this.getVoPage(result)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询两周内的考勤列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 考勤列表 | ||||
|      */ | ||||
|     @Override | ||||
|     public List<AttendanceClockDateForTwoWeekResp> listClockDateForTwoWeek(AttendanceQueryTwoWeekReq req) { | ||||
|         Long projectId = req.getProjectId(); | ||||
|         if (projectService.getById(projectId) == null) { | ||||
|             throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         // 获取两周前的日期 | ||||
|         LocalDate twoWeeksAgoLocal = LocalDate.now().minusWeeks(2); | ||||
|         // 2. 转成Date(时分秒会被置为 00:00:00) | ||||
|         Date twoWeeksDate = Date.from(twoWeeksAgoLocal.atStartOfDay(ZoneId.systemDefault()).toInstant()); | ||||
|         // 获取两周内的考勤记录 | ||||
|         LambdaQueryWrapper<BusAttendance> lqw = new LambdaQueryWrapper<>(); | ||||
|         lqw.eq(BusAttendance::getProjectId, projectId) | ||||
|             .ge(BusAttendance::getClockDate, twoWeeksDate) | ||||
|             .orderByDesc(BusAttendance::getClockDate); | ||||
|         Map<Date, List<BusAttendance>> dateListMap = this.list(lqw) | ||||
|             .stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); | ||||
|         // 遍历每个日期,计算考勤状态 | ||||
|         List<AttendanceClockDateForTwoWeekResp> respList = new ArrayList<>(); | ||||
|         dateListMap.forEach((date, attendanceList) -> { | ||||
|             AttendanceClockDateForTwoWeekResp resp = new AttendanceClockDateForTwoWeekResp(); | ||||
|             resp.setClockDate(date); | ||||
|             // 统计考勤状态数量 | ||||
|             int attendance = 0; | ||||
|             int halfAttendance = 0; | ||||
|             int absenteeism = 0; | ||||
|             // 遍历每个用户,统计考勤状态数量 | ||||
|             Map<Long, List<BusAttendance>> userAttendanceMap = attendanceList.stream() | ||||
|                 .collect(Collectors.groupingBy(BusAttendance::getUserId)); | ||||
|             if (CollUtil.isNotEmpty(userAttendanceMap)) { | ||||
|                 for (List<BusAttendance> userAttendanceList : userAttendanceMap.values()) { | ||||
|                     String clockInStatus = null; | ||||
|                     String clockOutStatus = null; | ||||
|                     // 获取上下班状态 | ||||
|                     for (BusAttendance a : userAttendanceList) { | ||||
|                         if (ConstructionUserAttendanceCommuterEnum.CLOCKIN.getValue().equals(a.getCommuter())) { | ||||
|                             clockInStatus = a.getClockStatus(); | ||||
|                         } else if (ConstructionUserAttendanceCommuterEnum.CLOCKOUT.getValue().equals(a.getCommuter())) { | ||||
|                             clockOutStatus = a.getClockStatus(); | ||||
|                         } | ||||
|                     } | ||||
|                     // 统计考勤状态 | ||||
|                     if (ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus) | ||||
|                         && ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus)) { | ||||
|                         attendance++; | ||||
|                     } else if (ConstructionUserAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus) | ||||
|                         && ConstructionUserAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { | ||||
|                         absenteeism++; | ||||
|                     } else { | ||||
|                         halfAttendance++; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             resp.setAttendance(attendance); | ||||
|             resp.setHalfAttendance(halfAttendance); | ||||
|             resp.setAbsenteeism(absenteeism); | ||||
|             respList.add(resp); | ||||
|         }); | ||||
|         // 按打卡日期正序排列 | ||||
|         respList.sort(Comparator.comparing(AttendanceClockDateForTwoWeekResp::getClockDate)); | ||||
|         return respList; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的考勤列表 | ||||
|      * | ||||
| @ -74,75 +156,6 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B | ||||
|         return this.list(lqw).stream().map(this::getVo).toList(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增考勤 | ||||
|      * | ||||
|      * @param req 考勤 | ||||
|      * @return 新增考勤id | ||||
|      */ | ||||
|     @Override | ||||
|     public Long insertByBo(AttendanceCreateReq req) { | ||||
|         // 将实体类和 DTO 进行转换 | ||||
|         BusAttendance attendance = new BusAttendance(); | ||||
|         BeanUtils.copyProperties(req, attendance); | ||||
|         // 数据校验 | ||||
|         validEntityBeforeSave(attendance, true); | ||||
|         // 操作数据库 | ||||
|         boolean save = this.save(attendance); | ||||
|         if (!save) { | ||||
|             throw new ServiceException("新增考勤失败,数据库异常", HttpStatus.ERROR); | ||||
|         } | ||||
|         return attendance.getId(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改考勤 | ||||
|      * | ||||
|      * @param req 考勤 | ||||
|      * @return 是否修改成功 | ||||
|      */ | ||||
|     @Override | ||||
|     public Boolean updateByBo(AttendanceUpdateReq req) { | ||||
|         // 将实体类和 DTO 进行转换 | ||||
|         BusAttendance attendance = new BusAttendance(); | ||||
|         BeanUtils.copyProperties(req, attendance); | ||||
|         // 数据校验 | ||||
|         validEntityBeforeSave(attendance, false); | ||||
|         // 判断是否存在 | ||||
|         BusAttendance oldBusAttendance = this.getById(attendance.getId()); | ||||
|         if (oldBusAttendance == null) { | ||||
|             throw new ServiceException("修改考勤失败,数据不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         // 操作数据库 | ||||
|         return this.updateById(attendance); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 保存前的数据校验 | ||||
|      */ | ||||
|     private void validEntityBeforeSave(BusAttendance entity, Boolean create) { | ||||
|         // TODO 做一些数据校验,如唯一约束 | ||||
|         if (create) { | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验并批量删除考勤信息 | ||||
|      * | ||||
|      * @param ids     待删除的主键集合 | ||||
|      * @param isValid 是否进行有效性校验 | ||||
|      * @return 是否删除成功 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { | ||||
|         if (isValid) { | ||||
|             // TODO 做一些业务上的校验,判断是否需要校验 | ||||
|         } | ||||
|         return this.removeBatchByIds(ids); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取考勤视图对象 | ||||
|      * | ||||
| @ -172,24 +185,24 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B | ||||
|         if (req == null) { | ||||
|             return lqw; | ||||
|         } | ||||
|         Long id = req.getId(); | ||||
|         Long userId = req.getUserId(); | ||||
|         String userName = req.getUserName(); | ||||
|         Long projectId = req.getProjectId(); | ||||
|         Long teamId = req.getTeamId(); | ||||
|         String clockStatus = req.getClockStatus(); | ||||
|         String pinchUserId = req.getPinchUserId(); | ||||
|         String commuter = req.getCommuter(); | ||||
|         String remark = req.getRemark(); | ||||
|         Date clockDate = req.getClockDate(); | ||||
|         // 联表查询 | ||||
|         if (ObjectUtils.isNotEmpty(teamId)) { | ||||
|             List<BusProjectTeamMember> projectTeamMemberList = projectTeamMemberService.lambdaQuery() | ||||
|                 .eq(BusProjectTeamMember::getTeamId, teamId).list(); | ||||
|             List<Long> userIdList = projectTeamMemberList.stream().map(BusProjectTeamMember::getMemberId).toList(); | ||||
|             lqw.in(BusAttendance::getUserId, userIdList); | ||||
|         } | ||||
|         // 模糊查询 | ||||
|         lqw.like(StringUtils.isNotBlank(userName), BusAttendance::getUserName, userName); | ||||
|         lqw.like(StringUtils.isNotBlank(remark), BusAttendance::getRemark, remark); | ||||
|         // 精确查询 | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(id), BusAttendance::getId, id); | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(userId), BusAttendance::getUserId, userId); | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(projectId), BusAttendance::getProjectId, projectId); | ||||
|         lqw.eq(StringUtils.isNotBlank(clockStatus), BusAttendance::getClockStatus, clockStatus); | ||||
|         lqw.eq(StringUtils.isNotBlank(pinchUserId), BusAttendance::getPinchUserId, pinchUserId); | ||||
|         lqw.eq(StringUtils.isNotBlank(commuter), BusAttendance::getCommuter, commuter); | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(clockDate), BusAttendance::getClockDate, clockDate); | ||||
|         return lqw; | ||||
|     } | ||||
|  | ||||
| @ -214,4 +227,5 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B | ||||
|         attendanceVoPage.setRecords(attendanceVoList); | ||||
|         return attendanceVoPage; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -7,8 +7,10 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
| import jakarta.annotation.Resource; | ||||
| import org.dromara.common.core.constant.DateConstant; | ||||
| import org.dromara.common.core.constant.HttpStatus; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.dromara.common.core.utils.DateUtils; | ||||
| import org.dromara.common.core.utils.ObjectUtils; | ||||
| import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| @ -16,9 +18,15 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.project.constant.ConstructionUserConstant; | ||||
| import org.dromara.project.domain.*; | ||||
| import org.dromara.project.domain.enums.ConstructionUserAttendanceClockStatusEnum; | ||||
| import org.dromara.project.domain.enums.ConstructionUserAttendanceCommuterEnum; | ||||
| import org.dromara.project.domain.enums.ConstructionUserAttendanceStatusEnum; | ||||
| import org.dromara.project.domain.enums.ConstructionUserFileStatusEnum; | ||||
| import org.dromara.project.domain.exportvo.BusConstructionUserExportVo; | ||||
| import org.dromara.project.domain.req.constructionuser.*; | ||||
| import org.dromara.project.domain.resp.attendance.AttendanceListByDay; | ||||
| import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceMonthResp; | ||||
| import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceTotalResp; | ||||
| import org.dromara.project.domain.vo.BusConstructionUserVo; | ||||
| import org.dromara.project.domain.vo.BusContractorVo; | ||||
| import org.dromara.project.domain.vo.BusProjectTeamVo; | ||||
| @ -31,6 +39,7 @@ import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import java.time.YearMonth; | ||||
| import java.util.*; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| @ -76,6 +85,10 @@ public class BusConstructionUserServiceImpl extends ServiceImpl<BusConstructionU | ||||
|     @Resource | ||||
|     private ISysDictTypeService dictTypeService; | ||||
|  | ||||
|     @Lazy | ||||
|     @Resource | ||||
|     private IBusAttendanceService attendanceService; | ||||
|  | ||||
|     /** | ||||
|      * 查询施工人员 | ||||
|      * | ||||
| @ -105,6 +118,93 @@ public class BusConstructionUserServiceImpl extends ServiceImpl<BusConstructionU | ||||
|         return TableDataInfo.build(getVoPage(result)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 分页查询施工人员考勤列表 | ||||
|      * | ||||
|      * @param req       查询条件 | ||||
|      * @param pageQuery 分页参数 | ||||
|      * @return 施工人员考勤分页列表 | ||||
|      */ | ||||
|     @Override | ||||
|     public TableDataInfo<ConstructionUserAttendanceTotalResp> queryPageAttendanceList(ConstructionUserAttendanceQueryReq req, | ||||
|                                                                                       PageQuery pageQuery) { | ||||
|         return TableDataInfo.build(getAttendanceTotalVoPage(req, pageQuery)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询施工人员月考勤列表 | ||||
|      * | ||||
|      * @param req 查询条件 | ||||
|      * @return 施工人员考勤月列表 | ||||
|      */ | ||||
|     @Override | ||||
|     public List<ConstructionUserAttendanceMonthResp> queryAttendanceMonthList(ConstructionUserAttendanceMonthReq req) { | ||||
|         Long id = req.getId(); | ||||
|         String clockMonth = req.getClockMonth(); | ||||
|         if (this.getById(id) == null) { | ||||
|             throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); | ||||
|         } | ||||
|         // 解析月份 | ||||
|         YearMonth yearMonth; | ||||
|         if (StringUtils.isNotBlank(clockMonth)) { | ||||
|             // 校验月份格式 | ||||
|             if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { | ||||
|                 throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); | ||||
|             } | ||||
|             yearMonth = YearMonth.parse(clockMonth); | ||||
|         } else { | ||||
|             // 如果月份为空,则默认查询当前月份 | ||||
|             yearMonth = YearMonth.now(); | ||||
|         } | ||||
|         // 计算当月第一天 / 最后一天 | ||||
|         Date start = DateUtils.toDate(yearMonth.atDay(1)); | ||||
|         Date end = DateUtils.toDate(yearMonth.atEndOfMonth()); | ||||
|         // 查询当月考勤记录 | ||||
|         Map<Date, List<BusAttendance>> dateListMap = attendanceService.lambdaQuery() | ||||
|             .eq(BusAttendance::getUserId, id) | ||||
|             .between(BusAttendance::getClockDate, start, end) | ||||
|             .list() | ||||
|             .stream().collect(Collectors.groupingBy(BusAttendance::getClockDate)); | ||||
|         // 遍历每天,计算考勤状态 | ||||
|         List<ConstructionUserAttendanceMonthResp> respList = new ArrayList<>(); | ||||
|         dateListMap.forEach((date, attendanceList) -> { | ||||
|             ConstructionUserAttendanceMonthResp resp = new ConstructionUserAttendanceMonthResp(); | ||||
|             resp.setId(id); | ||||
|             resp.setClockDate(date); | ||||
|             List<AttendanceListByDay> attendanceListByDayList = new ArrayList<>(); | ||||
|             String clockInStatus = null; | ||||
|             String clockOutStatus = null; | ||||
|             String status; | ||||
|             for (BusAttendance attendance : attendanceList) { | ||||
|                 // 获取考勤记录 | ||||
|                 AttendanceListByDay day = AttendanceListByDay.build(attendance); | ||||
|                 attendanceListByDayList.add(day); | ||||
|                 // 获取上下班状态 | ||||
|                 if (ConstructionUserAttendanceCommuterEnum.CLOCKIN.getValue().equals(attendance.getCommuter())) { | ||||
|                     clockInStatus = attendance.getClockStatus(); | ||||
|                 } else if (ConstructionUserAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getCommuter())) { | ||||
|                     clockOutStatus = attendance.getClockStatus(); | ||||
|                 } | ||||
|             } | ||||
|             // 统计当天考勤状态 | ||||
|             if (ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus) | ||||
|                 && ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus)) { | ||||
|                 status = ConstructionUserAttendanceStatusEnum.NORMAL.getValue(); | ||||
|             } else if (ConstructionUserAttendanceClockStatusEnum.REISSUE.getValue().equals(clockInStatus) | ||||
|                 || ConstructionUserAttendanceClockStatusEnum.REISSUE.getValue().equals(clockOutStatus)) { | ||||
|                 status = ConstructionUserAttendanceStatusEnum.REISSUE.getValue(); | ||||
|             } else { | ||||
|                 status = ConstructionUserAttendanceStatusEnum.ERROR.getValue(); | ||||
|             } | ||||
|             resp.setStatus(status); | ||||
|             resp.setAttendanceList(attendanceListByDayList); | ||||
|             respList.add(resp); | ||||
|         }); | ||||
|         // 按打卡日期正序排列 | ||||
|         respList.sort(Comparator.comparing(ConstructionUserAttendanceMonthResp::getClockDate)); | ||||
|         return respList; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询符合条件的施工人员列表 | ||||
|      * | ||||
| @ -653,4 +753,141 @@ public class BusConstructionUserServiceImpl extends ServiceImpl<BusConstructionU | ||||
|         constructionUserVoPage.setRecords(constructionUserVoList); | ||||
|         return constructionUserVoPage; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取施工人员考勤分页对象视图 | ||||
|      * | ||||
|      * @param req 施工人员考勤分页查询条件 | ||||
|      * @return 施工人员考勤分页对象视图 | ||||
|      */ | ||||
|     @Override | ||||
|     public Page<ConstructionUserAttendanceTotalResp> getAttendanceTotalVoPage(ConstructionUserAttendanceQueryReq req, | ||||
|                                                                               PageQuery pageQuery) { | ||||
|         LambdaQueryWrapper<BusConstructionUser> lqw = Wrappers.lambdaQuery(); | ||||
|         // 从对象中取值 | ||||
|         String userName = req.getUserName(); | ||||
|         Long projectId = req.getProjectId(); | ||||
|         Long teamId = req.getTeamId(); | ||||
|         String typeOfWork = req.getTypeOfWork(); | ||||
|         String clockMonth = req.getClockMonth(); | ||||
|         // 联表查询 | ||||
|         LambdaQueryWrapper<BusAttendance> attendanceLqw = Wrappers.lambdaQuery(BusAttendance.class) | ||||
|             .eq(BusAttendance::getProjectId, projectId); | ||||
|         if (ObjectUtils.isNotEmpty(clockMonth)) { | ||||
|             // 校验月份格式 | ||||
|             if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { | ||||
|                 throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); | ||||
|             } | ||||
|             // 解析月份 | ||||
|             YearMonth yearMonth = YearMonth.parse(clockMonth); | ||||
|             // 计算当月第一天 / 最后一天 | ||||
|             Date start = DateUtils.toDate(yearMonth.atDay(1)); | ||||
|             Date end = DateUtils.toDate(yearMonth.atEndOfMonth()); | ||||
|             attendanceLqw.between(BusAttendance::getClockDate, start, end); | ||||
|             List<Long> userIdList = attendanceService.list(attendanceLqw) | ||||
|                 .stream().map(BusAttendance::getUserId).toList(); | ||||
|             if (CollUtil.isNotEmpty(userIdList)) { | ||||
|                 lqw.in(BusConstructionUser::getId, userIdList); | ||||
|             } | ||||
|         } | ||||
|         // 模糊查询 | ||||
|         lqw.like(StringUtils.isNotBlank(userName), BusConstructionUser::getUserName, userName); | ||||
|         // 精确查询 | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(projectId), BusConstructionUser::getProjectId, projectId); | ||||
|         lqw.eq(ObjectUtils.isNotEmpty(teamId), BusConstructionUser::getTeamId, teamId); | ||||
|         lqw.eq(StringUtils.isNotBlank(typeOfWork), BusConstructionUser::getTypeOfWork, typeOfWork); | ||||
|         // 查询当前项目下的黑名单人员 | ||||
|         List<Long> blackUserIdList = constructionBlacklistService.lambdaQuery() | ||||
|             .eq(BusConstructionBlacklist::getProjectId, projectId).list() | ||||
|             .stream().map(BusConstructionBlacklist::getUserId).toList(); | ||||
|         // 查询结果移除黑名单人员 | ||||
|         if (CollUtil.isNotEmpty(blackUserIdList)) { | ||||
|             lqw.notIn(BusConstructionUser::getId, blackUserIdList); | ||||
|         } | ||||
|         // 分页查询获取数据 | ||||
|         Page<BusConstructionUser> constructionUserPage = this.page(pageQuery.build(), lqw); | ||||
|         List<BusConstructionUser> constructionUserList = constructionUserPage.getRecords(); | ||||
|         Page<ConstructionUserAttendanceTotalResp> constructionUserAttendanceTotalPage = new Page<>( | ||||
|             constructionUserPage.getCurrent(), | ||||
|             constructionUserPage.getSize(), | ||||
|             constructionUserPage.getTotal()); | ||||
|         if (CollUtil.isEmpty(constructionUserList)) { | ||||
|             return constructionUserAttendanceTotalPage; | ||||
|         } | ||||
|         // 获取施工人员id列表 | ||||
|         List<Long> userIdList = constructionUserList.stream().map(BusConstructionUser::getId).toList(); | ||||
|         // 关联查询施工人员考勤列表 | ||||
|         attendanceLqw.in(BusAttendance::getUserId, userIdList); | ||||
|         Map<Long, List<BusAttendance>> userIdBusAttendanceListMap = attendanceService.list(attendanceLqw) | ||||
|             .stream().collect(Collectors.groupingBy(BusAttendance::getUserId)); | ||||
|         // 关联查询班组列表 | ||||
|         List<Long> teamIdList = constructionUserList.stream().map(BusConstructionUser::getTeamId).toList(); | ||||
|         Map<Long, List<BusProjectTeam>> teamIdProjectTeamListMap = projectTeamService.lambdaQuery() | ||||
|             .in(BusProjectTeam::getId, teamIdList).list() | ||||
|             .stream().collect(Collectors.groupingBy(BusProjectTeam::getId)); | ||||
|         // 填充信息 | ||||
|         List<ConstructionUserAttendanceTotalResp> userAttendanceTotalList = constructionUserList.stream().map(constructionUser -> { | ||||
|             ConstructionUserAttendanceTotalResp constructionUserAttendanceTotalResp = new ConstructionUserAttendanceTotalResp(); | ||||
|             Long id = constructionUser.getId(); | ||||
|             constructionUserAttendanceTotalResp.setId(id); | ||||
|             constructionUserAttendanceTotalResp.setUserName(constructionUser.getUserName()); | ||||
|             constructionUserAttendanceTotalResp.setTypeOfWork(constructionUser.getTypeOfWork()); | ||||
|             // 关联施工人员考勤信息 | ||||
|             int attendanceDays = 0; | ||||
|             int lateDays = 0; | ||||
|             int leaveEarlyDays = 0; | ||||
|             int unClockDays = 0; | ||||
|             if (userIdBusAttendanceListMap.containsKey(id)) { | ||||
|                 List<BusAttendance> attendanceList = userIdBusAttendanceListMap.get(id); | ||||
|                 if (CollUtil.isNotEmpty(attendanceList)) { | ||||
|                     // 1. 按打卡日期分组 | ||||
|                     Map<Date, List<BusAttendance>> dailyMap = attendanceList.stream() | ||||
|                         .collect(Collectors.groupingBy(BusAttendance::getClockDate)); | ||||
|                     // 2. 对每一天的记录计算状态 | ||||
|                     for (List<BusAttendance> dailyList : dailyMap.values()) { | ||||
|                         String clockInStatus = null; | ||||
|                         String clockOutStatus = null; | ||||
|                         // 获取上下班状态 | ||||
|                         for (BusAttendance attendance : dailyList) { | ||||
|                             if (ConstructionUserAttendanceCommuterEnum.CLOCKIN.getValue().equals(attendance.getCommuter())) { | ||||
|                                 clockInStatus = attendance.getClockStatus(); | ||||
|                             } else if (ConstructionUserAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getCommuter())) { | ||||
|                                 clockOutStatus = attendance.getClockStatus(); | ||||
|                             } | ||||
|                         } | ||||
|                         // 统计考勤状态 | ||||
|                         if (ConstructionUserAttendanceClockStatusEnum.LATE.getValue().equals(clockInStatus)) { | ||||
|                             lateDays++; | ||||
|                         } | ||||
|                         if (ConstructionUserAttendanceClockStatusEnum.LEAVEEARLY.getValue().equals(clockOutStatus)) { | ||||
|                             leaveEarlyDays++; | ||||
|                         } | ||||
|                         if (clockInStatus == null || ConstructionUserAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus)) { | ||||
|                             unClockDays++; | ||||
|                         } | ||||
|                         if (clockOutStatus == null || ConstructionUserAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) { | ||||
|                             unClockDays++; | ||||
|                         } | ||||
|                     } | ||||
|                     attendanceDays = dailyMap.size(); | ||||
|                 } | ||||
|             } | ||||
|             constructionUserAttendanceTotalResp.setAttendanceDays(attendanceDays); | ||||
|             constructionUserAttendanceTotalResp.setLateDays(lateDays); | ||||
|             constructionUserAttendanceTotalResp.setLeaveEarlyDays(leaveEarlyDays); | ||||
|             constructionUserAttendanceTotalResp.setUnClockDays(unClockDays); | ||||
|             // 关联班组信息 | ||||
|             Long userTeamId = constructionUser.getTeamId(); | ||||
|             String teamName = null; | ||||
|             if (teamIdProjectTeamListMap.containsKey(userTeamId)) { | ||||
|                 teamName = teamIdProjectTeamListMap.get(userTeamId).get(0).getTeamName(); | ||||
|             } | ||||
|             constructionUserAttendanceTotalResp.setTeamId(userTeamId); | ||||
|             constructionUserAttendanceTotalResp.setTeamName(teamName); | ||||
|             return constructionUserAttendanceTotalResp; | ||||
|         }).toList(); | ||||
|         constructionUserAttendanceTotalPage.setRecords(userAttendanceTotalList); | ||||
|         return constructionUserAttendanceTotalPage; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user