分包考勤

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);
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());
}
}

View File

@ -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);
}
}

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);
/**
* 获取分包当天的考勤数据
*/
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.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());
}
}

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.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);
}

View File

@ -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);
}
}