package cn.iocoder.yudao.module.mes.service.pro.worktime;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.worktime.vo.MesProWorktimeReportReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.worktime.vo.MesProWorktimeReportRespVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
|
import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
|
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.ArrayList;
|
import java.util.Comparator;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_WORKTIME_REPORT_DIM_INVALID;
|
|
/**
|
* MES 工时考核报表 Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesProWorktimeReportServiceImpl implements MesProWorktimeReportService {
|
|
private static final BigDecimal HUNDRED = BigDecimal.valueOf(100);
|
|
@Resource
|
private MesProFeedbackMapper feedbackMapper;
|
@Resource
|
private MesProProcessService processService;
|
@Resource
|
private MesMdWorkstationService workstationService;
|
@Resource
|
private AdminUserApi adminUserApi;
|
|
@Override
|
public MesProWorktimeReportRespVO getReport(MesProWorktimeReportReqVO reqVO) {
|
Integer dimType = reqVO.getDimType();
|
if (dimType == null || dimType < 1 || dimType > 4) {
|
throw exception(PRO_WORKTIME_REPORT_DIM_INVALID, dimType);
|
}
|
List<MesProFeedbackDO> list = feedbackMapper.selectWorktimeReportList(reqVO.getBeginTime(), reqVO.getEndTime(),
|
reqVO.getFeedbackUserId(), reqVO.getProcessId(), reqVO.getWorkstationId());
|
|
// 1. 按维度分组累加
|
Map<String, Accumulator> accumulatorMap = new LinkedHashMap<>();
|
for (MesProFeedbackDO feedback : list) {
|
String key = buildDimKey(feedback, dimType);
|
accumulatorMap.computeIfAbsent(key, k -> new Accumulator()).add(feedback);
|
}
|
|
// 2. 解析维度名称
|
Map<String, String> nameMap = buildDimNameMap(accumulatorMap.keySet(), dimType);
|
|
// 3. 输出行 + 合计
|
MesProWorktimeReportRespVO resp = new MesProWorktimeReportRespVO();
|
Accumulator total = new Accumulator();
|
list.forEach(total::add);
|
List<MesProWorktimeReportRespVO.Row> rows = new ArrayList<>();
|
accumulatorMap.forEach((key, accumulator) -> {
|
MesProWorktimeReportRespVO.Row row = accumulator.toRow(key);
|
row.setDimName(nameMap.getOrDefault(key, key));
|
rows.add(row);
|
});
|
rows.sort(buildComparator(dimType));
|
resp.setRows(rows);
|
resp.setSummary(total.toRow("ALL"));
|
resp.getSummary().setDimName("合计");
|
return resp;
|
}
|
|
private static String buildDimKey(MesProFeedbackDO feedback, int dimType) {
|
return switch (dimType) {
|
case 1 -> String.valueOf(feedback.getFeedbackUserId());
|
case 2 -> String.valueOf(feedback.getProcessId());
|
case 3 -> feedback.getWorkstationId() == null ? "0" : String.valueOf(feedback.getWorkstationId());
|
default -> feedback.getFeedbackTime() == null ? "" : feedback.getFeedbackTime().toLocalDate().toString();
|
};
|
}
|
|
private Map<String, String> buildDimNameMap(java.util.Set<String> keys, int dimType) {
|
Map<String, String> nameMap = new LinkedHashMap<>();
|
if (CollUtil.isEmpty(keys)) {
|
return nameMap;
|
}
|
switch (dimType) {
|
case 1 -> {
|
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
keys.stream().map(Long::valueOf).toList());
|
keys.forEach(key -> nameMap.put(key,
|
userMap.containsKey(Long.valueOf(key)) ? userMap.get(Long.valueOf(key)).getNickname() : "ID=" + key));
|
}
|
case 2 -> {
|
Map<Long, MesProProcessDO> processMap = processService.getProcessMap(
|
keys.stream().map(Long::valueOf).toList());
|
keys.forEach(key -> nameMap.put(key,
|
processMap.containsKey(Long.valueOf(key)) ? processMap.get(Long.valueOf(key)).getName() : "ID=" + key));
|
}
|
case 3 -> {
|
List<Long> workstationIds = keys.stream().filter(key -> !"0".equals(key)).map(Long::valueOf).toList();
|
Map<Long, MesMdWorkstationDO> workstationMap = workstationService.getWorkstationMap(workstationIds);
|
keys.forEach(key -> {
|
if ("0".equals(key)) {
|
nameMap.put(key, "未指定机台");
|
} else {
|
nameMap.put(key, workstationMap.containsKey(Long.valueOf(key))
|
? workstationMap.get(Long.valueOf(key)).getName() : "ID=" + key);
|
}
|
});
|
}
|
default -> keys.forEach(key -> nameMap.put(key, key));
|
}
|
return nameMap;
|
}
|
|
private static Comparator<MesProWorktimeReportRespVO.Row> buildComparator(int dimType) {
|
if (dimType == 4) {
|
return Comparator.comparing(MesProWorktimeReportRespVO.Row::getDimKey);
|
}
|
return Comparator.comparing(row -> {
|
try {
|
return Long.parseLong(row.getDimKey());
|
} catch (NumberFormatException ignored) {
|
return Long.MAX_VALUE;
|
}
|
});
|
}
|
|
private static class Accumulator {
|
|
private long count;
|
private BigDecimal productionLength = BigDecimal.ZERO;
|
private BigDecimal actualHours = BigDecimal.ZERO;
|
private BigDecimal standardHours = BigDecimal.ZERO;
|
private BigDecimal wageAmount = BigDecimal.ZERO;
|
|
void add(MesProFeedbackDO feedback) {
|
count++;
|
productionLength = productionLength.add(nvl(feedback.getProductionLength()));
|
actualHours = actualHours.add(nvl(feedback.getWorkHours()));
|
standardHours = standardHours.add(nvl(feedback.getStandardWorkHours()));
|
wageAmount = wageAmount.add(nvl(feedback.getWageAmount()));
|
}
|
|
MesProWorktimeReportRespVO.Row toRow(String key) {
|
MesProWorktimeReportRespVO.Row row = new MesProWorktimeReportRespVO.Row();
|
row.setDimKey(key);
|
row.setFeedbackCount(count);
|
row.setProductionLength(productionLength.setScale(2, RoundingMode.HALF_UP));
|
row.setActualHours(actualHours.setScale(2, RoundingMode.HALF_UP));
|
row.setStandardHours(standardHours.setScale(2, RoundingMode.HALF_UP));
|
BigDecimal diff = actualHours.subtract(standardHours).setScale(2, RoundingMode.HALF_UP);
|
row.setWorkHoursDiff(diff);
|
row.setWorkHoursDiffRate(standardHours.signum() > 0
|
? diff.multiply(HUNDRED).divide(standardHours, 2, RoundingMode.HALF_UP) : null);
|
row.setWageAmount(wageAmount.setScale(2, RoundingMode.HALF_UP));
|
return row;
|
}
|
|
private static BigDecimal nvl(BigDecimal value) {
|
return value != null ? value : BigDecimal.ZERO;
|
}
|
|
}
|
|
}
|