feat(smartfactory): 增加工种筛选功能并优化考勤记录逻辑

- 在 StaffAttendanceRecordReqVO 中添加 workTypeId 字段,用于工种筛选
- 修改 StaffService 接口,增加按工种筛选的 getListByFactory 方法
- 重构 StaffAttendanceRecordServiceImpl 中的 convertRecord 方法,提高代码可读性和维护性
- 优化 StaffSalaryServiceImpl 中的扣款金额计算逻辑
- 在 StaffMapper 和 StaffSalaryMapper 中添加创建时间降序排序
This commit is contained in:
aikai 2025-07-17 14:23:36 +08:00
parent 224a758f11
commit 875a3ff406
8 changed files with 117 additions and 95 deletions

View File

@ -149,8 +149,9 @@ public class StaffAttendanceRecordController {
// 查询该厂区员工在 其他厂区得考勤记录
List<StaffAttendanceRecordDO> otherRecordDOS = staffAttendanceRecordService.getOtherRecord(reqVO);
// 获取工厂员工列表
List<StaffDO> staffDOS = staffService.getListByFactory(reqVO.getFactoryId(), true);
// 获取工厂员工列表支持工种筛选
List<Integer> workTypeIds = reqVO.getWorkTypeId() != null ? Collections.singletonList(reqVO.getWorkTypeId()) : null;
List<StaffDO> staffDOS = staffService.getListByFactory(reqVO.getFactoryId(), true, workTypeIds);
Map<Long, StaffDO> staffMap = convertMap(staffDOS, StaffDO::getId);
if (CollUtil.isNotEmpty(recordDOS)) {
@ -180,7 +181,7 @@ public class StaffAttendanceRecordController {
recordRespVO.addAll(otherRespVO);
return success(recordRespVO);
}else {
} else {
// 判断是否 新增考勤情况
if (reqVO.getFactoryId() != null && reqVO.getMonth() != null && reqVO.getType() != null) {
@ -196,7 +197,7 @@ public class StaffAttendanceRecordController {
.setStaffName(staffDO.getNickName())
.setWorkTypeId(staffDO.getWorkTypeId());
return success(Collections.singletonList(respVO));
}else {
} else {
List<StaffAttendanceRecordRespVO> respVO = staffDOS.stream()
.map(staffDO -> new StaffAttendanceRecordRespVO()
.setStaffId(staffDO.getId())
@ -220,7 +221,7 @@ public class StaffAttendanceRecordController {
@PreAuthorize("@ss.hasPermission('smartfactory:staff-attendance-record:export')")
@OperateLog(type = EXPORT)
public void exportStaffAttendanceRecordExcel(@Valid StaffAttendanceRecordReqVO reqVO,
HttpServletResponse response) throws IOException {
HttpServletResponse response) throws IOException {
List<StaffAttendanceRecordDO> recordDOS = staffAttendanceRecordService.getStaffAttendanceRecordList(reqVO);
// 导出 Excel
@ -239,4 +240,4 @@ public class StaffAttendanceRecordController {
staffAttendanceRecordService.updateReview(factoryId, month);
return success(true);
}
}
}

View File

@ -20,4 +20,7 @@ public class StaffAttendanceRecordReqVO {
@Schema(description = "考勤方式 | 1.正常月份 2.25号开始计算至下个月24号", example = "1")
private Integer type;
}
@Schema(description = "工种id", example = "1")
private Integer workTypeId;
}

View File

@ -76,7 +76,7 @@ public interface StaffMapper extends BaseMapperX<StaffDO> {
query.eqIfPresent(StaffDO::getFactoryId, pageReqVO.getFactoryId());
query.eqIfPresent(StaffDO::getWorkTypeId, pageReqVO.getWorkTypeId());
query.eqIfPresent(StaffDO::getId, pageReqVO.getStaffId());
query.orderByDesc(StaffSalaryDO::getCreateTime);
return selectJoinPage(pageReqVO, StaffSalaryRespVO.class, query);
}

View File

@ -41,7 +41,7 @@ public interface StaffSalaryMapper extends BaseMapperX<StaffSalaryDO> {
query.eqIfPresent(StaffSalaryDO::getStatus, reqVO.getStatus());
query.eqIfPresent(StaffSalaryDO::getIsGrant, reqVO.getIsGrant());
query.apply(Objects.nonNull(reqVO.getWorkTypeId()), "staff.work_type_id = {0} ", reqVO.getWorkTypeId());
query.orderByDesc(StaffSalaryDO::getCreateTime);
return selectJoinPage(reqVO, StaffSalaryRespVO.class, query);
}
@ -60,4 +60,4 @@ public interface StaffSalaryMapper extends BaseMapperX<StaffSalaryDO> {
return selectJoinList(StaffSalaryRespVO.class, query);
}
}
}

View File

@ -124,7 +124,7 @@ public class StaffAttendanceRecordServiceImpl implements StaffAttendanceRecordSe
List<StaffAttendanceRecordDO> lastMonthRecord = staffAttendanceRecordMapper.selectList(new LambdaQueryWrapperX<StaffAttendanceRecordDO>()
.eq(StaffAttendanceRecordDO::getStaffId, staffId)
.betweenIfPresent(StaffAttendanceRecordDO::getPunchTime, new LocalDate[]{ beginDate, lastMonthEnd }));
.betweenIfPresent(StaffAttendanceRecordDO::getPunchTime, new LocalDate[]{beginDate, lastMonthEnd}));
recordDOS.addAll(lastMonthRecord);
}
@ -176,7 +176,7 @@ public class StaffAttendanceRecordServiceImpl implements StaffAttendanceRecordSe
// 获取查询月份得第25日日期
LocalDate lastMonthEnd = now.withDayOfMonth(25);
date = new LocalDate[]{ beginDate, lastMonthEnd };
date = new LocalDate[]{beginDate, lastMonthEnd};
}
return staffAttendanceRecordMapper.selectRecordList(reqVO, date);
}
@ -216,48 +216,20 @@ public class StaffAttendanceRecordServiceImpl implements StaffAttendanceRecordSe
public List<StaffAttendanceRecordRespVO> convertRecord(StaffAttendanceRecordReqVO reqVO,
List<StaffAttendanceRecordDO> recordDOS,
List<StaffAttendanceRecordDO> otherRecordDOS) {
// 根据考勤类型 生成对应得日期数据
List<AttendanceRecordVO> punchTimeList = new ArrayList<>();
// 根据考勤类型生成对应的日期列表
List<AttendanceRecordVO> punchTimeList = generatePunchTimeList(reqVO);
// 获取所选月份的第一天
LocalDate now = LocalDate.parse(reqVO.getMonth() + "-01", DateTimeFormatter.ISO_LOCAL_DATE);
if (reqVO.getType() == 1) {
// 获取上月26日日期
LocalDate beginDate = now.minusMonths(1).withDayOfMonth(26);
// 本月25日日期
LocalDate lastMonthEnd = now.withDayOfMonth(25);
while (!beginDate.isAfter(lastMonthEnd)) {
AttendanceRecordVO attendanceRecordVO = new AttendanceRecordVO()
.setPunchTime(beginDate);
punchTimeList.add(attendanceRecordVO);
beginDate = beginDate.plusDays(1);
}
}
if (reqVO.getType() == 2) {
// 获取所选月份的第一天
LocalDate firstDayOfMonth = LocalDate.parse(reqVO.getMonth() + "-01", DateTimeFormatter.ISO_LOCAL_DATE);
// 生成当月每一天的 LocalDate
for (int i = 0; i < firstDayOfMonth.lengthOfMonth(); i++) {
AttendanceRecordVO attendanceRecordVO = new AttendanceRecordVO()
.setPunchTime(firstDayOfMonth.plusDays(i));
punchTimeList.add(attendanceRecordVO);
}
}
// 获取员工信息
// 获取员工信息 - 在当前厂区打卡的员工信息
List<StaffDO> staffDOS = staffService.getList(convertSet(recordDOS, StaffAttendanceRecordDO::getStaffId));
Map<Long, StaffDO> staffMap = convertMap(staffDOS, StaffDO::getId);
// 获取厂区信息
// 获取厂区信息 - 获取员工所打卡的所有厂区ids - 获取所有厂区信息
Set<Long> factoryIds = convertSet(recordDOS, StaffAttendanceRecordDO::getFactoryId);
factoryIds.addAll(convertList(otherRecordDOS, StaffAttendanceRecordDO::getFactoryId));
List<FactoryInfoDO> factoryDOS = factoryInfoService.getFactoryList(factoryIds);
Map<Long, FactoryInfoDO> factoryMap = convertMap(factoryDOS, FactoryInfoDO::getId);
// 根据用户 分组打卡记录
// 根据用户分组打卡记录
Map<Long, List<StaffAttendanceRecordDO>> recordMap = convertMultiMap(recordDOS, StaffAttendanceRecordDO::getStaffId);
// 重组数据
@ -275,10 +247,12 @@ public class StaffAttendanceRecordServiceImpl implements StaffAttendanceRecordSe
reqVO.getType(),
reqVO.getMonth());
// 筛选同一个工厂打卡数据并按日期建立映射
Map<LocalDate, AttendanceRecordVO> records = entry.getValue().stream()
.filter(record -> record.getFactoryId().equals(reqVO.getFactoryId())) // 筛选同一个工厂打卡数据
.filter(record -> record.getFactoryId().equals(reqVO.getFactoryId()))
.map(item -> BeanUtils.toBean(item, AttendanceRecordVO.class))
.collect(Collectors.toMap(AttendanceRecordVO::getPunchTime, value -> value));
// 设置打卡数据
List<AttendanceRecordVO> recordVOS = punchTimeList.stream()
.map(record -> {
@ -289,44 +263,16 @@ public class StaffAttendanceRecordServiceImpl implements StaffAttendanceRecordSe
return recordVO;
}).collect(Collectors.toList());
respVO.setRecords(recordVOS);
// 设置员工名称
respVO.setStaffName(staffMap.get(entry.getKey()).getNickName());
// 设置工种
respVO.setWorkTypeId(staffMap.get(entry.getKey()).getWorkTypeId());
// 设置厂区名称
// 设置员工名称工种厂区名称
StaffDO staffDO = staffMap.get(entry.getKey());
respVO.setStaffName(staffDO.getNickName());
respVO.setWorkTypeId(staffDO.getWorkTypeId());
respVO.setFactoryName(factoryMap.get(reqVO.getFactoryId()) != null ? factoryMap.get(reqVO.getFactoryId()).getName() : null);
// 处理其他厂区的考勤记录
if (CollUtil.isNotEmpty(otherRecordDOS)) {
// 获得该员工 在其他工厂的考勤记录
Map<Long, List<StaffAttendanceRecordDO>> factoryRecordMap = convertMultiMap(otherRecordDOS, StaffAttendanceRecordDO::getFactoryId);
List<StaffAttendanceRecordRespVO> childRespVO = otherRecordDOS.stream()
.map(recordDO -> new StaffAttendanceRecordRespVO(
recordDO.getStaffId(),
recordDO.getFactoryId(),
recordDO.getType(),
recordDO.getMonth()))
.distinct()
.collect(Collectors.toList());
childRespVO.forEach(vo -> {
if (!staffMap.containsKey(vo.getStaffId())) {
return;
}
// 设置员工名称
vo.setStaffName(staffMap.get(vo.getStaffId()).getNickName());
// 设置工种
vo.setWorkTypeId(staffMap.get(vo.getStaffId()).getWorkTypeId());
// 设置厂区名称
vo.setFactoryName(factoryMap.get(vo.getFactoryId()) != null ? factoryMap.get(vo.getFactoryId()).getName() : null);
if (factoryRecordMap.containsKey(vo.getFactoryId())) {
// 设置打卡记录
vo.setRecords(BeanUtils.toBean(factoryRecordMap.get(vo.getFactoryId()), AttendanceRecordVO.class));
}
});
// 插入其他考勤记录
List<StaffAttendanceRecordRespVO> childRespVO = processOtherFactoryRecords(otherRecordDOS, staffMap, factoryMap);
respVO.setChildRecords(childRespVO);
}
@ -336,4 +282,65 @@ public class StaffAttendanceRecordServiceImpl implements StaffAttendanceRecordSe
return respVOs;
}
}
/**
* 根据考勤类型生成对应的日期列表
*/
private List<AttendanceRecordVO> generatePunchTimeList(StaffAttendanceRecordReqVO reqVO) {
List<AttendanceRecordVO> punchTimeList = new ArrayList<>();
LocalDate now = LocalDate.parse(reqVO.getMonth() + "-01", DateTimeFormatter.ISO_LOCAL_DATE);
if (reqVO.getType() == 1) {
LocalDate beginDate = now.minusMonths(1).withDayOfMonth(26);
LocalDate lastMonthEnd = now.withDayOfMonth(25);
while (!beginDate.isAfter(lastMonthEnd)) {
punchTimeList.add(new AttendanceRecordVO().setPunchTime(beginDate));
beginDate = beginDate.plusDays(1);
}
} else if (reqVO.getType() == 2) {
LocalDate firstDayOfMonth = now;
int lengthOfMonth = firstDayOfMonth.lengthOfMonth();
for (int i = 0; i < lengthOfMonth; i++) {
punchTimeList.add(new AttendanceRecordVO().setPunchTime(firstDayOfMonth.plusDays(i)));
}
}
return punchTimeList;
}
/**
* 处理其他厂区的考勤记录
*/
private List<StaffAttendanceRecordRespVO> processOtherFactoryRecords(List<StaffAttendanceRecordDO> otherRecordDOS,
Map<Long, StaffDO> staffMap,
Map<Long, FactoryInfoDO> factoryMap) {
Map<Long, List<StaffAttendanceRecordDO>> factoryRecordMap = convertMultiMap(otherRecordDOS, StaffAttendanceRecordDO::getFactoryId);
return otherRecordDOS.stream()
.map(recordDO -> new StaffAttendanceRecordRespVO(
recordDO.getStaffId(),
recordDO.getFactoryId(),
recordDO.getType(),
recordDO.getMonth()))
.distinct()
.peek(vo -> {
if (staffMap.containsKey(vo.getStaffId())) {
StaffDO staffDO = staffMap.get(vo.getStaffId());
vo.setStaffName(staffDO.getNickName());
vo.setWorkTypeId(staffDO.getWorkTypeId());
if (factoryMap.containsKey(vo.getFactoryId())) {
vo.setFactoryName(factoryMap.get(vo.getFactoryId()).getName());
}
if (factoryRecordMap.containsKey(vo.getFactoryId())) {
vo.setRecords(BeanUtils.toBean(factoryRecordMap.get(vo.getFactoryId()), AttendanceRecordVO.class));
}
}
})
.filter(vo -> staffMap.containsKey(vo.getStaffId()))
.collect(Collectors.toList());
}
}

