施工人员补卡记录、请假记录相关接口

This commit is contained in:
lcj
2025-04-09 10:27:02 +08:00
parent fe596e6fc1
commit 4307f073e1
38 changed files with 2355 additions and 122 deletions

View File

@ -8,6 +8,7 @@ import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@ -284,4 +285,28 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
}
}
/**
* 将包含年月日的 Date 对象和时分秒字符串合并生成一个新的 Date 对象
*
* @param date 仅包含年月日部分的 Date 对象(时分秒默认为 00:00:00
* @param timeStr 时分秒字符串,格式为 "HH:mm:ss"(例如 "15:00:00"
* @return 合并后的包含日期和时间的 Date 对象
*/
public static Date combineDateAndTime(Date date, String timeStr) {
// 转换 Date 为 LocalDate系统默认时区
Instant dateInstant = date.toInstant();
LocalDate localDate = dateInstant.atZone(ZoneId.systemDefault()).toLocalDate();
// 使用指定格式解析时间字符串为 LocalTime
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
LocalTime localTime = LocalTime.parse(timeStr, timeFormatter);
// 合并 LocalDate 和 LocalTime 成 LocalDateTime
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
// 将 LocalDateTime 转换为 Instant再转换为 Date
Instant combinedInstant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
return Date.from(combinedInstant);
}
}

View File

@ -11,9 +11,11 @@ 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.AttendanceMonthByUserIdReq;
import org.dromara.project.domain.req.attendance.AttendanceQueryReq;
import org.dromara.project.domain.req.attendance.AttendanceQueryTwoWeekReq;
import org.dromara.project.domain.resp.attendance.AttendanceClockDateForTwoWeekResp;
import org.dromara.project.domain.resp.attendance.AttendanceMonthByUserIdResp;
import org.dromara.project.domain.vo.BusAttendanceVo;
import org.dromara.project.service.IBusAttendanceService;
import org.springframework.validation.annotation.Validated;
@ -53,6 +55,15 @@ public class BusAttendanceController extends BaseController {
return R.ok(busAttendanceService.listClockDateForTwoWeek(req));
}
/**
* 查询施工人员月份考勤列表
*/
@SaCheckPermission("project:attendance:list")
@GetMapping("/list/month/byUserId")
public R<List<AttendanceMonthByUserIdResp>> listAttendanceMonthListByUserId(AttendanceMonthByUserIdReq req) {
return R.ok(busAttendanceService.listAttendanceMonthListByUserId(req));
}
/**
* 导出考勤列表
*/

View File

