feat(oa): 新增车间报表汇总功能
- 在OaProjectScheduleDelayMapper.xml中增加关联项目表的查询字段 - 扩展OaProjectScheduleDelayVo实体类以支持更多项目相关信息展示 - 创建新的服务接口IOaWorkshopReportService及其实现类OaWorkshopReportServiceImpl - 实现发货单和工艺卡数据的综合统计逻辑 - 添加用于导出车间报表汇总信息的控制器OaWorkshopReportController - 提供按时间段筛选的数据统计与Excel导出功能 - 增加OaWorkshopReportSummaryVo视图对象来封装报表统计数据
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
package com.ruoyi.oa.service;
|
||||
|
||||
import com.ruoyi.oa.domain.vo.dashboard.OaWorkshopReportSummaryVo;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface IOaWorkshopReportService {
|
||||
OaWorkshopReportSummaryVo summary(Date startTime, Date endTime);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.ruoyi.oa.service.impl.dashboard;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ruoyi.oa.domain.OaDeliveryOrder;
|
||||
import com.ruoyi.oa.domain.OaDeliveryOrderDetail;
|
||||
import com.ruoyi.oa.domain.OaProcessCard;
|
||||
import com.ruoyi.oa.domain.OaProcessCardDetail;
|
||||
import com.ruoyi.oa.domain.vo.dashboard.OaWorkshopReportSummaryVo;
|
||||
import com.ruoyi.oa.mapper.OaDeliveryOrderDetailMapper;
|
||||
import com.ruoyi.oa.mapper.OaDeliveryOrderMapper;
|
||||
import com.ruoyi.oa.mapper.OaProcessCardDetailMapper;
|
||||
import com.ruoyi.oa.mapper.OaProcessCardMapper;
|
||||
import com.ruoyi.oa.service.IOaWorkshopReportService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class OaWorkshopReportServiceImpl implements IOaWorkshopReportService {
|
||||
|
||||
private final OaDeliveryOrderMapper deliveryOrderMapper;
|
||||
private final OaDeliveryOrderDetailMapper deliveryOrderDetailMapper;
|
||||
private final OaProcessCardMapper processCardMapper;
|
||||
private final OaProcessCardDetailMapper processCardDetailMapper;
|
||||
|
||||
@Override
|
||||
public OaWorkshopReportSummaryVo summary(Date startTime, Date endTime) {
|
||||
OaWorkshopReportSummaryVo vo = new OaWorkshopReportSummaryVo();
|
||||
|
||||
// 1) 发货单全局统计(按创建时间可选过滤)
|
||||
LambdaQueryWrapper<OaDeliveryOrder> orderWrap = Wrappers.lambdaQuery();
|
||||
orderWrap.eq(OaDeliveryOrder::getDelFlag, 0);
|
||||
if (startTime != null) {
|
||||
orderWrap.ge(OaDeliveryOrder::getCreateTime, startTime);
|
||||
}
|
||||
if (endTime != null) {
|
||||
orderWrap.le(OaDeliveryOrder::getCreateTime, endTime);
|
||||
}
|
||||
List<OaDeliveryOrder> orders = deliveryOrderMapper.selectList(orderWrap);
|
||||
vo.setDeliveryOrderCount(orders.size());
|
||||
Set<Long> projFromOrders = orders.stream()
|
||||
.map(OaDeliveryOrder::getProjectId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
List<Long> orderIds = orders.stream().map(OaDeliveryOrder::getOrderId).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(orderIds)) {
|
||||
LambdaQueryWrapper<OaDeliveryOrderDetail> dWrap = Wrappers.lambdaQuery();
|
||||
dWrap.in(OaDeliveryOrderDetail::getOrderId, orderIds).eq(OaDeliveryOrderDetail::getDelFlag, 0);
|
||||
List<OaDeliveryOrderDetail> details = deliveryOrderDetailMapper.selectList(dWrap);
|
||||
vo.setDeliveryDetailCount(details.size());
|
||||
|
||||
BigDecimal qty = details.stream()
|
||||
.map(d -> d.getQuantity() == null ? BigDecimal.ZERO : new BigDecimal(d.getQuantity()))
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
BigDecimal net = details.stream()
|
||||
.map(d -> d.getNetWeight() != null ? d.getNetWeight() : BigDecimal.ZERO)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
BigDecimal gross = details.stream()
|
||||
.map(d -> d.getGrossWeight() != null ? d.getGrossWeight() : BigDecimal.ZERO)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
BigDecimal vol = details.stream()
|
||||
.map(d -> d.getVolume() != null ? d.getVolume() : BigDecimal.ZERO)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
vo.setTotalQuantity(qty);
|
||||
vo.setTotalNetWeight(net);
|
||||
vo.setTotalGrossWeight(gross);
|
||||
vo.setTotalVolume(vol);
|
||||
Set<String> equipKinds = details.stream().map(OaDeliveryOrderDetail::getEquipmentName).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
Set<String> modelKinds = details.stream().map(OaDeliveryOrderDetail::getModelSpec).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
vo.setEquipmentKinds(equipKinds.size());
|
||||
vo.setModelKinds(modelKinds.size());
|
||||
} else {
|
||||
vo.setDeliveryDetailCount(0);
|
||||
vo.setTotalQuantity(BigDecimal.ZERO);
|
||||
vo.setTotalNetWeight(BigDecimal.ZERO);
|
||||
vo.setTotalGrossWeight(BigDecimal.ZERO);
|
||||
vo.setTotalVolume(BigDecimal.ZERO);
|
||||
vo.setEquipmentKinds(0);
|
||||
vo.setModelKinds(0);
|
||||
}
|
||||
|
||||
// 2) 工艺卡全局统计(可选创建时间过滤,明细可选工序时间过滤)
|
||||
LambdaQueryWrapper<OaProcessCard> cardWrap = Wrappers.lambdaQuery();
|
||||
cardWrap.eq(OaProcessCard::getDelFlag, 0);
|
||||
if (startTime != null) {
|
||||
cardWrap.ge(OaProcessCard::getCreateTime, startTime);
|
||||
}
|
||||
if (endTime != null) {
|
||||
cardWrap.le(OaProcessCard::getCreateTime, endTime);
|
||||
}
|
||||
List<OaProcessCard> cards = processCardMapper.selectList(cardWrap);
|
||||
vo.setProcessCardCount(cards.size());
|
||||
Set<Long> projFromCards = cards.stream().map(OaProcessCard::getProjectId).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
|
||||
List<Long> cardIds = cards.stream().map(OaProcessCard::getCardId).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(cardIds)) {
|
||||
LambdaQueryWrapper<OaProcessCardDetail> cdWrap = Wrappers.lambdaQuery();
|
||||
cdWrap.in(OaProcessCardDetail::getCardId, cardIds).eq(OaProcessCardDetail::getDelFlag, 0);
|
||||
if (startTime != null) {
|
||||
cdWrap.ge(OaProcessCardDetail::getProcessStartTime, startTime);
|
||||
}
|
||||
if (endTime != null) {
|
||||
cdWrap.le(OaProcessCardDetail::getProcessEndTime, endTime);
|
||||
}
|
||||
List<OaProcessCardDetail> cardDetails = processCardDetailMapper.selectList(cdWrap);
|
||||
vo.setProcessCardDetailCount(cardDetails.size());
|
||||
|
||||
List<BigDecimal> hoursList = cardDetails.stream()
|
||||
.filter(d -> d.getProcessStartTime() != null && d.getProcessEndTime() != null)
|
||||
.map(d -> {
|
||||
long minutes = Math.max(0, Duration.between(d.getProcessStartTime().toInstant(), d.getProcessEndTime().toInstant()).toMinutes());
|
||||
return new BigDecimal(minutes).divide(new BigDecimal(60), 2, java.math.RoundingMode.HALF_UP);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
vo.setProcessWithTimeCount(hoursList.size());
|
||||
BigDecimal totalHours = hoursList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
vo.setTotalWorkHours(totalHours);
|
||||
if (!hoursList.isEmpty()) {
|
||||
vo.setAvgWorkHours(totalHours.divide(new BigDecimal(hoursList.size()), 2, java.math.RoundingMode.HALF_UP));
|
||||
vo.setMinWorkHours(hoursList.stream().min(Comparator.naturalOrder()).orElse(BigDecimal.ZERO));
|
||||
vo.setMaxWorkHours(hoursList.stream().max(Comparator.naturalOrder()).orElse(BigDecimal.ZERO));
|
||||
} else {
|
||||
vo.setAvgWorkHours(BigDecimal.ZERO);
|
||||
vo.setMinWorkHours(BigDecimal.ZERO);
|
||||
vo.setMaxWorkHours(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
Set<String> manufacturingLeaders = cards.stream()
|
||||
.map(OaProcessCard::getManufacturingLeader)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toCollection(java.util.LinkedHashSet::new));
|
||||
Set<String> operationLeaders = cards.stream()
|
||||
.map(OaProcessCard::getOperationLeader)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toCollection(java.util.LinkedHashSet::new));
|
||||
vo.setManufacturingLeaders(new java.util.ArrayList<>(manufacturingLeaders));
|
||||
vo.setOperationLeaders(new java.util.ArrayList<>(operationLeaders));
|
||||
} else {
|
||||
vo.setProcessCardDetailCount(0);
|
||||
vo.setAvgWorkHours(BigDecimal.ZERO);
|
||||
vo.setTotalWorkHours(BigDecimal.ZERO);
|
||||
vo.setMinWorkHours(BigDecimal.ZERO);
|
||||
vo.setMaxWorkHours(BigDecimal.ZERO);
|
||||
vo.setProcessWithTimeCount(0);
|
||||
vo.setManufacturingLeaders(java.util.Collections.emptyList());
|
||||
vo.setOperationLeaders(java.util.Collections.emptyList());
|
||||
}
|
||||
|
||||
// 3) 涉及项目数(发货+工艺卡并集)
|
||||
Set<Long> involvedProjects = new HashSet<>();
|
||||
involvedProjects.addAll(projFromOrders);
|
||||
involvedProjects.addAll(projFromCards);
|
||||
vo.setInvolvedProjectCount(involvedProjects.size());
|
||||
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user