View File

@ -92,6 +92,8 @@ public interface StaffService {
*/
List<StaffDO> getListByFactory(Long factoryId, Boolean isIn);
List<StaffDO> getListByFactory(Long factoryId, Boolean isIn, List<Integer> workTypeIds);
/**
* 获取指定厂区得员工列表
*

View File

@ -250,10 +250,16 @@ public class StaffServiceImpl implements StaffService {
@Override
public List<StaffDO> getListByFactory(Long factoryId, Boolean isIn) {
return this.getListByFactory(factoryId, isIn, null);
}
@Override
public List<StaffDO> getListByFactory(Long factoryId, Boolean isIn, List<Integer> workTypeIds) {
return staffMapper.selectList(new LambdaQueryWrapperX<StaffDO>()
.eq(isIn, StaffDO::getFactoryId, factoryId)
.ne(!isIn, StaffDO::getFactoryId, factoryId)
.ne(StaffDO::getStatus, 0));
.ne(StaffDO::getStatus, 0)
.in(CollUtil.isNotEmpty(workTypeIds), StaffDO::getWorkTypeId, workTypeIds));
}
@Override

View File

@ -111,7 +111,7 @@ public class StaffSalaryServiceImpl implements StaffSalaryService {
if (pageReqVO.getMonth() != null && pageReqVO.getStatus() == null) {
return staffMapper.selectSalaryPage(pageReqVO);
}else {
} else {
return staffSalaryMapper.selectSalaryPage(pageReqVO);
}
}
@ -154,7 +154,7 @@ public class StaffSalaryServiceImpl implements StaffSalaryService {
firstDayOfMonth.minusMonths(1).withDayOfMonth(26),
firstDayOfMonth.withDayOfMonth(25)
};
}else if (type == 2) {
} else if (type == 2) {
date = new LocalDate[]{
firstDayOfMonth,
@ -213,10 +213,12 @@ public class StaffSalaryServiceImpl implements StaffSalaryService {
// 设置扣款明细 默认扣除保险 50元
salaryDO.setDeductionItems(Collections.singletonList(
new DeductionItemsVO()
.setKey("insurance")
.setValue("50")
));
new DeductionItemsVO()
.setKey("insurance")
.setValue("50")
));
// 设置扣款金额
salaryDO.setDeductionAmount(BigDecimal.valueOf(50));
// 计算应发工资
BigDecimal salary = staffDO.getSalary();
@ -226,14 +228,14 @@ public class StaffSalaryServiceImpl implements StaffSalaryService {
// 设置应发工资
salaryDO.setPayableAmount(salary);
// 设置实发工资
salaryDO.setRealAmount(salary.subtract(BigDecimal.valueOf(50)));
salaryDO.setRealAmount(salary.subtract(salaryDO.getDeductionAmount()));
} else {
BigDecimal payableAmount = salary.divide(BigDecimal.valueOf(workDays), 0, RoundingMode.DOWN)
.multiply(BigDecimal.valueOf(salaryDO.getAttendanceDays()));
// 设置应发工资
salaryDO.setPayableAmount(payableAmount);
// 设置实发工资
salaryDO.setRealAmount(payableAmount.subtract(BigDecimal.valueOf(50)));
salaryDO.setRealAmount(payableAmount.subtract(salaryDO.getDeductionAmount()));
}
// 设置薪资主体数据
@ -262,9 +264,10 @@ public class StaffSalaryServiceImpl implements StaffSalaryService {
.setId(id)
.setIsGrant(isGrant))
.collect(Collectors.toList());
// 更新
staffSalaryMapper.updateBatch(salaryDOS);
if (CollUtil.isNotEmpty(salaryDOS)) {
// 更新
staffSalaryMapper.updateBatch(salaryDOS);
}
}
@Override
@ -300,4 +303,4 @@ public class StaffSalaryServiceImpl implements StaffSalaryService {
return salaryTotalVO;
}
}
}