@ -11,6 +11,7 @@ import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.web.core.BaseController;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileQueryReq;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileSaveReq;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileTemplateReq;
import org.dromara.project.domain.vo.BusConstructionUserFileVo;
import org.dromara.project.service.IBusConstructionUserFileService;
import org.springframework.validation.annotation.Validated;
@ -59,8 +60,8 @@ public class BusConstructionUserFileController extends BaseController {
@SaCheckPermission("project:constructionUserFile:export")
@Log(title = "施工人员文件存储", businessType = BusinessType.EXPORT)
@PostMapping("/exportFileTemplate")
public void exportFileTemplate(Long projectId, HttpServletResponse response) {
busConstructionUserFileService.downloadFileTemplate(projectId, response);
public void exportFileTemplate(ConstructionUserFileTemplateReq req, HttpServletResponse response) {
busConstructionUserFileService.downloadFileTemplate(req, response);
}
/**

View File

@ -0,0 +1,94 @@
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.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.leave.LeaveManagerReviewReq;
import org.dromara.project.domain.req.leave.LeaveQueryReq;
import org.dromara.project.domain.vo.BusLeaveVo;
import org.dromara.project.service.IBusLeaveService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 施工人员请假申请
*
* @author lcj
* @date 2025-04-08
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/project/leave")
public class BusLeaveController extends BaseController {
private final IBusLeaveService busLeaveService;
/**
* 查询施工人员请假申请列表
*/
@SaCheckPermission("project:leave:list")
@GetMapping("/list")
public TableDataInfo<BusLeaveVo> list(LeaveQueryReq req, PageQuery pageQuery) {
return busLeaveService.queryPageList(req, pageQuery);
}
/**
* 导出施工人员请假申请列表
*/
@SaCheckPermission("project:leave:export")
@Log(title = "施工人员请假申请", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(LeaveQueryReq req, HttpServletResponse response) {
List<BusLeaveVo> list = busLeaveService.queryList(req);
ExcelUtil.exportExcel(list, "施工人员请假申请", BusLeaveVo.class, response);
}
/**
* 获取施工人员请假申请详细信息
*
* @param id 主键
*/
@SaCheckPermission("project:leave:query")
@GetMapping("/{id}")
public R<BusLeaveVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busLeaveService.queryById(id));
}
/**
* 管理员审核施工人员请假申请
*/
@SaCheckPermission("project:leave:edit")
@Log(title = "施工人员请假申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/review/manager")
public R<Void> managerReview(@Validated @RequestBody LeaveManagerReviewReq req) {
return toAjax(busLeaveService.managerReview(req));
}
/**
* 删除施工人员请假申请
*
* @param ids 主键串
*/
@SaCheckPermission("project:leave:remove")
@Log(title = "施工人员请假申请", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busLeaveService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,94 @@
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.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.reissuecard.ReissueCardManagerReviewReq;
import org.dromara.project.domain.req.reissuecard.ReissueCardQueryReq;
import org.dromara.project.domain.vo.BusReissueCardVo;
import org.dromara.project.service.IBusReissueCardService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 施工人员补卡申请
*
* @author lcj
* @date 2025-04-08
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/project/reissueCard")
public class BusReissueCardController extends BaseController {
private final IBusReissueCardService busReissueCardService;
/**
* 查询施工人员补卡申请列表
*/
@SaCheckPermission("project:reissueCard:list")
@GetMapping("/list")
public TableDataInfo<BusReissueCardVo> list(ReissueCardQueryReq req, PageQuery pageQuery) {
return busReissueCardService.queryPageList(req, pageQuery);
}
/**
* 导出施工人员补卡申请列表
*/
@SaCheckPermission("project:reissueCard:export")
@Log(title = "施工人员补卡申请", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ReissueCardQueryReq req, HttpServletResponse response) {
List<BusReissueCardVo> list = busReissueCardService.queryList(req);
ExcelUtil.exportExcel(list, "施工人员补卡申请", BusReissueCardVo.class, response);
}
/**
* 获取施工人员补卡申请详细信息
*
* @param id 主键
*/
@SaCheckPermission("project:reissueCard:query")
@GetMapping("/{id}")
public R<BusReissueCardVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busReissueCardService.queryById(id));
}
/**
* 管理员审核施工人员补卡申请
*/
@SaCheckPermission("project:reissueCard:edit")
@Log(title = "施工人员补卡申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/review/manager")
public R<Void> managerReview(@RequestBody ReissueCardManagerReviewReq req) {
return toAjax(busReissueCardService.managerReview(req));
}
/**
* 删除施工人员补卡申请
*
* @param ids 主键串
*/
@SaCheckPermission("project:reissueCard:remove")
@Log(title = "施工人员补卡申请", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busReissueCardService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,144 @@
package org.dromara.project.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 施工人员请假申请对象 bus_leave
*
* @author lcj
* @date 2025-04-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_leave")
public class BusLeave extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 申请人id
*/
private Long userId;
/**
* 申请人名字
*/
private String userName;
/**
* 申请请假说明
*/
private String userExplain;
/**
* 请假申请时间
*/
private Date userTime;
/**
* 请假类型1事假 2病假
*/
private String leaveType;
/**
* 请假开始时间
*/
private Date startTime;
/**
* 请假结束时间
*/
private Date endTime;
/**
* 班组长
*/
private Long gangerId;
/**
* 班组长名字
*/
private String gangerName;
/**
* 班组长意见1未读 2同意 3拒绝
*/
private String gangerOpinion;
/**
* 班组长说明
*/
private String gangerExplain;
/**
* 班组长操作时间
*/
private Date gangerTime;
/**
* 管理员id
*/
private Long managerId;
/**
* 管理员名字
*/
private String managerName;
/**
* 管理员意见1未读 2同意 3拒绝
*/
private String managerOpinion;
/**
* 管理员说明
*/
private String managerExplain;
/**
* 管理员操作时间
*/
private Date managerTime;
/**
* 项目id
*/
private Long projectId;
/**
* 班组id
*/
private Long teamId;
/**
* 备注
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -0,0 +1,139 @@
package org.dromara.project.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 施工人员补卡申请对象 bus_reissue_card
*
* @author lcj
* @date 2025-04-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_reissue_card")
public class BusReissueCard extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 申请人id
*/
private Long userId;
/**
* 申请人名字
*/
private String userName;
/**
* 申请补卡说明
*/
private String userExplain;
/**
* 补卡申请时间
*/
private Date userTime;
/**
* 班组长
*/
private Long gangerId;
/**
* 班组长名字
*/
private String gangerName;
/**
* 班组长意见1未读 2同意 3拒绝
*/
private String gangerOpinion;
/**
* 班组长说明
*/
private String gangerExplain;
/**
* 班组长操作时间
*/
private Date gangerTime;
/**
* 管理员id
*/
private Long managerId;
/**
* 管理员名字
*/
private String managerName;
/**
* 管理员意见1未读 2同意 3拒绝
*/
private String managerOpinion;
/**
* 管理员说明
*/
private String managerExplain;
/**
* 管理员操作时间
*/
private Date managerTime;
/**
* 项目id
*/
private Long projectId;
/**
* 班组id
*/
private Long teamId;
/**
* 补卡类型1上班 2下班
*/
private String reissueCardType;
/**
* 考勤表主键id
*/
private Long attendanceId;
/**
* 备注
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -1,7 +1,6 @@
package org.dromara.project.domain.enums;
import lombok.Getter;
import org.dromara.common.core.utils.ObjectUtils;
/**
* @author lcj
@ -25,22 +24,4 @@ public enum ConstructionUserAttendanceClockStatusEnum {
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;
}
}

View File

@ -1,7 +1,6 @@
package org.dromara.project.domain.enums;
import lombok.Getter;
import org.dromara.common.core.utils.ObjectUtils;
/**
* @author lcj
@ -22,22 +21,4 @@ public enum ConstructionUserAttendanceCommuterEnum {
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;
}
}

View File

@ -1,7 +1,6 @@
package org.dromara.project.domain.enums;
import lombok.Getter;
import org.dromara.common.core.utils.ObjectUtils;
/**
* @author lcj
@ -23,22 +22,4 @@ public enum ConstructionUserAttendanceStatusEnum {
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;
}
}

View File

@ -1,7 +1,6 @@
package org.dromara.project.domain.enums;
import lombok.Getter;
import org.dromara.common.core.utils.ObjectUtils;
/**
* @author lcj
@ -23,21 +22,4 @@ public enum ConstructionUserFileStatusEnum {
this.value = value;
}
/**
* 根据 value 获取枚举
*
* @param value 项目成员岗位枚举值
* @return 项目成员岗位枚举
*/
public static ConstructionUserFileStatusEnum getEnumByValue(String value) {
if (ObjectUtils.isEmpty(value)) {
return null;
}
for (ConstructionUserFileStatusEnum anEnum : ConstructionUserFileStatusEnum.values()) {
if (anEnum.value.equals(value)) {
return anEnum;
}
}
return null;
}
}

View File

@ -0,0 +1,25 @@
package org.dromara.project.domain.enums;
import lombok.Getter;
/**
* @author lcj
* @date 2025/4/8 10:55
*/
@Getter
public enum OpinionStatusEnum {
UNREAD("未读", "1"),
PASS("同意", "2"),
REFUSE("拒绝", "3");
private final String text;
private final String value;
OpinionStatusEnum(String text, String value) {
this.text = text;
this.value = value;
}
}

View File

@ -0,0 +1,57 @@
package org.dromara.project.domain.enums;
import lombok.Getter;
/**
* @author lcj
* @date 2025/4/8 16:13
*/
@Getter
public enum ReviewStatusEnum {
UNREVIEW("待审核", "1"),
INREVIEW("审核中", "2"),
AGREED("已同意", "3"),
DECLINED("已拒绝", "4");
private final String text;
private final String value;
ReviewStatusEnum(String text, String value) {
this.text = text;
this.value = value;
}
/**
* 根据班组长和管理员审核状态获取枚举
*
* @param gangerStatus 班组长审核状态
* @param managerStatus 管理员审核状态
* @return 施工人员补卡/请假审核状态
*/
public static String getEnumByOpinionStatus(String gangerStatus, String managerStatus) {
// 如果其中一个拒绝,返回 DECLINED("已拒绝", "4")
if (OpinionStatusEnum.REFUSE.getValue().equals(gangerStatus)
|| OpinionStatusEnum.REFUSE.getValue().equals(managerStatus)) {
return DECLINED.getValue();
}
// 当两个状态都未读,返回 UNREVIEW("待审核", "1")
if (OpinionStatusEnum.UNREAD.getValue().equals(gangerStatus)
&& OpinionStatusEnum.UNREAD.getValue().equals(managerStatus)) {
return UNREVIEW.getValue();
}
// 当两个状态都同意,返回 AGREED("已同意", "3")
if (OpinionStatusEnum.PASS.getValue().equals(gangerStatus)
&& OpinionStatusEnum.PASS.getValue().equals(managerStatus)) {
return AGREED.getValue();
}
// 当班组长状态不为未读 且管理员状态为未读,返回 INREVIEW("审核中", "2")
if (!OpinionStatusEnum.UNREAD.getValue().equals(gangerStatus)
&& OpinionStatusEnum.UNREAD.getValue().equals(managerStatus)) {
return INREVIEW.getValue();
}
return null;
}
}

View File

@ -0,0 +1,30 @@
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/8 17:13
*/
@Data
public class AttendanceMonthByUserIdReq implements Serializable {
@Serial
private static final long serialVersionUID = -1295339038112604001L;
/**
* 用户id
*/
@NotNull(message = "用户主键不能为空")
private Long userId;
/**
* 打卡月份
*/
private String clockMonth;
}

View File

@ -0,0 +1,56 @@
package org.dromara.project.domain.req.constructionuserfile;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author lcj
* @date 2025/4/9 9:25
*/
@Data
public class ConstructionUserFileTemplateReq implements Serializable {
@Serial
private static final long serialVersionUID = -6895109153171403950L;
/**
* 项目id
*/
@NotNull(message = "项目id不能为空")
private Long projectId;
/**
* 用户名
*/
private String userName;
/**
* 分包单位id
*/
private Long contractorId;
/**
* 班组id
*/
private Long teamId;
/**
* 工种
*/
private String typeOfWork;
/**
* 打卡
*/
private String clock;
/**
* 用户id列表
*/
private List<Long> userIdList;
}

View File

@ -0,0 +1,41 @@
package org.dromara.project.domain.req.leave;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/8 11:43
*/
@Data
public class LeaveManagerReviewReq implements Serializable {
@Serial
private static final long serialVersionUID = 3902793123554028126L;
/**
* 主键id
*/
@NotNull(message = "主键不能为空")
private Long id;
/**
* 管理员意见1未读 2同意 3拒绝
*/
@NotNull(message = "管理员意见不能为空")
private String managerOpinion;
/**
* 管理员说明
*/
private String managerExplain;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,68 @@
package org.dromara.project.domain.req.leave;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/8 11:44
*/
@Data
public class LeaveQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 43795533290515099L;
/**
* 主键id
*/
private Long id;
/**
* 申请人id
*/
private Long userId;
/**
* 申请人名字
*/
private String userName;
/**
* 请假类型1事假 2病假
*/
private String leaveType;
/**
* 班组长
*/
private Long gangerId;
/**
* 班组长名字
*/
private String gangerName;
/**
* 班组长意见1未读 2同意 3拒绝
*/
private String gangerOpinion;
/**
* 管理员意见1未读 2同意 3拒绝
*/
private String managerOpinion;
/**
* 项目id
*/
private Long projectId;
/**
* 班组id
*/
private Long teamId;
}

View File

@ -0,0 +1,41 @@
package org.dromara.project.domain.req.reissuecard;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/8 10:27
*/
@Data
public class ReissueCardManagerReviewReq implements Serializable {
@Serial
private static final long serialVersionUID = 5249263232892725923L;
/**
* 主键id
*/
@NotNull(message = "主键不能为空")
private Long id;
/**
* 管理员意见1未读 2同意 3拒绝
*/
@NotNull(message = "管理员意见不能为空")
private String managerOpinion;
/**
* 管理员说明
*/
private String managerExplain;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,73 @@
package org.dromara.project.domain.req.reissuecard;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/8 9:58
*/
@Data
public class ReissueCardQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -3708280254564807491L;
/**
* 主键id
*/
private Long id;
/**
* 申请人id
*/
private Long userId;
/**
* 申请人名字
*/
private String userName;
/**
* 班组长
*/
private Long gangerId;
/**
* 班组长名字
*/
private String gangerName;
/**
* 班组长意见1未读 2同意 3拒绝
*/
private String gangerOpinion;
/**
* 管理员意见1未读 2同意 3拒绝
*/
private String managerOpinion;
/**
* 项目id
*/
private Long projectId;
/**
* 班组id
*/
private Long teamId;
/**
* 补卡类型1上班 2下班
*/
private String reissueCardType;
/**
* 考勤表主键id
*/
private Long attendanceId;
}

View File

@ -40,4 +40,9 @@ public class AttendanceClockDateForTwoWeekResp implements Serializable {
*/
private Integer absenteeism;
/**
* 请假人数
*/
private Integer leave;
}

View File

@ -0,0 +1,44 @@
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;
import java.util.List;
/**
* @author lcj
* @date 2025/4/8 16:58
*/
@Data
public class AttendanceMonthByUserIdResp implements Serializable {
@Serial
private static final long serialVersionUID = -6172238396618801431L;
/**
* 主键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;
}

View File

@ -0,0 +1,71 @@
package org.dromara.project.domain.resp.constructionuser;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.project.domain.BusAttendance;
import org.dromara.project.domain.enums.ConstructionUserAttendanceCommuterEnum;
import java.util.Date;
import java.util.List;
/**
* @author lcj
* @date 2025/4/8 17:38
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConstructionUserAttendanceByDay {
/**
* 上班打卡时间
*/
private Date upClockDate;
/**
* 上班打卡图片id
*/
private Long upClockPicId;
/**
* 上班打卡图片
*/
private String upClockPic;
/**
* 下班打卡图片id
*/
private Long downClockPicId;
/**
* 下班打卡图片
*/
private String downClockPic;
/**
* 下班打卡时间
*/
private Date downClockDate;
public static ConstructionUserAttendanceByDay build(List<BusAttendance> attendanceList) {
if (attendanceList == null) {
return null;
}
ConstructionUserAttendanceByDay constructionUserAttendanceByDay = new ConstructionUserAttendanceByDay();
for (BusAttendance attendance : attendanceList) {
if (attendance.getCommuter().equals(ConstructionUserAttendanceCommuterEnum.CLOCKIN.getValue())) {
constructionUserAttendanceByDay.setUpClockDate(attendance.getClockDate());
if (attendance.getFacePic() != null) {
constructionUserAttendanceByDay.setUpClockPicId(Long.valueOf(attendance.getFacePic()));
}
} else if (attendance.getCommuter().equals(ConstructionUserAttendanceCommuterEnum.CLOCKOUT.getValue())) {
constructionUserAttendanceByDay.setDownClockDate(attendance.getClockDate());
if (attendance.getFacePic() != null) {
constructionUserAttendanceByDay.setDownClockPicId(Long.valueOf(attendance.getFacePic()));
}
}
}
return constructionUserAttendanceByDay;
}
}

View File

@ -2,12 +2,10 @@ 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
@ -40,6 +38,6 @@ public class ConstructionUserAttendanceMonthResp implements Serializable {
/**
* 当天打卡记录
*/
private List<AttendanceListByDay> attendanceList;
private ConstructionUserAttendanceByDay clockList;
}

View File

@ -0,0 +1,162 @@
package org.dromara.project.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.project.domain.BusLeave;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 施工人员请假申请视图对象 bus_leave
*
* @author lcj
* @date 2025-04-08
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusLeave.class)
public class BusLeaveVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
private Long id;
/**
* 申请人id
*/
private Long userId;
/**
* 申请人名字
*/
@ExcelProperty(value = "申请人名字")
private String userName;
/**
* 申请请假说明
*/
@ExcelProperty(value = "申请请假说明")
private String userExplain;
/**
* 请假申请时间
*/
@ExcelProperty(value = "请假申请时间")
private Date userTime;
/**
* 请假类型1事假 2病假
*/
@ExcelProperty(value = "请假类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "user_leave_type")
private String leaveType;
/**
* 请假开始时间
*/
@ExcelProperty(value = "请假开始时间")
private Date startTime;
/**
* 请假结束时间
*/
@ExcelProperty(value = "请假结束时间")
private Date endTime;
/**
* 项目id
*/
private Long teamId;
/**
* 项目名字
*/
private String teamName;
/**
* 项目id
*/
private Long projectId;
/**
* 班组长id
*/
private Long gangerId;
/**
* 班组长名字
*/
@ExcelProperty(value = "班组长名字")
private String gangerName;
/**
* 班组长意见1未读 2同意 3拒绝
*/
@ExcelProperty(value = "班组长意见", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "user_opinion_type")
private String gangerOpinion;
/**
* 班组长说明
*/
@ExcelProperty(value = "班组长说明")
private String gangerExplain;
/**
* 班组长操作时间
*/
@ExcelProperty(value = "班组长操作时间")
private Date gangerTime;
/**
* 管理员id
*/
private Long managerId;
/**
* 管理员名字
*/
private String managerName;
/**
* 管理员意见1未读 2同意 3拒绝
*/
@ExcelProperty(value = "管理员意见", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "user_opinion_type")
private String managerOpinion;
/**
* 管理员说明
*/
@ExcelProperty(value = "管理员说明")
private String managerExplain;
/**
* 管理员操作时间
*/
@ExcelProperty(value = "管理员操作时间")
private Date managerTime;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 审核状态
*/
private String status;
}

