分包考勤
This commit is contained in:
@ -1617,7 +1617,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
|
||||
List<BusProjectTeam> busProjectTeams = projectTeamService.listByIds(list1);
|
||||
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) {
|
||||
AttendanceTodayUserVo attendanceTodayUserVo = new AttendanceTodayUserVo();
|
||||
attendanceTodayUserVo.setUserId(constructionUser.getSysUserId());
|
||||
@ -1627,6 +1627,6 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
|
||||
attendanceTodayUserVos.add(attendanceTodayUserVo);
|
||||
}
|
||||
|
||||
return new TableDataInfo<AttendanceTodayUserVo>(attendanceTodayUserVos, result.getTotal());
|
||||
return new TableDataInfo<>(attendanceTodayUserVos, result.getTotal());
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,11 +6,16 @@ import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
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.projectteam.BusProjectTeamQueryReq;
|
||||
import org.dromara.project.domain.vo.attendance.*;
|
||||
import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo;
|
||||
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.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
@ -43,6 +48,8 @@ public class BusAttendanceController extends BaseController {
|
||||
|
||||
private final IBusProjectTeamService projectTeamService;
|
||||
|
||||
private final ISubContractorService contractorService;
|
||||
|
||||
/**
|
||||
* 查询考勤列表
|
||||
*/
|
||||
@ -156,4 +163,47 @@ public class BusAttendanceController extends BaseController {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -196,5 +196,23 @@ public interface IBusAttendanceService extends IService<BusAttendance>{
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@ -47,6 +47,7 @@ import org.dromara.project.domain.vo.attendance.*;
|
||||
import org.dromara.project.domain.vo.projectteam.BusProjectTeamAppVo;
|
||||
import org.dromara.project.mapper.BusAttendanceMapper;
|
||||
import org.dromara.project.service.*;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
import org.dromara.system.domain.vo.SysOssVo;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.service.ISysOssService;
|
||||
@ -60,11 +61,12 @@ import java.io.OutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.dromara.project.domain.enums.BusAttendanceClockStatusEnum.ATTENDANCE_LIST;
|
||||
import static org.dromara.project.domain.enums.BusAttendanceClockStatusEnum.*;
|
||||
|
||||
/**
|
||||
* 考勤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(),
|
||||
BusAttendanceClockStatusEnum.LATE.getValue(), BusAttendanceClockStatusEnum.LEAVEEARLY.getValue()
|
||||
LATE.getValue(), LEAVEEARLY.getValue()
|
||||
, BusAttendanceClockStatusEnum.REISSUE.getValue()));
|
||||
|
||||
|
||||
@ -159,14 +161,14 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
String clockMonth = req.getClockMonth();
|
||||
SubConstructionUser constructionUser = constructionUserService.getById(userId);
|
||||
if (constructionUser == null) {
|
||||
throw new ServiceException("施工人员信息不存在", HttpStatus.NOT_FOUND);
|
||||
throw new ServiceException("实名认证信息不存在", HttpStatus.ERROR);
|
||||
}
|
||||
// 解析月份
|
||||
YearMonth yearMonth;
|
||||
if (StringUtils.isNotBlank(clockMonth)) {
|
||||
// 校验月份格式
|
||||
if (!DateConstant.YEAR_MONTH_PATTERN.matcher(clockMonth).matches()) {
|
||||
throw new ServiceException("月份格式不正确", HttpStatus.BAD_REQUEST);
|
||||
throw new ServiceException("月份格式不正确", HttpStatus.ERROR);
|
||||
}
|
||||
yearMonth = YearMonth.parse(clockMonth);
|
||||
} else {
|
||||
@ -400,7 +402,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
attendance.setRuleTime(busAttendanceRuleVo.getClockInTime());
|
||||
// 判断是否为迟到
|
||||
if (isLate(now, busAttendanceRuleVo)) {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue());
|
||||
attendance.setClockStatus(LATE.getValue());
|
||||
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
|
||||
} else {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -454,7 +456,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
busAttendance.setClockTime(now);
|
||||
// 判断是否为迟到
|
||||
if (isLate(now, busAttendanceRuleVo)) {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue());
|
||||
busAttendance.setClockStatus(LATE.getValue());
|
||||
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
|
||||
} else {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -497,7 +499,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
busAttendance.setClockTime(now);
|
||||
// 判断是否为早退
|
||||
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue());
|
||||
busAttendance.setClockStatus(LEAVEEARLY.getValue());
|
||||
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
|
||||
} else {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -516,7 +518,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
attendance.setRuleTime(busAttendanceRuleVo.getClockOutTime());
|
||||
// 判断是否为早退
|
||||
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue());
|
||||
attendance.setClockStatus(LEAVEEARLY.getValue());
|
||||
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
|
||||
} else {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -651,7 +653,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
attendance.setRuleTime(busAttendanceRuleVo.getClockInTime());
|
||||
// 判断是否为迟到
|
||||
if (isLate(now, busAttendanceRuleVo)) {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue());
|
||||
attendance.setClockStatus(LATE.getValue());
|
||||
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
|
||||
} else {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -705,7 +707,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
busAttendance.setClockTime(now);
|
||||
// 判断是否为迟到
|
||||
if (isLate(now, busAttendanceRuleVo)) {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue());
|
||||
busAttendance.setClockStatus(LATE.getValue());
|
||||
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
|
||||
} else {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -748,7 +750,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
busAttendance.setClockTime(now);
|
||||
// 判断是否为早退
|
||||
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue());
|
||||
busAttendance.setClockStatus(LEAVEEARLY.getValue());
|
||||
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
|
||||
} else {
|
||||
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -767,7 +769,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
attendance.setRuleTime(busAttendanceRuleVo.getClockOutTime());
|
||||
// 判断是否为早退
|
||||
if (isLeaveEarly(now, busAttendanceRuleVo, localDate)) {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVEEARLY.getValue());
|
||||
attendance.setClockStatus(LEAVEEARLY.getValue());
|
||||
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockOutTime()));
|
||||
} else {
|
||||
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
|
||||
@ -1067,6 +1069,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
.eq(BusAttendance::getClockDate, localDate)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BusAttendanceVo> getTodayAttendanceV1(Long projectId, Long userId) {
|
||||
|
||||
@ -1136,8 +1139,8 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
@Override
|
||||
public TableDataInfo<BusAttendanceVo> getAbnormalAttendance(Long projectId, String handle, PageQuery pageQuery) {
|
||||
|
||||
List<String> abnormalList = Arrays.asList(BusAttendanceClockStatusEnum.LATE.getValue(),
|
||||
BusAttendanceClockStatusEnum.LEAVEEARLY.getValue(),
|
||||
List<String> abnormalList = Arrays.asList(LATE.getValue(),
|
||||
LEAVEEARLY.getValue(),
|
||||
BusAttendanceClockStatusEnum.UNCLOCK.getValue());
|
||||
|
||||
// 获取当前用户ID
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,12 @@ package org.dromara.system.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
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.bo.SysUserBo;
|
||||
import org.dromara.system.domain.dto.FbUserListDto;
|
||||
@ -286,4 +292,10 @@ public interface ISysUserService {
|
||||
Boolean deletion();
|
||||
|
||||
Boolean passwordCompare(String password);
|
||||
|
||||
List<SysUser> getUserListBySubDto(SubTwoWeekDto dto);
|
||||
|
||||
TableDataInfo<SysUserVo> selectPageFbUserAttendanceList(SubUserAttendanceQueryReq dto, PageQuery pageQuery);
|
||||
|
||||
TableDataInfo<SysUserVo> todayUserList(SubTodayUserDto dto, PageQuery pageQuery);
|
||||
}
|
||||
|
||||
@ -40,6 +40,11 @@ import org.dromara.design.service.IDesUserService;
|
||||
import org.dromara.design.service.IDesVolumeCatalogService;
|
||||
import org.dromara.design.service.IDesVolumeFileService;
|
||||
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.service.IBusProjectTeamService;
|
||||
import org.dromara.project.service.IBusUserProjectRelevancyService;
|
||||
@ -1419,4 +1424,89 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
||||
List<Long> longs = desUserService.selectbySpecialtyAndType(specialty, type,projectId);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user