分包考勤

This commit is contained in:
zt
2025-11-12 09:56:39 +08:00
parent 0941197ca9
commit 5da05dcf24
11 changed files with 716 additions and 51 deletions

View File

@ -1617,7 +1617,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
List<BusProjectTeam> busProjectTeams = projectTeamService.listByIds(list1); List<BusProjectTeam> busProjectTeams = projectTeamService.listByIds(list1);
Map<Long, String> teamMap = busProjectTeams.stream().collect(Collectors.toMap(BusProjectTeam::getId, BusProjectTeam::getTeamName)); Map<Long, String> teamMap = busProjectTeams.stream().collect(Collectors.toMap(BusProjectTeam::getId, BusProjectTeam::getTeamName));
ArrayList<AttendanceTodayUserVo> attendanceTodayUserVos = new ArrayList<>(); List<AttendanceTodayUserVo> attendanceTodayUserVos = new ArrayList<>();
for (SubConstructionUser constructionUser : records) { for (SubConstructionUser constructionUser : records) {
AttendanceTodayUserVo attendanceTodayUserVo = new AttendanceTodayUserVo(); AttendanceTodayUserVo attendanceTodayUserVo = new AttendanceTodayUserVo();
attendanceTodayUserVo.setUserId(constructionUser.getSysUserId()); attendanceTodayUserVo.setUserId(constructionUser.getSysUserId());
@ -1627,6 +1627,6 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
attendanceTodayUserVos.add(attendanceTodayUserVo); attendanceTodayUserVos.add(attendanceTodayUserVo);
} }
return new TableDataInfo<AttendanceTodayUserVo>(attendanceTodayUserVos, result.getTotal()); return new TableDataInfo<>(attendanceTodayUserVos, result.getTotal());
} }
} }

View File

@ -6,11 +6,16 @@ import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.contractor.domain.dto.contractor.SubContractorQueryReq;
import org.dromara.contractor.domain.vo.contractor.SubContractorVo;
import org.dromara.contractor.service.ISubContractorService;
import org.dromara.project.domain.dto.attendance.*; import org.dromara.project.domain.dto.attendance.*;
import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq; import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq;
import org.dromara.project.domain.vo.attendance.*; import org.dromara.project.domain.vo.attendance.*;
import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo; import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo;
import org.dromara.project.service.IBusProjectTeamService; import org.dromara.project.service.IBusProjectTeamService;
import org.dromara.system.domain.dto.FbUserListDto;
import org.dromara.system.domain.vo.SysUserVo;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.idempotent.annotation.RepeatSubmit;
@ -43,6 +48,8 @@ public class BusAttendanceController extends BaseController {
private final IBusProjectTeamService projectTeamService; private final IBusProjectTeamService projectTeamService;
private final ISubContractorService contractorService;
/** /**
* 查询考勤列表 * 查询考勤列表
*/ */
@ -156,4 +163,47 @@ public class BusAttendanceController extends BaseController {
return R.ok(projectTeamService.queryList(busProjectTeamQueryReq)); return R.ok(projectTeamService.queryList(busProjectTeamQueryReq));
} }
/**
* 查询项目分包人员当天考勤状况
*/
@GetMapping("/sub/list/clockDate/today")
public R<BusAttendanceClockDateForTwoWeekVo> getSubTodayAttendanceData(SubTwoWeekDto dto) {
return R.ok(busAttendanceService.getSubTodayAttendanceData(dto));
}
/**
* 查询项目分包人员前14天考勤状况
*/
@GetMapping("/sub/list/clockDate/twoWeek")
public R<List<BusAttendanceClockDateForTwoWeekVo>> getSubClockDateForTwoWeekList(SubTwoWeekDto dto) {
return R.ok(busAttendanceService.getSubClockDateForTwoWeekList(dto));
}
/**
* 查询项目分包人员当月考勤状况
*/
@GetMapping("/sub/countList")
public TableDataInfo<SubUserAttendanceTotalVo> subCountList(SubUserAttendanceQueryReq dto, PageQuery pageQuery) {
return busAttendanceService.subCountList(dto, pageQuery);
}
/**
* 查询分包当天出勤人员
*/
@GetMapping("/sub/list/attendanceUser")
public TableDataInfo<SubAttendanceTodayUserVo> getSubTodayAttendanceUser(SubTodayUserDto dto, PageQuery pageQuery) {
return busAttendanceService.getSubTodayAttendanceUser(dto,pageQuery);
}
/**
* 查询分包公司
*/
@GetMapping("/subContractorList")
public TableDataInfo<SubContractorVo> list(SubContractorQueryReq req, PageQuery pageQuery) {
return contractorService.queryPageList(req, pageQuery);
}
} }

View File

@ -0,0 +1,38 @@
package org.dromara.project.domain.dto.attendance;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
@Data
public class SubTodayUserDto {
/**
* 人员姓名
*/
private String userName;
/**
* 分包公司Id
*/
private Long contractorId;
/**
* 项目id
*/
private Long projectId;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate date;
private List<Long> userIds;
/**
* 出勤状态 1-全勤 2-缺勤 3-请假
*/
private String type;
private Boolean isToday;
}

View File

@ -0,0 +1,22 @@
package org.dromara.project.domain.dto.attendance;
import lombok.Data;
@Data
public class SubTwoWeekDto {
/**
* 人员姓名
*/
private String userName;
/**
* 分包公司Id
*/
private Long contractorId;
/**
* 项目id
*/
private Long projectId;
}

View File

@ -0,0 +1,40 @@
package org.dromara.project.domain.dto.attendance;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025/4/7 10:52
*/
@Data
public class SubUserAttendanceQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -6634291825924626633L;
/**
* 人员姓名
*/
private String userName;
/**
* 项目id
*/
@NotNull(message = "项目id不能为空")
private Long projectId;
/**
* 分包id
*/
private Long contractorId;
/**
* 打卡月份
*/
private String clockDate;
}

View File

@ -0,0 +1,24 @@
package org.dromara.project.domain.vo.attendance;
import lombok.Data;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
@Data
public class SubAttendanceTodayUserVo {
private Long userId;
private String userName;
/**
* 分包
*/
private Long contractorId;
/**
* 分包单位名称
*/
private String contractorName;
}