View File

@ -0,0 +1,143 @@
package org.dromara.project.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.project.domain.BusReissueCard;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 施工人员补卡申请视图对象 bus_reissue_card
*
* @author lcj
* @date 2025-04-08
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusReissueCard.class)
public class BusReissueCardVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
private Long id;
/**
* 申请人id
*/
private Long userId;
/**
* 申请人名字
*/
@ExcelProperty(value = "申请人名字")
private String userName;
/**
* 申请补卡说明
*/
@ExcelProperty(value = "申请补卡说明")
private String userExplain;
/**
* 补卡申请时间
*/
@ExcelProperty(value = "补卡申请时间")
private Date userTime;
/**
* 项目id
*/
private Long teamId;
/**
* 项目名字
*/
private String teamName;
/**
* 项目id
*/
private Long projectId;
/**
* 班组长id
*/
private Long gangerId;
/**
* 班组长名字
*/
@ExcelProperty(value = "班组长名字")
private String gangerName;
/**
* 班组长意见1未读 2同意 3拒绝
*/
@ExcelProperty(value = "班组长意见", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "user_opinion_type")
private String gangerOpinion;
/**
* 班组长说明
*/
@ExcelProperty(value = "班组长说明")
private String gangerExplain;
/**
* 班组长操作时间
*/
@ExcelProperty(value = "班组长操作时间")
private Date gangerTime;
/**
* 管理员id
*/
private Long managerId;
/**
* 管理员名字
*/
private String managerName;
/**
* 管理员意见1未读 2同意 3拒绝
*/
@ExcelProperty(value = "管理员意见", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "user_opinion_type")
private String managerOpinion;
/**
* 管理员说明
*/
@ExcelProperty(value = "管理员说明")
private String managerExplain;
/**
* 管理员操作时间
*/
@ExcelProperty(value = "管理员操作时间")
private Date managerTime;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 状态
*/
private String status;
}

View File

@ -0,0 +1,15 @@
package org.dromara.project.mapper;
import org.dromara.project.domain.BusLeave;
import org.dromara.project.domain.vo.BusLeaveVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 施工人员请假申请Mapper接口
*
* @author lcj
* @date 2025-04-08
*/
public interface BusLeaveMapper extends BaseMapperPlus<BusLeave, BusLeaveVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.project.mapper;
import org.dromara.project.domain.BusReissueCard;
import org.dromara.project.domain.vo.BusReissueCardVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 施工人员补卡申请Mapper接口
*
* @author lcj
* @date 2025-04-08
*/
public interface BusReissueCardMapper extends BaseMapperPlus<BusReissueCard, BusReissueCardVo> {
}

View File

@ -6,9 +6,11 @@ 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.AttendanceMonthByUserIdReq;
import org.dromara.project.domain.req.attendance.AttendanceQueryReq;
import org.dromara.project.domain.req.attendance.AttendanceQueryTwoWeekReq;
import org.dromara.project.domain.resp.attendance.AttendanceClockDateForTwoWeekResp;
import org.dromara.project.domain.resp.attendance.AttendanceMonthByUserIdResp;
import org.dromara.project.domain.vo.BusAttendanceVo;
import java.util.List;
@ -46,6 +48,14 @@ public interface IBusAttendanceService extends IService<BusAttendance> {
*/
List<AttendanceClockDateForTwoWeekResp> listClockDateForTwoWeek(AttendanceQueryTwoWeekReq req);
/**
* 查询用户每月考勤列表
*
* @param req 查询条件
* @return 考勤列表
*/
List<AttendanceMonthByUserIdResp> listAttendanceMonthListByUserId(AttendanceMonthByUserIdReq req);
/**
* 查询符合条件的考勤列表
*

View File

@ -3,9 +3,11 @@ package org.dromara.project.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.project.domain.BusConstructionUser;
import org.dromara.project.domain.BusConstructionUserFile;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileQueryReq;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileSaveReq;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileTemplateReq;
import org.dromara.project.domain.vo.BusConstructionUserFileVo;
import org.springframework.web.multipart.MultipartFile;
@ -38,10 +40,10 @@ public interface IBusConstructionUserFileService extends IService<BusConstructio
/**
* 导出施工人员文件模版zip
*
* @param projectId 项目id
* @param response 响应对象
* @param req 查询条件
* @param response 响应对象
*/
void downloadFileTemplate(Long projectId, HttpServletResponse response);
void downloadFileTemplate(ConstructionUserFileTemplateReq req, HttpServletResponse response);
/**
* 通过zip文件批量上传施工人员文件
@ -67,4 +69,12 @@ public interface IBusConstructionUserFileService extends IService<BusConstructio
*/
LambdaQueryWrapper<BusConstructionUserFile> buildQueryWrapper(ConstructionUserFileQueryReq req);
/**
* 获取施工人员查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
LambdaQueryWrapper<BusConstructionUser> buildTemplateQueryWrapper(ConstructionUserFileTemplateReq req);
}

View File

@ -0,0 +1,90 @@
package org.dromara.project.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.BusLeave;
import org.dromara.project.domain.req.leave.LeaveManagerReviewReq;
import org.dromara.project.domain.req.leave.LeaveQueryReq;
import org.dromara.project.domain.vo.BusLeaveVo;
import java.util.Collection;
import java.util.List;
/**
* 施工人员请假申请Service接口
*
* @author lcj
* @date 2025-04-08
*/
public interface IBusLeaveService extends IService<BusLeave> {
/**
* 查询施工人员请假申请
*
* @param id 主键
* @return 施工人员请假申请
*/
BusLeaveVo queryById(Long id);
/**
* 分页查询施工人员请假申请列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 施工人员请假申请分页列表
*/
TableDataInfo<BusLeaveVo> queryPageList(LeaveQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的施工人员请假申请列表
*
* @param req 查询条件
* @return 施工人员请假申请列表
*/
List<BusLeaveVo> queryList(LeaveQueryReq req);
/**
* 管理员审核施工人员请假申请
*
* @param req 管理员审核施工人员请假申请
* @return 是否审核成功
*/
Boolean managerReview(LeaveManagerReviewReq req);
/**
* 校验并批量删除施工人员请假申请信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取施工人员请假申请视图对象
*
* @param leave 施工人员请假申请对象
* @return 施工人员请假申请视图对象
*/
BusLeaveVo getVo(BusLeave leave);
/**
* 获取施工人员请假申请查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
LambdaQueryWrapper<BusLeave> buildQueryWrapper(LeaveQueryReq req);
/**
* 获取施工人员请假申请分页对象视图
*
* @param leavePage 施工人员请假申请分页对象
* @return 施工人员请假申请分页对象视图
*/
Page<BusLeaveVo> getVoPage(Page<BusLeave> leavePage);
}

View File

@ -0,0 +1,90 @@
package org.dromara.project.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.BusReissueCard;
import org.dromara.project.domain.req.reissuecard.ReissueCardManagerReviewReq;
import org.dromara.project.domain.req.reissuecard.ReissueCardQueryReq;
import org.dromara.project.domain.vo.BusReissueCardVo;
import java.util.Collection;
import java.util.List;
/**
* 施工人员补卡申请Service接口
*
* @author lcj
* @date 2025-04-08
*/
public interface IBusReissueCardService extends IService<BusReissueCard> {
/**
* 查询施工人员补卡申请
*
* @param id 主键
* @return 施工人员补卡申请
*/
BusReissueCardVo queryById(Long id);
/**
* 分页查询施工人员补卡申请列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 施工人员补卡申请分页列表
*/
TableDataInfo<BusReissueCardVo> queryPageList(ReissueCardQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的施工人员补卡申请列表
*
* @param req 查询条件
* @return 施工人员补卡申请列表
*/
List<BusReissueCardVo> queryList(ReissueCardQueryReq req);
/**
* 管理员审核施工人员补卡申请
*
* @param req 管理员审核施工人员补卡申请
* @return 是否审核成功
*/
Boolean managerReview(ReissueCardManagerReviewReq req);
/**
* 校验并批量删除施工人员补卡申请信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取施工人员补卡申请视图对象
*
* @param reissueCard 施工人员补卡申请对象
* @return 施工人员补卡申请视图对象
*/
BusReissueCardVo getVo(BusReissueCard reissueCard);
/**
* 获取施工人员补卡申请查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
LambdaQueryWrapper<BusReissueCard> buildQueryWrapper(ReissueCardQueryReq req);
/**
* 获取施工人员补卡申请分页对象视图
*
* @param reissueCardPage 施工人员补卡申请分页对象
* @return 施工人员补卡申请分页对象视图
*/
Page<BusReissueCardVo> getVoPage(Page<BusReissueCard> reissueCardPage);
}

View File

@ -5,28 +5,35 @@ 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.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;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.domain.BusAttendance;
import org.dromara.project.domain.BusLeave;
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.enums.ConstructionUserAttendanceStatusEnum;
import org.dromara.project.domain.req.attendance.AttendanceMonthByUserIdReq;
import org.dromara.project.domain.req.attendance.AttendanceQueryReq;
import org.dromara.project.domain.req.attendance.AttendanceQueryTwoWeekReq;
import org.dromara.project.domain.resp.attendance.AttendanceClockDateForTwoWeekResp;
import org.dromara.project.domain.resp.attendance.AttendanceListByDay;
import org.dromara.project.domain.resp.attendance.AttendanceMonthByUserIdResp;
import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceMonthResp;
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.dromara.project.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
@ -47,6 +54,12 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
@Resource
private IBusProjectTeamMemberService projectTeamMemberService;
@Resource
private IBusLeaveService leaveService;
@Resource
private IBusConstructionUserService constructionUserService;
/**
* 查询考勤
*
@ -98,23 +111,49 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
.orderByDesc(BusAttendance::getClockDate);
Map<Date, List<BusAttendance>> dateListMap = this.list(lqw)
.stream().collect(Collectors.groupingBy(BusAttendance::getClockDate));
// 查询两周内的请假记录
List<BusLeave> leaveList = leaveService.lambdaQuery()
.eq(BusLeave::getProjectId, projectId)
.ge(BusLeave::getEndTime, twoWeeksDate) // 请假结束时间在两周前之后的
.le(BusLeave::getStartTime, new Date()) // 请假开始时间在当前时间之前的
.list();
// 构造一个 MapKey -> LocalDate请假生效的日期Value -> 当天请假的用户ID集合Set 用于去重)
Map<LocalDate, Set<Long>> leaveMap = new HashMap<>();
LocalDate todayLocal = LocalDate.now();
for (BusLeave leave : leaveList) {
// 将请假记录的开始和结束时间转换为 LocalDate
LocalDate leaveStart = leave.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate leaveEnd = leave.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
// 计算在两周范围内的有效区间
LocalDate effectiveStart = leaveStart.isBefore(twoWeeksAgoLocal) ? twoWeeksAgoLocal : leaveStart;
LocalDate effectiveEnd = leaveEnd.isAfter(todayLocal) ? todayLocal : leaveEnd;
// 对有效区间内的每一天加入该请假用户
for (LocalDate date = effectiveStart; !date.isAfter(effectiveEnd); date = date.plusDays(1)) {
leaveMap.computeIfAbsent(date, k -> new HashSet<>()).add(leave.getUserId());
}
}
// 遍历每个日期,计算考勤状态
List<AttendanceClockDateForTwoWeekResp> respList = new ArrayList<>();
dateListMap.forEach((date, attendanceList) -> {
// 遍历从两周前到今天的所有日期
for (LocalDate localDate = twoWeeksAgoLocal; !localDate.isAfter(todayLocal); localDate = localDate.plusDays(1)) {
AttendanceClockDateForTwoWeekResp resp = new AttendanceClockDateForTwoWeekResp();
resp.setClockDate(date);
// 统计考勤状态数量
// 转换为 Date 类型(时分秒为 00:00:00
Date currentDate = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
resp.setClockDate(currentDate);
int attendance = 0;
int halfAttendance = 0;
int absenteeism = 0;
// 遍历每个用户,统计考勤状态数量
int leave = 0;
// 获取当天的考勤记录(可能为 null
List<BusAttendance> attendanceList = dateListMap.getOrDefault(currentDate, Collections.emptyList());
// 按用户分组考勤记录
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();
@ -123,8 +162,10 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
}
}
// 统计考勤状态
if (ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus)
&& ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus)) {
if ((ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockInStatus)
|| ConstructionUserAttendanceClockStatusEnum.REISSUE.getValue().equals(clockInStatus))
&& (ConstructionUserAttendanceClockStatusEnum.NORMAL.getValue().equals(clockOutStatus)
|| ConstructionUserAttendanceClockStatusEnum.REISSUE.getValue().equals(clockOutStatus))) {
attendance++;
} else if (ConstructionUserAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockInStatus)
&& ConstructionUserAttendanceClockStatusEnum.UNCLOCK.getValue().equals(clockOutStatus)) {
@ -134,13 +175,92 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
}
}
}
Set<Long> leaveUserSet = leaveMap.get(localDate);
if (leaveUserSet != null) {
leave = leaveUserSet.size();
}
resp.setAttendance(attendance);
resp.setHalfAttendance(halfAttendance);
resp.setAbsenteeism(absenteeism);
resp.setLeave(leave);
respList.add(resp);
}
// 按打卡日期正序排列
respList.sort(Comparator.comparing(AttendanceClockDateForTwoWeekResp::getClockDate));
return respList;
}
/**
* 查询用户每月考勤列表
*
* @param req 查询条件
* @return 考勤列表
*/
@Override
public List<AttendanceMonthByUserIdResp> listAttendanceMonthListByUserId(AttendanceMonthByUserIdReq req) {
Long userId = req.getUserId();
String clockMonth = req.getClockMonth();
if (constructionUserService.getById(userId) == 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 = this.lambdaQuery()
.eq(BusAttendance::getUserId, userId)
.between(BusAttendance::getClockDate, start, end)
.list()
.stream().collect(Collectors.groupingBy(BusAttendance::getClockDate));
// 遍历每天,计算考勤状态
List<AttendanceMonthByUserIdResp> respList = new ArrayList<>();
dateListMap.forEach((date, attendanceList) -> {
AttendanceMonthByUserIdResp resp = new AttendanceMonthByUserIdResp();
resp.setId(userId);
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(AttendanceClockDateForTwoWeekResp::getClockDate));
respList.sort(Comparator.comparing(AttendanceMonthByUserIdResp::getClockDate));
return respList;
}

View File

@ -26,6 +26,7 @@ import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileQueryReq;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileReq;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileSaveReq;
import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileTemplateReq;
import org.dromara.project.domain.vo.BusConstructionUserFileVo;
import org.dromara.project.mapper.BusConstructionUserFileMapper;
import org.dromara.project.service.IBusConstructionBlacklistService;
@ -105,42 +106,37 @@ public class BusConstructionUserFileServiceImpl extends ServiceImpl<BusConstruct
/**
* 导出施工人员文件模版zip
*
* @param projectId 项目id
* @param response 响应对象
* @param req 项目id
* @param response 响应对象
*/
@Override
public void downloadFileTemplate(Long projectId, HttpServletResponse response) {
public void downloadFileTemplate(ConstructionUserFileTemplateReq req, HttpServletResponse response) {
// 1. 校验项目是否存在
Long projectId = req.getProjectId();
BusProject project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST);
}
// 2. 根据项目id获取黑名单施工人员
List<Long> blacklistUserIdList = constructionBlacklistService.lambdaQuery()
.eq(BusConstructionBlacklist::getProjectId, projectId)
.list().stream().map(BusConstructionBlacklist::getUserId).toList();
// 3. 根据项目id获取对应施工人员
List<BusConstructionUser> constructionUserList = constructionUserService.lambdaQuery()
.notIn(BusConstructionUser::getId, blacklistUserIdList)
.eq(BusConstructionUser::getProjectId, projectId).list();
// 4. 根目录名称
// 2. 查询施工人员列表
List<BusConstructionUser> constructionUserList = constructionUserService.list(this.buildTemplateQueryWrapper(req));
// 3. 根目录名称
String randomString = project.getId() + "_" + RandomUtil.randomString(8);
String rootFolder = project.getShortName() + "_" + randomString + "/";
// 6. 设置响应头
// 4. 设置响应头
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=\"" + randomString + ".zip\"");
// 7. 获取输出流,并封装为 ZipOutputStream
// 5. 获取输出流,并封装为 ZipOutputStream
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// 8. 根目录下创建一个文件夹
// 6. 根目录下创建一个文件夹
zipOut.putNextEntry(new ZipEntry(rootFolder));
zipOut.closeEntry();
// 9. 对每个人,创建其文件夹,再在其中创建子文件夹(如“三级安全教育”、“体检报告”...)及文件
// 7. 对每个人,创建其文件夹,再在其中创建子文件夹(如“三级安全教育”、“体检报告”...)及文件
for (BusConstructionUser constructionUser : constructionUserList) {
String personFolder = rootFolder + constructionUser.getUserName() + "-" + constructionUser.getId() + "/";
// 9.1. 写入个人文件夹条目
// 7.1. 写入个人文件夹条目
zipOut.putNextEntry(new ZipEntry(personFolder));
zipOut.closeEntry();
// 9.2. 在个人文件夹下写几个子文件夹
// 7.2. 在个人文件夹下写几个子文件夹
List<SysDictDataVo> dictDataList = dictTypeService.selectDictDataByType(ConstructionUserConstant.USER_FILE_TYPE);
for (SysDictDataVo dataVo : dictDataList) {
String subFolderPath = personFolder + dataVo.getDictValue() + "_" + dataVo.getDictLabel() + "/";
@ -358,7 +354,7 @@ public class BusConstructionUserFileServiceImpl extends ServiceImpl<BusConstruct
saveOrUpdateList.add(existingFile);
} else {
// 如果不存在且存在文件id则更新
if (StringUtils.isNotBlank(fileId)){
if (StringUtils.isNotBlank(fileId)) {
BusConstructionUserFile newFile = new BusConstructionUserFile();
newFile.setUserId(userId);
newFile.setFileType(fileType);
@ -409,4 +405,44 @@ public class BusConstructionUserFileServiceImpl extends ServiceImpl<BusConstruct
return lqw;
}
/**
* 获取施工人员查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
@Override
public LambdaQueryWrapper<BusConstructionUser> buildTemplateQueryWrapper(ConstructionUserFileTemplateReq req) {
LambdaQueryWrapper<BusConstructionUser> lqw = new LambdaQueryWrapper<>();
if (req == null) {
return lqw;
}
Long projectId = req.getProjectId();
String userName = req.getUserName();
Long contractorId = req.getContractorId();
Long teamId = req.getTeamId();
String typeOfWork = req.getTypeOfWork();
String clock = req.getClock();
List<Long> userIdList = req.getUserIdList();
// 模糊查询
lqw.like(StringUtils.isNotBlank(userName), BusConstructionUser::getUserName, userName);
// 精确查询
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusConstructionUser::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(contractorId), BusConstructionUser::getContractorId, contractorId);
lqw.eq(ObjectUtils.isNotEmpty(teamId), BusConstructionUser::getTeamId, teamId);
lqw.eq(StringUtils.isNotBlank(typeOfWork), BusConstructionUser::getTypeOfWork, typeOfWork);
lqw.eq(StringUtils.isNotBlank(clock), BusConstructionUser::getClock, clock);
if (CollUtil.isNotEmpty(userIdList)) {
lqw.in(BusConstructionUser::getId, userIdList);
}
// 根据项目id获取黑名单施工人员
List<Long> blacklistUserIdList = constructionBlacklistService.lambdaQuery()
.eq(BusConstructionBlacklist::getProjectId, projectId)
.list().stream().map(BusConstructionBlacklist::getUserId).toList();
if (CollUtil.isNotEmpty(blacklistUserIdList)) {
lqw.notIn(BusConstructionUser::getId, blacklistUserIdList);
}
return lqw;
}
}

View File

@ -24,7 +24,7 @@ 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.ConstructionUserAttendanceByDay;
import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceMonthResp;
import org.dromara.project.domain.resp.constructionuser.ConstructionUserAttendanceTotalResp;
import org.dromara.project.domain.vo.BusConstructionUserVo;
@ -32,6 +32,7 @@ import org.dromara.project.domain.vo.BusContractorVo;
import org.dromara.project.domain.vo.BusProjectTeamVo;
import org.dromara.project.mapper.BusConstructionUserMapper;
import org.dromara.project.service.*;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysDictTypeService;
import org.dromara.system.service.ISysOssService;
import org.springframework.beans.BeanUtils;
@ -160,25 +161,36 @@ public class BusConstructionUserServiceImpl extends ServiceImpl<BusConstructionU
Date start = DateUtils.toDate(yearMonth.atDay(1));
Date end = DateUtils.toDate(yearMonth.atEndOfMonth());
// 查询当月考勤记录
Map<Date, List<BusAttendance>> dateListMap = attendanceService.lambdaQuery()
List<BusAttendance> dateList = attendanceService.lambdaQuery()
.eq(BusAttendance::getUserId, id)
.between(BusAttendance::getClockDate, start, end)
.list()
.stream().collect(Collectors.groupingBy(BusAttendance::getClockDate));
.list();
Map<Date, List<BusAttendance>> dateListMap = dateList.stream().collect(Collectors.groupingBy(BusAttendance::getClockDate));
// 获取所有打卡图片id
List<Long> picIds = dateList.stream().map(BusAttendance::getFacePic).filter(Objects::nonNull).map(Long::valueOf).toList();
Map<Long, List<SysOssVo>> ossIdUrlMap = ossService.listByIds(picIds)
.stream().collect(Collectors.groupingBy(SysOssVo::getOssId));
// 遍历每天,计算考勤状态
List<ConstructionUserAttendanceMonthResp> respList = new ArrayList<>();
dateListMap.forEach((date, attendanceList) -> {
ConstructionUserAttendanceMonthResp resp = new ConstructionUserAttendanceMonthResp();
resp.setId(id);
resp.setClockDate(date);
List<AttendanceListByDay> attendanceListByDayList = new ArrayList<>();
// 获取考勤记录
ConstructionUserAttendanceByDay day = ConstructionUserAttendanceByDay.build(attendanceList);
// 填充打卡图片url
if (day != null) {
if (day.getUpClockPicId() != null) {
day.setUpClockPic(ossIdUrlMap.get(day.getUpClockPicId()).get(0).getUrl());
}
if (day.getDownClockPicId() != null) {
day.setDownClockPic(ossIdUrlMap.get(day.getDownClockPicId()).get(0).getUrl());
}
}
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();
@ -197,7 +209,7 @@ public class BusConstructionUserServiceImpl extends ServiceImpl<BusConstructionU
status = ConstructionUserAttendanceStatusEnum.ERROR.getValue();
}
resp.setStatus(status);
resp.setAttendanceList(attendanceListByDayList);
resp.setClockList(day);
respList.add(resp);
});
// 按打卡日期正序排列

View File

@ -0,0 +1,236 @@
package org.dromara.project.service.impl;
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;
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.BusLeave;
import org.dromara.project.domain.BusProjectTeam;
import org.dromara.project.domain.enums.OpinionStatusEnum;
import org.dromara.project.domain.enums.ReviewStatusEnum;
import org.dromara.project.domain.req.leave.LeaveManagerReviewReq;
import org.dromara.project.domain.req.leave.LeaveQueryReq;
import org.dromara.project.domain.vo.BusLeaveVo;
import org.dromara.project.mapper.BusLeaveMapper;
import org.dromara.project.service.IBusLeaveService;
import org.dromara.project.service.IBusProjectTeamService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* 施工人员请假申请Service业务层处理
*
* @author lcj
* @date 2025-04-08
*/
@Service
public class BusLeaveServiceImpl extends ServiceImpl<BusLeaveMapper, BusLeave>
implements IBusLeaveService {
@Resource
private IBusProjectTeamService projectTeamService;
/**
* 查询施工人员请假申请
*
* @param id 主键
* @return 施工人员请假申请
*/
@Override
public BusLeaveVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询施工人员请假申请列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 施工人员请假申请分页列表
*/
@Override
public TableDataInfo<BusLeaveVo> queryPageList(LeaveQueryReq req, PageQuery pageQuery) {
Page<BusLeave> result = this.page(pageQuery.build(), buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的施工人员请假申请列表
*
* @param req 查询条件
* @return 施工人员请假申请列表
*/
@Override
public List<BusLeaveVo> queryList(LeaveQueryReq req) {
LambdaQueryWrapper<BusLeave> lqw = buildQueryWrapper(req);
return baseMapper.selectVoList(lqw);
}
/**
* 管理员审核施工人员请假申请
*
* @param req 管理员审核施工人员请假申请
* @return 是否审核成功
*/
@Override
public Boolean managerReview(LeaveManagerReviewReq req) {
Long id = req.getId();
String managerOpinion = req.getManagerOpinion();
// 判断该请假记录是否存在
BusLeave oldLeave = this.getById(id);
if (oldLeave == null) {
throw new ServiceException("施工人员请假申请不存在", HttpStatus.NOT_FOUND);
}
// 如果已经审核过,则返回
if (!OpinionStatusEnum.UNREAD.getValue().equals(managerOpinion)) {
throw new ServiceException("该请假已审核,请勿重复操作", HttpStatus.BAD_REQUEST);
}
// 判断班组长是否审核通过
String gangerOpinion = oldLeave.getGangerOpinion();
if (!OpinionStatusEnum.PASS.getValue().equals(gangerOpinion)) {
throw new ServiceException("请等待班组长审核通过后再进行操作", HttpStatus.BAD_REQUEST);
}
// todo 判断当前用户是否为项目管理员
// 填充默认值,更新数据
BusLeave leave = new BusLeave();
leave.setId(id);
leave.setManagerOpinion(managerOpinion);
leave.setManagerExplain(req.getManagerExplain());
leave.setManagerTime(new Date());
leave.setRemark(req.getRemark());
boolean result = this.updateById(leave);
if (!result) {
throw new ServiceException("更新管理员审核操作失败", HttpStatus.ERROR);
}
return true;
}
/**
* 校验并批量删除施工人员请假申请信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 获取施工人员请假申请视图对象
*
* @param leave 施工人员请假申请对象
* @return 施工人员请假申请视图对象
*/
@Override
public BusLeaveVo getVo(BusLeave leave) {
// 对象转封装类
BusLeaveVo leaveVo = new BusLeaveVo();
if (leave == null) {
return leaveVo;
}
BeanUtils.copyProperties(leave, leaveVo);
// 获取班组信息
Long teamId = leave.getTeamId();
if (teamId != null) {
BusProjectTeam team = projectTeamService.lambdaQuery()
.eq(BusProjectTeam::getId, teamId).select(BusProjectTeam::getTeamName).one();
leaveVo.setTeamName(team.getTeamName());
}
// 添加审核状态
String status = ReviewStatusEnum.getEnumByOpinionStatus(leave.getGangerOpinion(), leave.getManagerOpinion());
leaveVo.setStatus(status);
return leaveVo;
}
/**
* 获取施工人员请假申请查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
@Override
public LambdaQueryWrapper<BusLeave> buildQueryWrapper(LeaveQueryReq req) {
LambdaQueryWrapper<BusLeave> lqw = new LambdaQueryWrapper<>();
if (req == null) {
return lqw;
}
Long id = req.getId();
Long userId = req.getUserId();
String userName = req.getUserName();
String leaveType = req.getLeaveType();
Long gangerId = req.getGangerId();
String gangerName = req.getGangerName();
String gangerOpinion = req.getGangerOpinion();
String managerOpinion = req.getManagerOpinion();
Long projectId = req.getProjectId();
Long teamId = req.getTeamId();
// 模糊查询
lqw.like(StringUtils.isNotBlank(userName), BusLeave::getUserName, userName);
lqw.like(StringUtils.isNotBlank(gangerName), BusLeave::getGangerName, gangerName);
// 精确查询
lqw.eq(ObjectUtils.isNotEmpty(id), BusLeave::getId, id);
lqw.eq(ObjectUtils.isNotEmpty(userId), BusLeave::getUserId, userId);
lqw.eq(ObjectUtils.isNotEmpty(gangerId), BusLeave::getGangerId, gangerId);
lqw.eq(StringUtils.isNotBlank(gangerOpinion), BusLeave::getGangerOpinion, gangerOpinion);
lqw.eq(StringUtils.isNotBlank(managerOpinion), BusLeave::getManagerOpinion, managerOpinion);
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusLeave::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(teamId), BusLeave::getTeamId, teamId);
lqw.eq(StringUtils.isNotBlank(leaveType), BusLeave::getLeaveType, leaveType);
return lqw;
}
/**
* 获取施工人员请假申请分页对象视图
*
* @param leavePage 施工人员请假申请分页对象
* @return 施工人员请假申请分页对象视图
*/
@Override
public Page<BusLeaveVo> getVoPage(Page<BusLeave> leavePage) {
List<BusLeave> leaveList = leavePage.getRecords();
Page<BusLeaveVo> leaveVoPage = new Page<>(
leavePage.getCurrent(),
leavePage.getSize(),
leavePage.getTotal());
if (CollUtil.isEmpty(leaveList)) {
return leaveVoPage;
}
// 关联查询班组信息
Set<Long> teamIdSet = leaveList.stream().map(BusLeave::getTeamId)
.collect(Collectors.toSet());
Map<Long, List<BusProjectTeam>> teamIdTeamMap = projectTeamService.listByIds(teamIdSet).stream()
.collect(Collectors.groupingBy(BusProjectTeam::getId));
List<BusLeaveVo> leaveVoList = leaveList.stream().map(leave -> {
BusLeaveVo leaveVo = new BusLeaveVo();
BeanUtils.copyProperties(leave, leaveVo);
// 关联班组信息
Long teamId = leave.getTeamId();
String teamName = null;
if (teamIdTeamMap.containsKey(teamId)) {
teamName = projectTeamService.getVo(teamIdTeamMap.get(teamId).get(0)).getTeamName();
}
leaveVo.setTeamName(teamName);
// 添加审核状态
String status = ReviewStatusEnum.getEnumByOpinionStatus(leave.getGangerOpinion(), leave.getManagerOpinion());
leaveVo.setStatus(status);
return leaveVo;
}).toList();
leaveVoPage.setRecords(leaveVoList);
return leaveVoPage;
}
}

View File

@ -0,0 +1,278 @@
package org.dromara.project.service.impl;
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.DateUtils;
import org.dromara.common.core.utils.ObjectUtils;
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.BusProject;
import org.dromara.project.domain.BusProjectTeam;
import org.dromara.project.domain.BusReissueCard;
import org.dromara.project.domain.enums.ConstructionUserAttendanceClockStatusEnum;
import org.dromara.project.domain.enums.ConstructionUserAttendanceCommuterEnum;
import org.dromara.project.domain.enums.OpinionStatusEnum;
import org.dromara.project.domain.enums.ReviewStatusEnum;
import org.dromara.project.domain.req.reissuecard.ReissueCardManagerReviewReq;
import org.dromara.project.domain.req.reissuecard.ReissueCardQueryReq;
import org.dromara.project.domain.vo.BusReissueCardVo;
import org.dromara.project.mapper.BusReissueCardMapper;
import org.dromara.project.service.IBusAttendanceService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusProjectTeamService;
import org.dromara.project.service.IBusReissueCardService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* 施工人员补卡申请Service业务层处理
*
* @author lcj
* @date 2025-04-08
*/
@Service
public class BusReissueCardServiceImpl extends ServiceImpl<BusReissueCardMapper, BusReissueCard>
implements IBusReissueCardService {
@Resource
private IBusProjectService projectService;
@Resource
private IBusProjectTeamService projectTeamService;
@Resource
private IBusAttendanceService attendanceService;
/**
* 查询施工人员补卡申请
*
* @param id 主键
* @return 施工人员补卡申请
*/
@Override
public BusReissueCardVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询施工人员补卡申请列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 施工人员补卡申请分页列表
*/
@Override
public TableDataInfo<BusReissueCardVo> queryPageList(ReissueCardQueryReq req, PageQuery pageQuery) {
Page<BusReissueCard> result = this.page(pageQuery.build(), buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的施工人员补卡申请列表
*
* @param req 查询条件
* @return 施工人员补卡申请列表
*/
@Override
public List<BusReissueCardVo> queryList(ReissueCardQueryReq req) {
LambdaQueryWrapper<BusReissueCard> lqw = buildQueryWrapper(req);
return baseMapper.selectVoList(lqw);
}
/**
* 管理员审核施工人员补卡申请
*
* @param req 管理员审核施工人员补卡申请
* @return 是否审核成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean managerReview(ReissueCardManagerReviewReq req) {
Long id = req.getId();
String managerOpinion = req.getManagerOpinion();
// 判断该补卡记录是否存在
BusReissueCard oldReissueCard = this.getById(id);
if (oldReissueCard == null) {
throw new ServiceException("施工人员补卡申请不存在", HttpStatus.NOT_FOUND);
}
// 如果已经审核过,则返回
if (!OpinionStatusEnum.UNREAD.getValue().equals(managerOpinion)) {
throw new ServiceException("该请假已审核,请勿重复操作", HttpStatus.BAD_REQUEST);
}
// 判断班组长是否审核通过
String gangerOpinion = oldReissueCard.getGangerOpinion();
if (!OpinionStatusEnum.PASS.getValue().equals(gangerOpinion)) {
throw new ServiceException("请等待班组长审核通过后再进行操作", HttpStatus.BAD_REQUEST);
}
// todo 判断当前用户是否为项目管理员
// 填充默认值,更新数据
BusReissueCard reissueCard = new BusReissueCard();
reissueCard.setId(id);
reissueCard.setManagerOpinion(managerOpinion);
reissueCard.setManagerExplain(req.getManagerExplain());
reissueCard.setManagerTime(new Date());
reissueCard.setRemark(req.getRemark());
boolean result = this.updateById(reissueCard);
if (!result) {
throw new ServiceException("更新管理员审核操作失败", HttpStatus.ERROR);
}
// 更新考勤表记录
BusAttendance oldAttendance = attendanceService.getById(oldReissueCard.getAttendanceId());
if (oldAttendance == null) {
throw new ServiceException("考勤记录不存在", HttpStatus.NOT_FOUND);
}
BusAttendance attendance = new BusAttendance();
BusProject project = projectService.getById(oldReissueCard.getProjectId());
// 根据补卡类型更新考勤时间
String[] clockTime = project.getPunchRange().split(",");
String reissueCardType = oldReissueCard.getReissueCardType();
if (ConstructionUserAttendanceCommuterEnum.CLOCKIN.getValue().equals(reissueCardType)) {
// 拼接时间,获取项目的上班打卡时间
Date date = DateUtils.combineDateAndTime(oldAttendance.getClockDate(), clockTime[0] + ":00");
attendance.setClockTime(date);
} else if (ConstructionUserAttendanceCommuterEnum.CLOCKOUT.getValue().equals(reissueCardType)) {
// 拼接时间,获取项目的下班打卡时间
Date date = DateUtils.combineDateAndTime(oldAttendance.getClockDate(), clockTime[1] + ":00");
attendance.setClockTime(date);
}
attendance.setId(oldReissueCard.getAttendanceId());
attendance.setClockStatus(ConstructionUserAttendanceClockStatusEnum.REISSUE.getValue());
boolean updateAttendance = attendanceService.updateById(attendance);
if (!updateAttendance) {
throw new ServiceException("更新考勤记录失败", HttpStatus.ERROR);
}
return true;
}
/**
* 校验并批量删除施工人员补卡申请信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 获取施工人员补卡申请视图对象
*
* @param reissueCard 施工人员补卡申请对象
* @return 施工人员补卡申请视图对象
*/
@Override
public BusReissueCardVo getVo(BusReissueCard reissueCard) {
// 对象转封装类
BusReissueCardVo reissueCardVo = new BusReissueCardVo();
if (reissueCard == null) {
return reissueCardVo;
}
BeanUtils.copyProperties(reissueCard, reissueCardVo);
// 获取班组信息
Long teamId = reissueCard.getTeamId();
if (teamId != null) {
BusProjectTeam team = projectTeamService.lambdaQuery()
.eq(BusProjectTeam::getId, teamId).select(BusProjectTeam::getTeamName).one();
reissueCardVo.setTeamName(team.getTeamName());
}
// 添加审核状态
String status = ReviewStatusEnum.getEnumByOpinionStatus(reissueCard.getGangerOpinion(), reissueCard.getManagerOpinion());
reissueCardVo.setStatus(status);
return reissueCardVo;
}
/**
* 获取施工人员补卡申请查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
@Override
public LambdaQueryWrapper<BusReissueCard> buildQueryWrapper(ReissueCardQueryReq req) {
LambdaQueryWrapper<BusReissueCard> lqw = new LambdaQueryWrapper<>();
if (req == null) {
return lqw;
}
Long id = req.getId();
Long userId = req.getUserId();
String userName = req.getUserName();
Long gangerId = req.getGangerId();
String gangerName = req.getGangerName();
String gangerOpinion = req.getGangerOpinion();
String managerOpinion = req.getManagerOpinion();
Long projectId = req.getProjectId();
Long teamId = req.getTeamId();
String reissueCardType = req.getReissueCardType();
Long attendanceId = req.getAttendanceId();
// 模糊查询
lqw.like(StringUtils.isNotBlank(userName), BusReissueCard::getUserName, userName);
lqw.like(StringUtils.isNotBlank(gangerName), BusReissueCard::getGangerName, gangerName);
// 精确查询
lqw.eq(ObjectUtils.isNotEmpty(id), BusReissueCard::getId, id);
lqw.eq(ObjectUtils.isNotEmpty(userId), BusReissueCard::getUserId, userId);
lqw.eq(ObjectUtils.isNotEmpty(gangerId), BusReissueCard::getGangerId, gangerId);
lqw.eq(StringUtils.isNotBlank(gangerOpinion), BusReissueCard::getGangerOpinion, gangerOpinion);
lqw.eq(StringUtils.isNotBlank(managerOpinion), BusReissueCard::getManagerOpinion, managerOpinion);
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusReissueCard::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(teamId), BusReissueCard::getTeamId, teamId);
lqw.eq(StringUtils.isNotBlank(reissueCardType), BusReissueCard::getReissueCardType, reissueCardType);
lqw.eq(ObjectUtils.isNotEmpty(attendanceId), BusReissueCard::getAttendanceId, attendanceId);
return lqw;
}
/**
* 获取施工人员补卡申请分页对象视图
*
* @param reissueCardPage 施工人员补卡申请分页对象
* @return 施工人员补卡申请分页对象视图
*/
@Override
public Page<BusReissueCardVo> getVoPage(Page<BusReissueCard> reissueCardPage) {
List<BusReissueCard> reissueCardList = reissueCardPage.getRecords();
Page<BusReissueCardVo> reissueCardVoPage = new Page<>(
reissueCardPage.getCurrent(),
reissueCardPage.getSize(),
reissueCardPage.getTotal());
if (CollUtil.isEmpty(reissueCardList)) {
return reissueCardVoPage;
}
// 关联查询班组信息
Set<Long> teamIdSet = reissueCardList.stream().map(BusReissueCard::getTeamId)
.collect(Collectors.toSet());
Map<Long, List<BusProjectTeam>> teamIdTeamMap = projectTeamService.listByIds(teamIdSet).stream()
.collect(Collectors.groupingBy(BusProjectTeam::getId));
List<BusReissueCardVo> reissueCardVoList = reissueCardList.stream().map(reissueCard -> {
BusReissueCardVo reissueCardVo = new BusReissueCardVo();
BeanUtils.copyProperties(reissueCard, reissueCardVo);
// 关联班组信息
Long teamId = reissueCard.getTeamId();
String teamName = null;
if (teamIdTeamMap.containsKey(teamId)) {
teamName = projectTeamService.getVo(teamIdTeamMap.get(teamId).get(0)).getTeamName();
}
reissueCardVo.setTeamName(teamName);
// 添加审核状态
String status = ReviewStatusEnum.getEnumByOpinionStatus(reissueCard.getGangerOpinion(), reissueCard.getManagerOpinion());
reissueCardVo.setStatus(status);
return reissueCardVo;
}).toList();
reissueCardVoPage.setRecords(reissueCardVoList);
return reissueCardVoPage;
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.project.mapper.BusReissueCardMapper">
</mapper>

View File

@ -541,3 +541,70 @@ CREATE TABLE `bus_construction_user_exit`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id'
) comment = '施工人员入场退场记录信息' COLLATE = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_reissue_card`;
CREATE TABLE `bus_reissue_card`
(
`id` bigint not null auto_increment comment '主键id',
`user_id` bigint not null comment '申请人id',
`user_name` varchar(50) not null comment '申请人名字',
`user_explain` varchar(512) null comment '申请补卡说明',
`user_time` datetime default CURRENT_TIMESTAMP null comment '补卡申请时间',
`ganger_id` bigint null comment '班组长',
`ganger_name` varchar(50) null comment '班组长名字',
`ganger_opinion` char(1) default '1' not null comment '班组长意见1未读 2同意 3拒绝',
`ganger_explain` varchar(512) null comment '班组长说明',
`ganger_time` datetime null comment '班组长操作时间',
`manager_opinion` char(1) default '1' not null comment '管理员意见1未读 2同意 3拒绝',
`manager_explain` varchar(512) null comment '管理员说明',
`manager_time` datetime null comment '管理员操作时间',
`project_id` bigint not null comment '项目id',
`team_id` bigint null comment '班组id',
`reissue_card_type` char(1) not null comment '补卡类型1上班 2下班',
`attendance_id` bigint not null comment '考勤表主键id',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id',
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id'
) comment = '施工人员补卡申请' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_leave`;
CREATE TABLE `bus_leave`
(
`id` bigint not null auto_increment comment '主键id',
`user_id` bigint not null comment '申请人id',
`user_name` varchar(50) not null comment '申请人名字',
`user_explain` varchar(512) null comment '申请请假说明',
`user_time` datetime default CURRENT_TIMESTAMP null comment '请假申请时间',
`leave_type` char(1) not null comment '请假类型1事假 2病假',
`start_time` datetime not null comment '请假开始时间',
`end_time` datetime not null comment '请假结束时间',
`ganger_id` bigint null comment '班组长',
`ganger_name` varchar(50) null comment '班组长名字',
`ganger_opinion` char(1) default '1' not null comment '班组长意见1未读 2同意 3拒绝',
`ganger_explain` varchar(512) null comment '班组长说明',
`ganger_time` datetime null comment '班组长操作时间',
`manager_opinion` char(1) default '1' not null comment '管理员意见1未读 2同意 3拒绝',
`manager_explain` varchar(512) null comment '管理员说明',
`manager_time` datetime null comment '管理员操作时间',
`project_id` bigint not null comment '项目id',
`team_id` bigint null comment '班组id',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id',
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id'
) comment = '施工人员请假申请' collate = utf8mb4_unicode_ci;