View File

@ -0,0 +1,64 @@
package org.dromara.project.domain.vo.attendance;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025/4/7 10:16
*/
@Data
public class SubUserAttendanceTotalVo implements Serializable {
@Serial
private static final long serialVersionUID = 1335094839733429171L;
/**
* 主键id
*/
private Long id;
/**
* 人员姓名
*/
private String userName;
/**
* 分包
*/
private Long contractorId;
/**
* 分包单位名称
*/
private String contractorName;
/**
* 出勤天数
*/
private Integer attendanceDays;
/**
* 迟到天数
*/
private Integer lateDays;
/**
* 早退天数
*/
private Integer leaveEarlyDays;
/**
* 缺卡天数
*/
private Integer unClockDays;
/**
* 请假天数
*/
private Integer leaveDays;
}

View File

@ -196,5 +196,23 @@ public interface IBusAttendanceService extends IService<BusAttendance>{
*/ */
void getExportList(AttendanceExportDto dto,HttpServletResponse response); void getExportList(AttendanceExportDto dto,HttpServletResponse response);
/**
* 获取分包当天的考勤数据
*/
BusAttendanceClockDateForTwoWeekVo getSubTodayAttendanceData(SubTwoWeekDto dto);
/**
* 分包近两周打卡统计
*/
List<BusAttendanceClockDateForTwoWeekVo> getSubClockDateForTwoWeekList(SubTwoWeekDto dto);
/**
* 获取分包打卡统计
*/
TableDataInfo<SubUserAttendanceTotalVo> subCountList(SubUserAttendanceQueryReq dto, PageQuery pageQuery);
/**
* 查询分包当天出勤人员
*/
TableDataInfo<SubAttendanceTodayUserVo> getSubTodayAttendanceUser(SubTodayUserDto dto, PageQuery pageQuery);
} }

View File

@ -47,6 +47,7 @@ import org.dromara.project.domain.vo.attendance.*;
import org.dromara.project.domain.vo.projectteam.BusProjectTeamAppVo; import org.dromara.project.domain.vo.projectteam.BusProjectTeamAppVo;
import org.dromara.project.mapper.BusAttendanceMapper; import org.dromara.project.mapper.BusAttendanceMapper;
import org.dromara.project.service.*; import org.dromara.project.service.*;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysOssService; import org.dromara.system.service.ISysOssService;
@ -60,11 +61,12 @@ import java.io.OutputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.*; import java.time.*;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.dromara.project.domain.enums.BusAttendanceClockStatusEnum.ATTENDANCE_LIST; import static org.dromara.project.domain.enums.BusAttendanceClockStatusEnum.*;
/** /**
* 考勤Service业务层处理 * 考勤Service业务层处理
@ -118,7 +120,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
// 出勤状态(正常、迟到、早退) // 出勤状态(正常、迟到、早退)
private static final Set<String> ATTENDANCE_STATUS = new HashSet<>(Arrays.asList(BusAttendanceClockStatusEnum.NORMAL.getValue(), private static final Set<String> ATTENDANCE_STATUS = new HashSet<>(Arrays.asList(BusAttendanceClockStatusEnum.NORMAL.getValue(),
BusAttendanceClockStatusEnum.LATE.getValue(), BusAttendanceClockStatusEnum.LEAVEEARLY.getValue() LATE.getValue(), LEAVEEARLY.getValue()
, BusAttendanceClockStatusEnum.REISSUE.getValue())); , BusAttendanceClockStatusEnum.REISSUE.getValue()));
@ -159,14 +161,14 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
String clockMonth = req.getClockMonth(); String clockMonth = req.getClockMonth();
SubConstructionUser constructionUser = constructionUserService.getById(userId); SubConstructionUser constructionUser = constructionUserService.getById(userId);
if (constructionUser == null) { if (constructionUser == null) {
throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND); throw new ServiceException("实名认证信息不存在", HttpStatus.ERROR);
} }
// 解析月份 // 解析月份
YearMonth yearMonth; YearMonth yearMonth;
if (StringUtils.isNotBlank(clockMonth)) { if (StringUtils.isNotBlank(clockMonth)) {
// 校验月份格式 // 校验月份格式
if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) { if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) {
throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST); throw new ServiceException("月份格式不正确", HttpStatus.ERROR);
} }
yearMonth = YearMonth.parse(clockMonth); yearMonth = YearMonth.parse(clockMonth);
} else { } else {
@ -328,12 +330,12 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
// 记录当前打卡时间 // 记录当前打卡时间
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
if(req.getPunchTime() != null){ if (req.getPunchTime() != null) {
now = req.getPunchTime(); now = req.getPunchTime();
} }
//打卡范围 //打卡范围
if (!"1".equals(req.getSource())){ if (!"1".equals(req.getSource())) {
if (!checkInRange(req)) { if (!checkInRange(req)) {
throw new ServiceException("打卡位置不在范围内", HttpStatus.ERROR); throw new ServiceException("打卡位置不在范围内", HttpStatus.ERROR);
} }
@ -392,7 +394,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getClockType())).toList(); BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getClockType())).toList();
if (clockTypeByTime == 1) { if (clockTypeByTime == 1) {
if(CollectionUtils.isEmpty(inAttendances)){ if (CollectionUtils.isEmpty(inAttendances)) {
BusAttendance attendance = new BusAttendance(); BusAttendance attendance = new BusAttendance();
// 上班打卡 // 上班打卡
attendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue()); attendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue());
@ -400,7 +402,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setRuleTime(busAttendanceRuleVo.getClockInTime()); attendance.setRuleTime(busAttendanceRuleVo.getClockInTime());
// 判断是否为迟到 // 判断是否为迟到
if (isLate(now, busAttendanceRuleVo)) { if (isLate(now, busAttendanceRuleVo)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue()); attendance.setClockStatus(LATE.getValue());
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime())); attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
} else { } else {
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -418,7 +420,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setClockTime(now); attendance.setClockTime(now);
attendance.setUserName(constructionUser.getUserName()); attendance.setUserName(constructionUser.getUserName());
attendance.setReplaceId(replaceId); attendance.setReplaceId(replaceId);
if(req.getSource() != null){ if (req.getSource() != null) {
attendance.setSource(req.getSource()); attendance.setSource(req.getSource());
attendance.setSn(req.getSn()); attendance.setSn(req.getSn());
} }
@ -447,14 +449,14 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
return this.save(attendance); return this.save(attendance);
} }
//考勤机打卡会有历史记录,需要更新状态 //考勤机打卡会有历史记录,需要更新状态
if(CollectionUtil.isNotEmpty(outAttendances) && "1".equals(req.getSource())){ if (CollectionUtil.isNotEmpty(outAttendances) && "1".equals(req.getSource())) {
BusAttendance busAttendance = outAttendances.getFirst(); BusAttendance busAttendance = outAttendances.getFirst();
String oldStatus = busAttendance.getClockStatus(); String oldStatus = busAttendance.getClockStatus();
//更新打卡时间 //更新打卡时间
busAttendance.setClockTime(now); busAttendance.setClockTime(now);
// 判断是否为迟到 // 判断是否为迟到
if (isLate(now, busAttendanceRuleVo)) { if (isLate(now, busAttendanceRuleVo)) {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue()); busAttendance.setClockStatus(LATE.getValue());
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime())); busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
} else { } else {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -468,7 +470,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
busAttendance.setSource(req.getSource()); busAttendance.setSource(req.getSource());
busAttendance.setSn(req.getSn()); busAttendance.setSn(req.getSn());
//如果是缺卡需要上传人脸 //如果是缺卡需要上传人脸
if(oldStatus.equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())){ if (oldStatus.equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
SysOssVo upload = ossService.upload(file); SysOssVo upload = ossService.upload(file);
busAttendance.setFacePic(upload.getOssId().toString()); busAttendance.setFacePic(upload.getOssId().toString());
} }
@ -480,14 +482,14 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
if (CollectionUtil.isNotEmpty(outAttendances)) { if (CollectionUtil.isNotEmpty(outAttendances)) {
BusAttendance busAttendance = outAttendances.getFirst(); BusAttendance busAttendance = outAttendances.getFirst();
if("1".equals(req.getSource())){ if ("1".equals(req.getSource())) {
busAttendance.setSource(req.getSource()); busAttendance.setSource(req.getSource());
busAttendance.setSn(req.getSn()); busAttendance.setSn(req.getSn());
if(busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())){ if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
SysOssVo upload = ossService.upload(file); SysOssVo upload = ossService.upload(file);
busAttendance.setFacePic(upload.getOssId().toString()); busAttendance.setFacePic(upload.getOssId().toString());
} }
}else { } else {
if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) { if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
throw new ServiceException("下班缺卡记录已生成,不能更新"); throw new ServiceException("下班缺卡记录已生成,不能更新");
} }
@ -497,7 +499,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
busAttendance.setClockTime(now); busAttendance.setClockTime(now);
// 判断是否为早退 // 判断是否为早退
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) { if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue()); busAttendance.setClockStatus(LEAVEEARLY.getValue());
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime())); busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
} else { } else {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -516,7 +518,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setRuleTime(busAttendanceRuleVo.getClockOutTime()); attendance.setRuleTime(busAttendanceRuleVo.getClockOutTime());
// 判断是否为早退 // 判断是否为早退
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) { if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue()); attendance.setClockStatus(LEAVEEARLY.getValue());
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime())); attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
} else { } else {
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -533,7 +535,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setClockTime(now); attendance.setClockTime(now);
attendance.setUserName(constructionUser.getUserName()); attendance.setUserName(constructionUser.getUserName());
attendance.setReplaceId(replaceId); attendance.setReplaceId(replaceId);
if(req.getSource() != null){ if (req.getSource() != null) {
attendance.setSource(req.getSource()); attendance.setSource(req.getSource());
attendance.setSn(req.getSn()); attendance.setSn(req.getSn());
} }
@ -579,12 +581,12 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
// 记录当前打卡时间 // 记录当前打卡时间
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
if(req.getPunchTime() != null){ if (req.getPunchTime() != null) {
now = req.getPunchTime(); now = req.getPunchTime();
} }
//打卡范围 //打卡范围
if (!"1".equals(req.getSource())){ if (!"1".equals(req.getSource())) {
if (!checkInRangeV1(req)) { if (!checkInRangeV1(req)) {
throw new ServiceException("打卡位置不在范围内", HttpStatus.ERROR); throw new ServiceException("打卡位置不在范围内", HttpStatus.ERROR);
} }
@ -620,7 +622,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
} }
//打卡规则 //打卡规则
BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectIdAndType(req.getProjectId(),constructionUser.getUserRole()); BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectIdAndType(req.getProjectId(), constructionUser.getUserRole());
if (busAttendanceRuleVo == null) { if (busAttendanceRuleVo == null) {
throw new ServiceException("未设置打卡规则", HttpStatus.ERROR); throw new ServiceException("未设置打卡规则", HttpStatus.ERROR);
@ -643,7 +645,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getClockType())).toList(); BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getClockType())).toList();
if (clockTypeByTime == 1) { if (clockTypeByTime == 1) {
if(CollectionUtils.isEmpty(inAttendances)){ if (CollectionUtils.isEmpty(inAttendances)) {
BusAttendance attendance = new BusAttendance(); BusAttendance attendance = new BusAttendance();
// 上班打卡 // 上班打卡
attendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue()); attendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue());
@ -651,7 +653,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setRuleTime(busAttendanceRuleVo.getClockInTime()); attendance.setRuleTime(busAttendanceRuleVo.getClockInTime());
// 判断是否为迟到 // 判断是否为迟到
if (isLate(now, busAttendanceRuleVo)) { if (isLate(now, busAttendanceRuleVo)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue()); attendance.setClockStatus(LATE.getValue());
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime())); attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
} else { } else {
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -669,7 +671,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setClockTime(now); attendance.setClockTime(now);
attendance.setUserName(constructionUser.getUserName()); attendance.setUserName(constructionUser.getUserName());
attendance.setReplaceId(replaceId); attendance.setReplaceId(replaceId);
if(req.getSource() != null){ if (req.getSource() != null) {
attendance.setSource(req.getSource()); attendance.setSource(req.getSource());
attendance.setSn(req.getSn()); attendance.setSn(req.getSn());
} }
@ -698,14 +700,14 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
return this.save(attendance); return this.save(attendance);
} }
//考勤机打卡会有历史记录,需要更新状态 //考勤机打卡会有历史记录,需要更新状态
if(CollectionUtil.isNotEmpty(outAttendances) && "1".equals(req.getSource())){ if (CollectionUtil.isNotEmpty(outAttendances) && "1".equals(req.getSource())) {
BusAttendance busAttendance = outAttendances.getFirst(); BusAttendance busAttendance = outAttendances.getFirst();
String oldStatus = busAttendance.getClockStatus(); String oldStatus = busAttendance.getClockStatus();
//更新打卡时间 //更新打卡时间
busAttendance.setClockTime(now); busAttendance.setClockTime(now);
// 判断是否为迟到 // 判断是否为迟到
if (isLate(now, busAttendanceRuleVo)) { if (isLate(now, busAttendanceRuleVo)) {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue()); busAttendance.setClockStatus(LATE.getValue());
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime())); busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
} else { } else {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -719,7 +721,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
busAttendance.setSource(req.getSource()); busAttendance.setSource(req.getSource());
busAttendance.setSn(req.getSn()); busAttendance.setSn(req.getSn());
//如果是缺卡需要上传人脸 //如果是缺卡需要上传人脸
if(oldStatus.equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())){ if (oldStatus.equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
SysOssVo upload = ossService.upload(file); SysOssVo upload = ossService.upload(file);
busAttendance.setFacePic(upload.getOssId().toString()); busAttendance.setFacePic(upload.getOssId().toString());
} }
@ -731,14 +733,14 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
if (CollectionUtil.isNotEmpty(outAttendances)) { if (CollectionUtil.isNotEmpty(outAttendances)) {
BusAttendance busAttendance = outAttendances.getFirst(); BusAttendance busAttendance = outAttendances.getFirst();
if("1".equals(req.getSource())){ if ("1".equals(req.getSource())) {
busAttendance.setSource(req.getSource()); busAttendance.setSource(req.getSource());
busAttendance.setSn(req.getSn()); busAttendance.setSn(req.getSn());
if(busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())){ if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
SysOssVo upload = ossService.upload(file); SysOssVo upload = ossService.upload(file);
busAttendance.setFacePic(upload.getOssId().toString()); busAttendance.setFacePic(upload.getOssId().toString());
} }
}else { } else {
if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) { if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
throw new ServiceException("下班缺卡记录已生成,不能更新"); throw new ServiceException("下班缺卡记录已生成,不能更新");
} }
@ -748,7 +750,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
busAttendance.setClockTime(now); busAttendance.setClockTime(now);
// 判断是否为早退 // 判断是否为早退
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) { if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue()); busAttendance.setClockStatus(LEAVEEARLY.getValue());
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime())); busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
} else { } else {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -767,7 +769,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setRuleTime(busAttendanceRuleVo.getClockOutTime()); attendance.setRuleTime(busAttendanceRuleVo.getClockOutTime());
// 判断是否为早退 // 判断是否为早退
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) { if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue()); attendance.setClockStatus(LEAVEEARLY.getValue());
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime())); attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
} else { } else {
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue()); attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
@ -784,7 +786,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setClockTime(now); attendance.setClockTime(now);
attendance.setUserName(constructionUser.getUserName()); attendance.setUserName(constructionUser.getUserName());
attendance.setReplaceId(replaceId); attendance.setReplaceId(replaceId);
if(req.getSource() != null){ if (req.getSource() != null) {
attendance.setSource(req.getSource()); attendance.setSource(req.getSource());
attendance.setSn(req.getSn()); attendance.setSn(req.getSn());
} }
@ -1026,7 +1028,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
} }
} }
// 再获取项目的规则 // 再获取项目的规则
BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectIdAndType(projectId,"0"); BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectIdAndType(projectId, "0");
if (busAttendanceRuleVo != null && "2".equals(busAttendanceRuleVo.getType())) { if (busAttendanceRuleVo != null && "2".equals(busAttendanceRuleVo.getType())) {
return true; return true;
} }
@ -1067,6 +1069,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
.eq(BusAttendance::getClockDate, localDate) .eq(BusAttendance::getClockDate, localDate)
); );
} }
@Override @Override
public List<BusAttendanceVo> getTodayAttendanceV1(Long projectId, Long userId) { public List<BusAttendanceVo> getTodayAttendanceV1(Long projectId, Long userId) {
@ -1074,7 +1077,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
userId = LoginHelper.getUserId(); userId = LoginHelper.getUserId();
} }
BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectIdV1(projectId,userId); BusAttendanceRuleVo busAttendanceRuleVo = attendanceRuleService.queryByProjectIdV1(projectId, userId);
if (busAttendanceRuleVo == null) { if (busAttendanceRuleVo == null) {
return List.of(); return List.of();
@ -1134,10 +1137,10 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
@Override @Override
public TableDataInfo<BusAttendanceVo> getAbnormalAttendance(Long projectId,String handle, PageQuery pageQuery) { public TableDataInfo<BusAttendanceVo> getAbnormalAttendance(Long projectId, String handle, PageQuery pageQuery) {
List<String> abnormalList = Arrays.asList(BusAttendanceClockStatusEnum.LATE.getValue(), List<String> abnormalList = Arrays.asList(LATE.getValue(),
BusAttendanceClockStatusEnum.LEAVEEARLY.getValue(), LEAVEEARLY.getValue(),
BusAttendanceClockStatusEnum.UNCLOCK.getValue()); BusAttendanceClockStatusEnum.UNCLOCK.getValue());
// 获取当前用户ID // 获取当前用户ID
@ -1654,8 +1657,8 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
String todayStr = currentDate.format(DateTimeFormatter.ISO_LOCAL_DATE); // 结果:"2024-10-10" String todayStr = currentDate.format(DateTimeFormatter.ISO_LOCAL_DATE); // 结果:"2024-10-10"
if(currentDate.isEqual(now)){ if (currentDate.isEqual(now)) {
vo.setAbsenteeism(allUserIds.size()- full); vo.setAbsenteeism(allUserIds.size() - full);
} }
int count = 0; int count = 0;
@ -1750,7 +1753,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
vo.setClockDate(now); vo.setClockDate(now);
vo.setAttendance(full); vo.setAttendance(full);
vo.setHalfAttendance(half); vo.setHalfAttendance(half);
vo.setAbsenteeism(allUserIds.size() - count-full-half); vo.setAbsenteeism(allUserIds.size() - count - full - half);
//计算考勤率 //计算考勤率
vo.setAllUserNum(allUserIds.size() - count); vo.setAllUserNum(allUserIds.size() - count);
vo.setLeave(count); vo.setLeave(count);
@ -1767,7 +1770,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
date = LocalDate.now(); date = LocalDate.now();
} }
if("1".equals(dto.getType())){ if ("1".equals(dto.getType())) {
List<BusAttendance> list = list(Wrappers.<BusAttendance>lambdaQuery() List<BusAttendance> list = list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, date) .eq(BusAttendance::getClockDate, date)
.eq(BusAttendance::getProjectId, dto.getProjectId()) .eq(BusAttendance::getProjectId, dto.getProjectId())
@ -1775,18 +1778,18 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
); );
List<Long> list1 = list.stream().map(BusAttendance::getUserId).distinct().toList(); List<Long> list1 = list.stream().map(BusAttendance::getUserId).distinct().toList();
if(CollectionUtil.isEmpty(list1)){ if (CollectionUtil.isEmpty(list1)) {
return TableDataInfo.build(); return TableDataInfo.build();
} }
dto.setUserIds(list1); dto.setUserIds(list1);
}else if("2".equals(dto.getType())){ } else if ("2".equals(dto.getType())) {
List<BusAttendance> list = list(Wrappers.<BusAttendance>lambdaQuery() List<BusAttendance> list = list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, date) .eq(BusAttendance::getClockDate, date)
.eq(BusAttendance::getProjectId, dto.getProjectId()) .eq(BusAttendance::getProjectId, dto.getProjectId())
.in(BusAttendance::getClockStatus, ATTENDANCE_LIST) .in(BusAttendance::getClockStatus, ATTENDANCE_LIST)
); );
List<Long> list1 = list.stream().map(BusAttendance::getUserId).distinct().toList(); List<Long> list1 = list.stream().map(BusAttendance::getUserId).distinct().toList();
if(date.isEqual(LocalDate.now())){ if (date.isEqual(LocalDate.now())) {
String todayStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE); String todayStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
List<BusLeave> list2 = leaveService.list(Wrappers.<BusLeave>lambdaQuery() List<BusLeave> list2 = leaveService.list(Wrappers.<BusLeave>lambdaQuery()
.eq(BusLeave::getProjectId, dto.getProjectId()) .eq(BusLeave::getProjectId, dto.getProjectId())
@ -1801,7 +1804,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
longs.addAll(list11); longs.addAll(list11);
dto.setUserIds(longs); dto.setUserIds(longs);
dto.setIsToday(true); dto.setIsToday(true);
}else{ } else {
List<BusAttendance> unlocks = list(Wrappers.<BusAttendance>lambdaQuery() List<BusAttendance> unlocks = list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, date) .eq(BusAttendance::getClockDate, date)
.eq(BusAttendance::getProjectId, dto.getProjectId()) .eq(BusAttendance::getProjectId, dto.getProjectId())
@ -1811,12 +1814,12 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
list11.removeAll(list1); list11.removeAll(list1);
dto.setUserIds(list11); dto.setUserIds(list11);
dto.setIsToday(false); dto.setIsToday(false);
if(CollectionUtil.isEmpty(list11)){ if (CollectionUtil.isEmpty(list11)) {
return TableDataInfo.build(); return TableDataInfo.build();
} }
} }
}else if("3".equals(dto.getType())){ } else if ("3".equals(dto.getType())) {
String todayStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE); String todayStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
List<BusLeave> list2 = leaveService.list(Wrappers.<BusLeave>lambdaQuery() List<BusLeave> list2 = leaveService.list(Wrappers.<BusLeave>lambdaQuery()
.eq(BusLeave::getProjectId, dto.getProjectId()) .eq(BusLeave::getProjectId, dto.getProjectId())
@ -1826,7 +1829,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
.apply("DATE(end_time) >= {0}", todayStr)); .apply("DATE(end_time) >= {0}", todayStr));
List<Long> list11 = list2.stream().map(BusLeave::getUserId).distinct().toList(); List<Long> list11 = list2.stream().map(BusLeave::getUserId).distinct().toList();
if(CollectionUtil.isEmpty(list11)){ if (CollectionUtil.isEmpty(list11)) {
return TableDataInfo.build(); return TableDataInfo.build();
} }
dto.setUserIds(list11); dto.setUserIds(list11);
@ -2222,4 +2225,308 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
} }
@Override
public BusAttendanceClockDateForTwoWeekVo getSubTodayAttendanceData(SubTwoWeekDto dto) {
LocalDate now = LocalDate.now();
//查询所有管理员和分包人员
List<SysUser> userListBySubDto = userService.getUserListBySubDto(dto);
List<Long> allUserIds = userListBySubDto.stream().map(SysUser::getUserId).collect(Collectors.toList());
//当天请假人数
String todayStr = now.format(DateTimeFormatter.ISO_LOCAL_DATE); // 结果:"2024-10-10"
// 2. 拼接 SQL 时添加单引号,确保语法正确
int count = 0;
if (CollectionUtil.isNotEmpty(allUserIds)) {
count = (int) leaveService.count(Wrappers.<BusLeave>lambdaQuery()
.eq(BusLeave::getProjectId, dto.getProjectId())
.in(BusLeave::getUserId, allUserIds)
// 关键:给日期字符串加单引号,避免 SQL 语法错误
.apply("DATE(start_time) <= {0}", todayStr)
.apply("DATE(end_time) >= {0}", todayStr)
);
}
List<BusAttendance> list;
if (CollectionUtil.isEmpty(allUserIds)) {
list = new ArrayList<>();
} else {
list = list(Wrappers.<BusAttendance>lambdaQuery()
.in(CollectionUtil.isNotEmpty(allUserIds), BusAttendance::getUserId, allUserIds)
.eq(BusAttendance::getClockDate, now)
.orderByAsc(BusAttendance::getClockDate)
);
}
Map<Long, List<BusAttendance>> collect = list.stream().collect(Collectors.groupingBy(BusAttendance::getUserId));
int full = 0, half = 0, absent = 0;
for (Map.Entry<Long, List<BusAttendance>> userEntry : collect.entrySet()) {
List<BusAttendance> records = userEntry.getValue();
long validCount = records.stream()
.map(BusAttendance::getClockStatus)
.filter(ATTENDANCE_LIST::contains)
.count();
if (validCount >= 2) {
full++;
} else if (validCount == 1) {
half++;
} else {
absent++;
}
}
BusAttendanceClockDateForTwoWeekVo vo = new BusAttendanceClockDateForTwoWeekVo();
vo.setClockDate(now);
vo.setAttendance(full);
vo.setHalfAttendance(half);
vo.setAbsenteeism(allUserIds.size() - count - full - half);
//计算考勤率
vo.setAllUserNum(allUserIds.size() - count);
vo.setLeave(count);
vo.setClockNum(full + half);
vo.setAttendanceRate(BigDecimalUtil.toPercentage(new BigDecimal(full + half),
new BigDecimal(vo.getAllUserNum())));
return vo;
}
@Override
public List<BusAttendanceClockDateForTwoWeekVo> getSubClockDateForTwoWeekList(SubTwoWeekDto dto) {
LocalDate now = LocalDate.now();
//查询所有分包人员
List<SysUser> userListBySubDto = userService.getUserListBySubDto(dto);
List<Long> allUserIds = userListBySubDto.stream().map(SysUser::getUserId).collect(Collectors.toList());
// 往前14天包含今天
LocalDate startDate = now.minusDays(13);
List<BusAttendance> list;
if (CollectionUtil.isEmpty(allUserIds)) {
list = new ArrayList<>();
} else {
list = list(Wrappers.<BusAttendance>lambdaQuery()
.in(BusAttendance::getUserId, allUserIds)
.between(BusAttendance::getClockDate, startDate, now)
.orderByAsc(BusAttendance::getClockDate)
);
}
// 按日期分组
Map<LocalDate, List<BusAttendance>> groupedByDate = list.stream()
.collect(Collectors.groupingBy(BusAttendance::getClockDate));
// 按日期和用户ID分组
Map<LocalDate, Map<Long, List<BusAttendance>>> dateUserMap = new HashMap<>();
for (Map.Entry<LocalDate, List<BusAttendance>> entry : groupedByDate.entrySet()) {
LocalDate date = entry.getKey();
Map<Long, List<BusAttendance>> userAttendanceMap = entry.getValue().stream()
.collect(Collectors.groupingBy(BusAttendance::getUserId));
dateUserMap.put(date, userAttendanceMap);
}
// 统计全勤、半勤、缺卡人数
List<BusAttendanceClockDateForTwoWeekVo> result = new ArrayList<>();
LocalDate currentDate = startDate;
while (!currentDate.isAfter(now)) {
Map<Long, List<BusAttendance>> userAttendanceMap = dateUserMap.getOrDefault(currentDate, new HashMap<>());
int full = 0, half = 0, absent = 0;
for (Map.Entry<Long, List<BusAttendance>> userEntry : userAttendanceMap.entrySet()) {
List<BusAttendance> records = userEntry.getValue();
long validCount = records.stream()
.map(BusAttendance::getClockStatus)
.filter(ATTENDANCE_LIST::contains)
.count();
if (validCount >= 1) {
full++;
} else {
absent++;
}
}
BusAttendanceClockDateForTwoWeekVo vo = new BusAttendanceClockDateForTwoWeekVo();
vo.setClockDate(currentDate);
vo.setAttendance(full);
vo.setHalfAttendance(half);
vo.setAbsenteeism(absent);
String todayStr = currentDate.format(DateTimeFormatter.ISO_LOCAL_DATE); // 结果:"2024-10-10"
if (currentDate.isEqual(now)) {
vo.setAbsenteeism(allUserIds.size() - full);
}
int count = 0;
if (CollectionUtil.isNotEmpty(allUserIds)) {
count = (int) leaveService.count(Wrappers.<BusLeave>lambdaQuery()
.eq(BusLeave::getProjectId, dto.getProjectId())
.in(BusLeave::getUserId, allUserIds)
// 关键:给日期字符串加单引号,避免 SQL 语法错误
.apply("DATE(start_time) <= {0}", todayStr)
.apply("DATE(end_time) >= {0}", todayStr)
);
}
vo.setLeave(count);
result.add(vo);
currentDate = currentDate.plusDays(1);
}
return result;
}
@Override
public TableDataInfo<SubUserAttendanceTotalVo> subCountList(SubUserAttendanceQueryReq dto, PageQuery pageQuery) {
if (dto.getClockDate() == null) {
throw new ServiceException("请选择月份");
}
TableDataInfo<SysUserVo> sysUserVoTableDataInfo = userService.selectPageFbUserAttendanceList(dto, pageQuery);
List<SysUserVo> rows = sysUserVoTableDataInfo.getRows();
List<Long> list1 = rows.stream().map(SysUserVo::getUserId).distinct().toList();
// 解析输入的年月字符串(拼接-01作为当月第一天
LocalDate date = LocalDate.parse(dto.getClockDate() + "-01");
// 月份开始日期当月1日
LocalDate startDate = date.with(TemporalAdjusters.firstDayOfMonth());
// 月份结束日期:当月最后一天
LocalDate endDate = date.with(TemporalAdjusters.lastDayOfMonth());
List<BusAttendance> list;
if (CollectionUtil.isEmpty(list1)) {
list = new ArrayList<>();
}else {
list = list(Wrappers.<BusAttendance>lambdaQuery()
.in(BusAttendance::getUserId, list1)
.between(BusAttendance::getClockDate, startDate, endDate)
.orderByAsc(BusAttendance::getClockDate)
);
}
List<SubUserAttendanceTotalVo> list2 = new ArrayList<>();
for (SysUserVo sysUserVo : rows) {
SubUserAttendanceTotalVo vo = new SubUserAttendanceTotalVo();
vo.setUserName(sysUserVo.getUserName());
vo.setContractorId(sysUserVo.getContractorId());
vo.setContractorName(sysUserVo.getContractorName());
List<BusAttendance> userList = list.stream().filter(attendance -> attendance.getUserId().equals(sysUserVo.getUserId())).toList();
//出勤天数
long count = userList.stream().filter(attendance -> ATTENDANCE_LIST.contains(attendance.getClockStatus()))
.map(BusAttendance::getClockDate).distinct().count();
vo.setAttendanceDays(Math.toIntExact(count));
//迟到次数
long lateCount = userList.stream().filter(attendance -> attendance.getClockStatus().equals(LATE.getValue())).count();
vo.setLateDays(Math.toIntExact(lateCount));
//早退次数
long leaveEarlyCount = userList.stream().filter(attendance -> attendance.getClockStatus().equals(LEAVEEARLY.getValue())).count();
vo.setLeaveEarlyDays(Math.toIntExact(leaveEarlyCount));
//缺卡次数
long unClockCount = userList.stream().filter(attendance -> attendance.getClockStatus().equals(UNCLOCK.getValue())).count();
vo.setUnClockDays(Math.toIntExact(unClockCount));
list2.add(vo);
}
return new TableDataInfo<>(list2, sysUserVoTableDataInfo.getTotal());
}
@Override
public TableDataInfo<SubAttendanceTodayUserVo> getSubTodayAttendanceUser(SubTodayUserDto dto, PageQuery pageQuery) {
LocalDate date = dto.getDate();
if (date == null) {
date = LocalDate.now();
}
if ("1".equals(dto.getType())) {
List<BusAttendance> list = list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, date)
.eq(BusAttendance::getProjectId, dto.getProjectId())
.in(BusAttendance::getClockStatus, ATTENDANCE_LIST)
);
List<Long> list1 = list.stream().map(BusAttendance::getUserId).distinct().toList();
if (CollectionUtil.isEmpty(list1)) {
return TableDataInfo.build();
}
dto.setUserIds(list1);
} else if ("2".equals(dto.getType())) {
List<BusAttendance> list = list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, date)
.eq(BusAttendance::getProjectId, dto.getProjectId())
.in(BusAttendance::getClockStatus, ATTENDANCE_LIST)
);
List<Long> list1 = list.stream().map(BusAttendance::getUserId).distinct().toList();
if (date.isEqual(LocalDate.now())) {
String todayStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
List<BusLeave> list2 = leaveService.list(Wrappers.<BusLeave>lambdaQuery()
.eq(BusLeave::getProjectId, dto.getProjectId())
// 关键:给日期字符串加单引号,避免 SQL 语法错误
.apply("DATE(start_time) <= {0}", todayStr)
.apply("DATE(end_time) >= {0}", todayStr));
List<Long> list11 = list2.stream().map(BusLeave::getUserId).distinct().toList();
ArrayList<Long> longs = new ArrayList<>();
longs.addAll(list1);
longs.addAll(list11);
dto.setUserIds(longs);
dto.setIsToday(true);
} else {
List<BusAttendance> unlocks = list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, date)
.eq(BusAttendance::getProjectId, dto.getProjectId())
.eq(BusAttendance::getClockStatus, BusAttendanceClockStatusEnum.UNCLOCK.getValue())
);
List<Long> list11 = new ArrayList<>(unlocks.stream().map(BusAttendance::getUserId).distinct().toList());
list11.removeAll(list1);
dto.setUserIds(list11);
dto.setIsToday(false);
if (CollectionUtil.isEmpty(list11)) {
return TableDataInfo.build();
}
}
} else if ("3".equals(dto.getType())) {
String todayStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
List<BusLeave> list2 = leaveService.list(Wrappers.<BusLeave>lambdaQuery()
.eq(BusLeave::getProjectId, dto.getProjectId())
// 关键:给日期字符串加单引号,避免 SQL 语法错误
.apply("DATE(start_time) <= {0}", todayStr)
.apply("DATE(end_time) >= {0}", todayStr));
List<Long> list11 = list2.stream().map(BusLeave::getUserId).distinct().toList();
if (CollectionUtil.isEmpty(list11)) {
return TableDataInfo.build();
}
dto.setUserIds(list11);
}
TableDataInfo<SysUserVo> sysUserVoTableDataInfo = userService.todayUserList(dto, pageQuery);
List<SubAttendanceTodayUserVo> list = new ArrayList<>();
for (SysUserVo sysUserVo : sysUserVoTableDataInfo.getRows()) {
SubAttendanceTodayUserVo subAttendanceTodayUserVo = new SubAttendanceTodayUserVo();
subAttendanceTodayUserVo.setUserId(sysUserVo.getUserId());
subAttendanceTodayUserVo.setUserName(sysUserVo.getUserName());
subAttendanceTodayUserVo.setContractorId(sysUserVo.getContractorId());
subAttendanceTodayUserVo.setContractorName(sysUserVo.getContractorName());
list.add(subAttendanceTodayUserVo);
}
return new TableDataInfo<>(list, sysUserVoTableDataInfo.getTotal());
}
} }

View File

@ -2,6 +2,12 @@ package org.dromara.system.service;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.domain.dto.attendance.SubTodayUserDto;
import org.dromara.project.domain.dto.attendance.SubTwoWeekDto;
import org.dromara.project.domain.dto.attendance.SubUserAttendanceQueryReq;
import org.dromara.project.domain.dto.attendance.TodayUserDto;
import org.dromara.project.domain.vo.attendance.AttendanceTodayUserVo;
import org.dromara.project.domain.vo.attendance.SubUserAttendanceTotalVo;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysUserBo; import org.dromara.system.domain.bo.SysUserBo;
import org.dromara.system.domain.dto.FbUserListDto; import org.dromara.system.domain.dto.FbUserListDto;
@ -286,4 +292,10 @@ public interface ISysUserService {
Boolean deletion(); Boolean deletion();
Boolean passwordCompare(String password); Boolean passwordCompare(String password);
List<SysUser> getUserListBySubDto(SubTwoWeekDto dto);
TableDataInfo<SysUserVo> selectPageFbUserAttendanceList(SubUserAttendanceQueryReq dto, PageQuery pageQuery);
TableDataInfo<SysUserVo> todayUserList(SubTodayUserDto dto, PageQuery pageQuery);
} }

View File

@ -40,6 +40,11 @@ import org.dromara.design.service.IDesUserService;
import org.dromara.design.service.IDesVolumeCatalogService; import org.dromara.design.service.IDesVolumeCatalogService;
import org.dromara.design.service.IDesVolumeFileService; import org.dromara.design.service.IDesVolumeFileService;
import org.dromara.project.domain.BusUserProjectRelevancy; import org.dromara.project.domain.BusUserProjectRelevancy;
import org.dromara.project.domain.dto.attendance.SubTodayUserDto;
import org.dromara.project.domain.dto.attendance.SubTwoWeekDto;
import org.dromara.project.domain.dto.attendance.SubUserAttendanceQueryReq;
import org.dromara.project.domain.dto.attendance.TodayUserDto;
import org.dromara.project.domain.vo.attendance.SubUserAttendanceTotalVo;
import org.dromara.project.domain.vo.projectteam.BusProjectTeamAppVo; import org.dromara.project.domain.vo.projectteam.BusProjectTeamAppVo;
import org.dromara.project.service.IBusProjectTeamService; import org.dromara.project.service.IBusProjectTeamService;
import org.dromara.project.service.IBusUserProjectRelevancyService; import org.dromara.project.service.IBusUserProjectRelevancyService;
@ -1419,4 +1424,89 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
List<Long> longs = desUserService.selectbySpecialtyAndType(specialty, type,projectId); List<Long> longs = desUserService.selectbySpecialtyAndType(specialty, type,projectId);
return longs.stream().map(String::valueOf).toList(); return longs.stream().map(String::valueOf).toList();
} }
@Override
public List<SysUser> getUserListBySubDto(SubTwoWeekDto dto) {
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getAppUserType, "2");
wrapper.like(StringUtils.isNotBlank(dto.getUserName()),SysUser::getUserName, dto.getUserName());
wrapper.like(dto.getContractorId()!=null,SysUser::getContractorId, dto.getContractorId());
wrapper.exists("SELECT 1 FROM bus_user_project_relevancy " +
"WHERE bus_user_project_relevancy.user_id = sys_user.user_id " +
"AND project_id = {0}", dto.getProjectId());
return baseMapper.selectList(wrapper);
}
@Override
public TableDataInfo<SysUserVo> selectPageFbUserAttendanceList(SubUserAttendanceQueryReq dto, PageQuery pageQuery){
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getAppUserType, "2");
wrapper.eq(dto.getContractorId()!=null,SysUser::getContractorId, dto.getContractorId());
wrapper.like(StringUtils.isNotBlank(dto.getUserName()),SysUser::getUserName, dto.getUserName());
wrapper.exists("SELECT 1 FROM bus_user_project_relevancy " +
"WHERE bus_user_project_relevancy.user_id = u.user_id " +
"AND project_id = {0}", dto.getProjectId());
Page<SysUserVo> page = baseMapper.selectPageUserList(pageQuery.build(), wrapper);
List<SysUserVo> userVoList = page.getRecords();
if (CollUtil.isNotEmpty(userVoList)) {
List<Long> list1 = userVoList.stream().map(SysUserVo::getContractorId).toList();
List<SubContractor> subContractors = contractorService.listByIds(list1);
Map<Long, String> collect = subContractors.stream().collect(Collectors.toMap(SubContractor::getId, SubContractor::getName));
userVoList.forEach(userVo -> {
Long contractorId = userVo.getContractorId();
userVo.setContractorName(collect.get(contractorId));
});
page.setRecords(userVoList);
}
return TableDataInfo.build(page);
}
@Override
public TableDataInfo<SysUserVo> todayUserList(SubTodayUserDto dto, PageQuery pageQuery) {
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getAppUserType, "2");
wrapper.eq(dto.getContractorId()!=null,SysUser::getContractorId, dto.getContractorId());
wrapper.like(StringUtils.isNotBlank(dto.getUserName()),SysUser::getUserName, dto.getUserName());
wrapper.exists("SELECT 1 FROM bus_user_project_relevancy " +
"WHERE bus_user_project_relevancy.user_id = u.user_id " +
"AND project_id = {0}", dto.getProjectId());
if("1".equals(dto.getType())){
wrapper.in(SysUser::getUserId, dto.getUserIds());
}else if("2".equals(dto.getType())){
if(dto.getIsToday()){
wrapper.notIn(CollectionUtil.isNotEmpty(dto.getUserIds()),SysUser::getUserId, dto.getUserIds());
}else {
wrapper.in(SysUser::getUserId, dto.getUserIds());
}
}else{
wrapper.in(SysUser::getUserId, dto.getUserIds());
}
Page<SysUserVo> page = baseMapper.selectPageUserList(pageQuery.build(), wrapper);
List<SysUserVo> userVoList = page.getRecords();
if (CollUtil.isNotEmpty(userVoList)) {
List<Long> list1 = userVoList.stream().map(SysUserVo::getContractorId).toList();
List<SubContractor> subContractors = contractorService.listByIds(list1);
Map<Long, String> collect = subContractors.stream().collect(Collectors.toMap(SubContractor::getId, SubContractor::getName));
userVoList.forEach(userVo -> {
Long contractorId = userVo.getContractorId();
userVo.setContractorName(collect.get(contractorId));
});
page.setRecords(userVoList);
}
return TableDataInfo.build(page);
}
} }