From 940ceef4c4adf20c0b9da9270f1cd5ed58e14a4c Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期一, 02 二月 2026 15:22:21 +0800
Subject: [PATCH] feat: 进销质量类分析大屏接口
---
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java | 1706 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 1,609 insertions(+), 97 deletions(-)
diff --git a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
index b66def3..7e96c10 100644
--- a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
+++ b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -2,8 +2,11 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.mapper.AccountIncomeMapper;
+import com.ruoyi.account.pojo.AccountExpense;
+import com.ruoyi.home.mapper.HomeMapper;
+import com.ruoyi.account.mapper.AccountExpenseMapper;
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.basic.mapper.CustomerMapper;
@@ -12,12 +15,12 @@
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.Product;
-import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.collaborativeApproval.mapper.NoticeMapper;
import com.ruoyi.collaborativeApproval.pojo.Notice;
import com.ruoyi.common.enums.ApproveTypeEnum;
import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.device.mapper.DeviceRepairMapper;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.dto.MapDto;
@@ -31,6 +34,9 @@
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.mapper.ProductWorkOrderMapper;
+import com.ruoyi.production.mapper.ProductionProductInputMapper;
+import com.ruoyi.production.mapper.ProductionProductOutputMapper;
+import com.ruoyi.production.mapper.SalesLedgerProductionAccountingMapper;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
@@ -43,7 +49,9 @@
import com.ruoyi.purchase.pojo.PaymentRegistration;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
+import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
import com.ruoyi.quality.pojo.QualityInspect;
+import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
@@ -86,7 +94,7 @@
private SalesLedgerProductMapper salesLedgerProductMapper;
@Autowired
- private ProcurementRecordMapper procurementRecordStorageMapper;
+ private StockInventoryMapper stockInventoryMapper;
@Autowired
private QualityInspectMapper qualityStatisticsMapper;
@@ -105,28 +113,36 @@
@Autowired
private NoticeMapper noticeMapper;
+
@Autowired
private ProductOrderMapper productOrderMapper;
+
@Autowired
private ProductWorkOrderMapper productWorkOrderMapper;
- @Autowired
- private ProductModelMapper productModelMapper;
+
@Autowired
private ProductMapper productMapper;
- @Autowired
- private StockUtils stockUtils;
+
@Autowired
private StaffOnJobMapper staffOnJobMapper;
+
@Autowired
private CustomerMapper customerMapper;
+
@Autowired
private SupplierManageMapper supplierManageMapper;
+
@Autowired
- private SysUserMapper sysUserMapper;
+ private HomeMapper homeMapper;
+
@Autowired
- private SysUserDeptMapper sysUserDeptMapper;
+ private ProductionProductOutputMapper productionProductOutputMapper;
+
@Autowired
- private StockInventoryMapper stockInventoryMapper;
+ private QualityInspectMapper qualityInspectMapper;
+
+ @Autowired
+ private QualityUnqualifiedMapper qualityUnqualifiedMapper;
@Override
public HomeBusinessDto business() {
@@ -136,7 +152,7 @@
YearMonth currentMonth = YearMonth.from(now);
// 鍒涘缓LambdaQueryWrapper
LambdaQueryWrapper<SalesLedger> salesLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
- salesLedgerLambdaQueryWrapper.ge(SalesLedger::getEntryDate, currentMonth.atDay(1).atStartOfDay()) // 澶т簬绛変簬鏈湀绗竴澶�
+ salesLedgerLambdaQueryWrapper.ge(SalesLedger::getEntryDate, currentMonth.atDay(1).atStartOfDay()) // 澶т簬绛変簬鏈湀绗竴澶�
.lt(SalesLedger::getEntryDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 灏忎簬涓嬫湀绗竴澶�
List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(salesLedgerLambdaQueryWrapper);
if (!CollectionUtils.isEmpty(salesLedgers)) {
@@ -146,8 +162,10 @@
.reduce(BigDecimal.ZERO, BigDecimal::add);
LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductMapperLambdaQueryWrapper = new LambdaQueryWrapper<SalesLedgerProduct>();
salesLedgerProductMapperLambdaQueryWrapper.eq(SalesLedgerProduct::getType, 1)
- .in(SalesLedgerProduct::getSalesLedgerId, salesLedgers.stream().map(SalesLedger::getId).collect(Collectors.toList()));
- List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(salesLedgerProductMapperLambdaQueryWrapper);
+ .in(SalesLedgerProduct::getSalesLedgerId,
+ salesLedgers.stream().map(SalesLedger::getId).collect(Collectors.toList()));
+ List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper
+ .selectList(salesLedgerProductMapperLambdaQueryWrapper);
// 鏈紑绁ㄩ噾棰�
BigDecimal noInvoiceAmountTotal = salesLedgerProducts.stream().map(SalesLedgerProduct::getNoInvoiceAmount)
.filter(Objects::nonNull)
@@ -157,15 +175,17 @@
}
// 鍒涘缓LambdaQueryWrapper
LambdaQueryWrapper<PurchaseLedger> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.ge(PurchaseLedger::getEntryDate, currentMonth.atDay(1).atStartOfDay()) // 澶т簬绛変簬鏈湀绗竴澶�
+ queryWrapper.ge(PurchaseLedger::getEntryDate, currentMonth.atDay(1).atStartOfDay()) // 澶т簬绛変簬鏈湀绗竴澶�
.lt(PurchaseLedger::getEntryDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // 灏忎簬涓嬫湀绗竴澶�
// 鎵ц鏌ヨ骞惰绠楁�诲拰
List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(queryWrapper);
if (!CollectionUtils.isEmpty(purchaseLedgers)) {
LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductMapperLambdaQueryWrapperCopy = new LambdaQueryWrapper<SalesLedgerProduct>();
salesLedgerProductMapperLambdaQueryWrapperCopy.eq(SalesLedgerProduct::getType, 2)
- .in(SalesLedgerProduct::getSalesLedgerId, purchaseLedgers.stream().map(PurchaseLedger::getId).collect(Collectors.toList()));
- List<SalesLedgerProduct> salesLedgerProductsCopy = salesLedgerProductMapper.selectList(salesLedgerProductMapperLambdaQueryWrapperCopy);
+ .in(SalesLedgerProduct::getSalesLedgerId,
+ purchaseLedgers.stream().map(PurchaseLedger::getId).collect(Collectors.toList()));
+ List<SalesLedgerProduct> salesLedgerProductsCopy = salesLedgerProductMapper
+ .selectList(salesLedgerProductMapperLambdaQueryWrapperCopy);
// 鍚堣鍚堝悓閲戦
BigDecimal receiveAmount = purchaseLedgers.stream()
.map(PurchaseLedger::getContractAmount)
@@ -177,12 +197,12 @@
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
homeBusinessDto.setMonthPurchaseMoney(receiveAmount.setScale(2, RoundingMode.HALF_UP).toString());
- homeBusinessDto.setMonthPurchaseHaveMoney(unReceiptPaymentAmount.setScale(2, RoundingMode.HALF_UP).toString());
+ homeBusinessDto
+ .setMonthPurchaseHaveMoney(unReceiptPaymentAmount.setScale(2, RoundingMode.HALF_UP).toString());
}
// 缁熻搴撳瓨
BigDecimal stockQuantityTotal = stockInventoryMapper.selectTotal();
homeBusinessDto.setInventoryNum(stockQuantityTotal.setScale(2, RoundingMode.HALF_UP).toString());
-
// 鑾峰彇褰撳ぉ鍏ュ簱鏁伴噺
BigDecimal bigDecimal = stockInventoryMapper.selectTotalByDate(LocalDate.now());
@@ -207,7 +227,7 @@
// 鑾峰彇鏈懆鍛ㄦ棩
LocalDate endOfWeek = today.with(DayOfWeek.SUNDAY);
List<SalesLedger> salesLedgers1 = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
- .ge(SalesLedger::getEntryDate, startOfWeek) // 澶т簬绛変簬鏈懆鍛ㄤ竴
+ .ge(SalesLedger::getEntryDate, startOfWeek) // 澶т簬绛変簬鏈懆鍛ㄤ竴
.lt(SalesLedger::getEntryDate, endOfWeek.plusDays(1))); // 淇敼锛氫娇鐢� lt 骞跺姞涓婁竴澶╂潵鍖呭惈鍛ㄦ棩
BigDecimal weekContractAmount = salesLedgers1.stream().map(SalesLedger::getContractAmount)
.filter(Objects::nonNull)
@@ -216,7 +236,7 @@
LocalDate lastYearStartOfWeek = today.minusYears(1).with(DayOfWeek.MONDAY);
LocalDate lastYearEndOfWeek = today.minusYears(1).with(DayOfWeek.SUNDAY);
List<SalesLedger> salesLedgers2 = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
- .ge(SalesLedger::getEntryDate, lastYearStartOfWeek) // 澶т簬绛変簬鍘诲勾鏈懆鍛ㄤ竴
+ .ge(SalesLedger::getEntryDate, lastYearStartOfWeek) // 澶т簬绛変簬鍘诲勾鏈懆鍛ㄤ竴
.lt(SalesLedger::getEntryDate, lastYearEndOfWeek.plusDays(1))); // 淇敼锛氫娇鐢� lt 骞跺姞涓婁竴澶╂潵鍖呭惈鍛ㄦ棩
BigDecimal lastYearWeekContractAmount = salesLedgers2.stream().map(SalesLedger::getContractAmount)
.filter(Objects::nonNull)
@@ -227,7 +247,8 @@
if (subtract.compareTo(BigDecimal.ZERO) == 0 || lastYearWeekContractAmount.compareTo(BigDecimal.ZERO) == 0) {
weekYny = "0.00";
} else {
- weekYny = String.format("%.2f", subtract.divide(lastYearWeekContractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
+ weekYny = String.format("%.2f", subtract.divide(lastYearWeekContractAmount, 2, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100")));
}
@@ -235,26 +256,29 @@
LocalDate yesterday = today.minusDays(1);
LocalDate plusDays = today.plusDays(1);
List<SalesLedger> salesLedgers3 = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
- .ge(SalesLedger::getEntryDate, today) // 澶т簬绛変簬浠婂ぉ
+ .ge(SalesLedger::getEntryDate, today) // 澶т簬绛変簬浠婂ぉ
.lt(SalesLedger::getEntryDate, plusDays)); // 淇敼锛氫娇鐢� lt 骞跺姞涓婁竴澶╂潵鍖呭惈褰撳ぉ
BigDecimal todayContractAmount = salesLedgers3.stream().map(SalesLedger::getContractAmount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
List<SalesLedger> salesLedgers4 = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
- .ge(SalesLedger::getEntryDate, yesterday) // 澶т簬绛変簬鏄ㄥぉ
+ .ge(SalesLedger::getEntryDate, yesterday) // 澶т簬绛変簬鏄ㄥぉ
.lt(SalesLedger::getEntryDate, today)); // 淇敼锛氫娇鐢� lt 鑰屼笉鏄� gt
BigDecimal lastYearYesterdayContractAmount = salesLedgers4.stream().map(SalesLedger::getContractAmount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
- BigDecimal subtract1 = todayContractAmount.subtract(lastYearYesterdayContractAmount); // 淇敼锛氫娇鐢� todayContractAmount 鑰屼笉鏄� yesterdayContractAmount
+ BigDecimal subtract1 = todayContractAmount.subtract(lastYearYesterdayContractAmount); // 淇敼锛氫娇鐢�
+ // todayContractAmount 鑰屼笉鏄�
+ // yesterdayContractAmount
// 鏃ョ幆姣�
String chain = "";
- if (subtract1.compareTo(BigDecimal.ZERO) == 0 || lastYearYesterdayContractAmount.compareTo(BigDecimal.ZERO) == 0) {
+ if (subtract1.compareTo(BigDecimal.ZERO) == 0
+ || lastYearYesterdayContractAmount.compareTo(BigDecimal.ZERO) == 0) {
chain = "0.00";
} else {
- chain = String.format("%.2f", subtract1.divide(lastYearYesterdayContractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
+ chain = String.format("%.2f", subtract1.divide(lastYearYesterdayContractAmount, 2, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100")));
}
-
AnalysisCustomerContractAmountsDto analysisCustomerContractAmountsDto = new AnalysisCustomerContractAmountsDto();
// 淇敼锛氬皢鍚堝悓閲戦淇濈暀涓や綅灏忔暟
@@ -262,8 +286,9 @@
analysisCustomerContractAmountsDto.setYny(weekYny);
analysisCustomerContractAmountsDto.setChain(chain);
- Map<String, BigDecimal> collect = salesLedgers.stream().collect(Collectors.groupingBy(SalesLedger::getCustomerName, Collectors.reducing(BigDecimal.ZERO,
- SalesLedger::getContractAmount, BigDecimal::add)));
+ Map<String, BigDecimal> collect = salesLedgers.stream()
+ .collect(Collectors.groupingBy(SalesLedger::getCustomerName, Collectors.reducing(BigDecimal.ZERO,
+ SalesLedger::getContractAmount, BigDecimal::add)));
List<MapDto> mapDtos = new ArrayList<>();
collect.forEach((k, v) -> {
MapDto mapDto = new MapDto();
@@ -273,14 +298,14 @@
if (contractAmount.compareTo(new BigDecimal(0)) == 0) {
mapDto.setRate("0");
} else {
- mapDto.setRate(String.format("%.2f", v.divide(contractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))));
+ mapDto.setRate(String.format("%.2f",
+ v.divide(contractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))));
}
mapDtos.add(mapDto);
});
analysisCustomerContractAmountsDto.setItem(mapDtos);
return analysisCustomerContractAmountsDto;
}
-
@Override
public QualityStatisticsDto qualityStatistics() {
@@ -371,7 +396,7 @@
approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveDelete, 0)
.eq(ApproveProcess::getApproveUserCurrentId, loginUser.getUserId())
.ne(ApproveProcess::getApproveStatus, 2);
-// .eq(ApproveProcess::getTenantId, loginUser.getTenantId());
+ // .eq(ApproveProcess::getTenantId, loginUser.getTenantId());
List<ApproveProcess> approveProcesses = approveProcessMapper.selectList(approveProcessLambdaQueryWrapper);
if (CollectionUtils.isEmpty(approveProcesses)) {
approveProcesses = new ArrayList<>();
@@ -382,24 +407,25 @@
a.setApproveTypeName(ApproveTypeEnum.getNameByCode(a.getApproveType()));
}
});
-// // 鏌ヨ鏈鐢ㄥ姵淇濊褰�
-// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
-//
-// LaborIssue laborIssue1 = new LaborIssue();
-// laborIssue1.setAdoptedDate(new Date());
-// laborIssue1.setIssueDate(sdf.parse(sdf.format(new Date())));
-// List<LaborIssue> laborIssues = lavorIssueMapper.list(laborIssue1); //staff_join_leave_record琛ㄨ鍒犻櫎
-// if(!CollectionUtils.isEmpty(laborIssues)){
-// for (LaborIssue laborIssue : laborIssues) {
-// ApproveProcess approveProcess = new ApproveProcess();
-// approveProcess.setApproveId(laborIssue.getOrderNo());
-// approveProcess.setApproveDeptName(sysDeptMapper.selectDeptById(loginUser.getTenantId()).getDeptName());
-// approveProcess.setApproveTime(laborIssue.getIssueDate());
-// approveProcess.setApproveReason(laborIssue.getDictTypeName() + "-" + laborIssue.getDictName() + "瓒呮椂鏈鍙�");
-// approveProcesses.add(approveProcess);
-// }
-// }
-
+ // // 鏌ヨ鏈鐢ㄥ姵淇濊褰�
+ // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ //
+ // LaborIssue laborIssue1 = new LaborIssue();
+ // laborIssue1.setAdoptedDate(new Date());
+ // laborIssue1.setIssueDate(sdf.parse(sdf.format(new Date())));
+ // List<LaborIssue> laborIssues = lavorIssueMapper.list(laborIssue1);
+ // //staff_join_leave_record琛ㄨ鍒犻櫎
+ // if(!CollectionUtils.isEmpty(laborIssues)){
+ // for (LaborIssue laborIssue : laborIssues) {
+ // ApproveProcess approveProcess = new ApproveProcess();
+ // approveProcess.setApproveId(laborIssue.getOrderNo());
+ // approveProcess.setApproveDeptName(sysDeptMapper.selectDeptById(loginUser.getTenantId()).getDeptName());
+ // approveProcess.setApproveTime(laborIssue.getIssueDate());
+ // approveProcess.setApproveReason(laborIssue.getDictTypeName() + "-" +
+ // laborIssue.getDictName() + "瓒呮椂鏈鍙�");
+ // approveProcesses.add(approveProcess);
+ // }
+ // }
return approveProcesses;
}
@@ -437,31 +463,41 @@
}
// 搴旀敹
List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
-// .ge(SalesLedger::getEntryDate, startDate)
-// .lt(SalesLedger::getEntryDate, endDate)
+ // .ge(SalesLedger::getEntryDate, startDate)
+ // .lt(SalesLedger::getEntryDate, endDate)
);
-// BigDecimal receivableMoney = salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+ // BigDecimal receivableMoney =
+ // salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO,
+ // BigDecimal::add);
BigDecimal receivableMoney = sumAmount(salesLedgers, SalesLedger::getContractAmount);
// 搴斾粯
- List<PurchaseLedger> procurementRecords = purchaseLedgerMapper.selectList(new LambdaQueryWrapper<PurchaseLedger>()
-// .ge(PurchaseLedger::getEntryDate, startDate)
-// .lt(PurchaseLedger::getEntryDate, endDate)
- );
-// BigDecimal payableMoney = procurementRecords.stream().map(PurchaseLedger::getContractAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+ List<PurchaseLedger> procurementRecords = purchaseLedgerMapper
+ .selectList(new LambdaQueryWrapper<PurchaseLedger>()
+ // .ge(PurchaseLedger::getEntryDate, startDate)
+ // .lt(PurchaseLedger::getEntryDate, endDate)
+ );
+ // BigDecimal payableMoney =
+ // procurementRecords.stream().map(PurchaseLedger::getContractAmount).reduce(BigDecimal.ZERO,
+ // BigDecimal::add);
BigDecimal payableMoney = sumAmount(procurementRecords, PurchaseLedger::getContractAmount);
// 棰勬敹
List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
-// .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
-// .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
+ // .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
+ // .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
);
-// BigDecimal advanceMoney = receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+ // BigDecimal advanceMoney =
+ // receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).reduce(BigDecimal.ZERO,
+ // BigDecimal::add);
BigDecimal advanceMoney = sumAmount(receiptPayments, ReceiptPayment::getReceiptPaymentAmount);
// 棰勪粯
- List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper.selectList(new LambdaQueryWrapper<PaymentRegistration>()
-// .ge(PaymentRegistration::getPaymentDate, startDate)
-// .lt(PaymentRegistration::getPaymentDate, endDate)
- );
-// BigDecimal prepayMoney = paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+ List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper
+ .selectList(new LambdaQueryWrapper<PaymentRegistration>()
+ // .ge(PaymentRegistration::getPaymentDate, startDate)
+ // .lt(PaymentRegistration::getPaymentDate, endDate)
+ );
+ // BigDecimal prepayMoney =
+ // paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO,
+ // BigDecimal::add);
BigDecimal prepayMoney = sumAmount(paymentRegistrations, PaymentRegistration::getCurrentPaymentAmount);
StatisticsReceivablePayableDto statisticsReceivablePayableDto = new StatisticsReceivablePayableDto();
statisticsReceivablePayableDto.setPayableMoney(payableMoney.subtract(prepayMoney));
@@ -494,10 +530,12 @@
Long aLong1 = deviceRepairMapper.selectCount(new LambdaQueryWrapper<DeviceRepair>()
.eq(DeviceRepair::getStatus, 0)
.eq(DeviceRepair::getRepairName, SecurityUtils.getLoginUser().getNickName()));
- return new HashMap<String, Object>() {{
- put("approveTodo", aLong);
- put("deviceRepairTodo", aLong1);
- }};
+ return new HashMap<String, Object>() {
+ {
+ put("approveTodo", aLong);
+ put("deviceRepairTodo", aLong1);
+ }
+ };
}
@Override
@@ -514,11 +552,16 @@
ProductOrderDto orderDto = new ProductOrderDto();
orderDto.setStartTime(LocalDateTime.now().minusMonths(1));
orderDto.setEndTime(LocalDateTime.now());
- List<ProductOrderDto> productOrderDtos = productOrderMapper.pageProductOrder(new Page<>(1, -1), orderDto).getRecords();
+ List<ProductOrderDto> productOrderDtos = productOrderMapper.pageProductOrder(new Page<>(1, -1), orderDto)
+ .getRecords();
productionProgressDto.setCompletedOrderDetails(productOrderDtos);
long totalCount = productOrderDtos.size();
- long count = productOrderDtos.stream().filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0).count();
- long count2 = productOrderDtos.stream().filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(BigDecimal.ZERO) == 0).count();
+ long count = productOrderDtos.stream().filter(
+ productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0)
+ .count();
+ long count2 = productOrderDtos.stream()
+ .filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(BigDecimal.ZERO) == 0)
+ .count();
productionProgressDto.setTotalOrderCount(totalCount);
productionProgressDto.setCompletedOrderCount(count);
productionProgressDto.setUncompletedOrderCount(count2);
@@ -532,29 +575,38 @@
ProductWorkOrderDto workOrder = new ProductWorkOrderDto();
workOrder.setPlanStartTime(LocalDate.now().minusMonths(1));
workOrder.setPlanEndTime(LocalDate.now());
- List<ProductWorkOrderDto> productWorkOrders = productWorkOrderMapper.pageProductWorkOrder(new Page<>(1, -1), workOrder).getRecords();
+ List<ProductWorkOrderDto> productWorkOrders = productWorkOrderMapper
+ .pageProductWorkOrder(new Page<>(1, -1), workOrder).getRecords();
long sum = productWorkOrders.stream()
- .filter(productWorkOrder -> productWorkOrder.getPlanQuantity().compareTo(productWorkOrder.getCompleteQuantity()) > 0)
+ .filter(productWorkOrder -> productWorkOrder.getPlanQuantity()
+ .compareTo(productWorkOrder.getCompleteQuantity()) > 0)
.map(ProductWorkOrder::getPlanQuantity)
.mapToLong(BigDecimal::longValue)
.sum();
- if (sum == 0) return null;
- productionTurnoverDto.setTotalOrderCount(sum);//鎬诲湪鍒跺搧鏁伴噺
- productionTurnoverDto.setAverageTurnoverDays(BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(ChronoUnit.DAYS.between(LocalDateTime.now().minusMonths(1), LocalDateTime.now())), 2, RoundingMode.HALF_UP));
+ if (sum == 0)
+ return null;
+ productionTurnoverDto.setTotalOrderCount(sum);// 鎬诲湪鍒跺搧鏁伴噺
+ productionTurnoverDto.setAverageTurnoverDays(BigDecimal.valueOf(sum).divide(
+ BigDecimal.valueOf(ChronoUnit.DAYS.between(LocalDateTime.now().minusMonths(1), LocalDateTime.now())), 2,
+ RoundingMode.HALF_UP));
long completeQuantity = productWorkOrders.stream()
- .filter(productWorkOrder -> productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) >= 0)
+ .filter(productWorkOrder -> productWorkOrder.getCompleteQuantity()
+ .compareTo(productWorkOrder.getPlanQuantity()) >= 0)
.map(ProductWorkOrder::getCompleteQuantity)
.mapToLong(BigDecimal::longValue)
.sum();
- productionTurnoverDto.setTurnoverEfficiency(BigDecimal.valueOf(completeQuantity).divide(BigDecimal.valueOf(sum), 2, RoundingMode.HALF_UP));
+ productionTurnoverDto.setTurnoverEfficiency(
+ BigDecimal.valueOf(completeQuantity).divide(BigDecimal.valueOf(sum), 2, RoundingMode.HALF_UP));
Map<String, List<ProductWorkOrderDto>> map = productWorkOrders.stream()
- .filter(productWorkOrder -> productWorkOrder.getPlanQuantity().compareTo(productWorkOrder.getCompleteQuantity()) > 0)
+ .filter(productWorkOrder -> productWorkOrder.getPlanQuantity()
+ .compareTo(productWorkOrder.getCompleteQuantity()) > 0)
.collect(Collectors.groupingBy(ProductWorkOrderDto::getProcessName));
List<String> strings = new ArrayList<>();
List<Long> processQuantityDetails = new ArrayList<>();
map.entrySet().stream().forEach(entry -> {
String key = entry.getKey();
- long completeSum = entry.getValue().stream().map(ProductWorkOrderDto::getCompleteQuantity).mapToLong(BigDecimal::longValue).sum();
+ long completeSum = entry.getValue().stream().map(ProductWorkOrderDto::getCompleteQuantity)
+ .mapToLong(BigDecimal::longValue).sum();
strings.add(key);
processQuantityDetails.add(completeSum);
});
@@ -580,9 +632,9 @@
for (SysDept dept : depts) {
if ("0".equals(dept.getStatus()) && "0".equals(dept.getDelFlag())) {
- Long count = sysUserDeptMapper.selectCount(new LambdaQueryWrapper<SysUserDept>()
- .eq(SysUserDept::getDeptId, dept.getDeptId()));
- if (count > 0) {
+ Long count = staffOnJobMapper.selectCount(new QueryWrapper<StaffOnJob>()
+ .eq("sys_dept_id", dept.getDeptId()).eq("staff_state", 1));
+ if (count != null && count > 0) {
Map<String, Object> map = new HashMap<>();
map.put("name", dept.getDeptName());
map.put("count", count);
@@ -620,19 +672,19 @@
LocalDateTime currentMonthEnd = currentMonth.atEndOfMonth().atTime(23, 59, 59);
LocalDateTime prevMonthEnd = prevMonth.atEndOfMonth().atTime(23, 59, 59);
- // 鎬诲伐浣滀汉鍛�
+ // 鎬诲伐浣滀汉鍛�
Long currentStaff = countStaff(currentMonthEnd);
Long prevStaff = countStaff(prevMonthEnd);
dto.setTotalStaff(currentStaff);
dto.setStaffGrowthRate(calculateMoM(currentStaff, prevStaff));
- // 鎬诲鎴锋暟
+ // 鎬诲鎴锋暟
Long currentCustomers = countCustomers(currentMonthEnd);
Long prevCustomers = countCustomers(prevMonthEnd);
dto.setTotalCustomer(currentCustomers);
dto.setCustomerGrowthRate(calculateMoM(currentCustomers, prevCustomers));
- // 鎬讳緵搴斿晢鏁�
+ // 鎬讳緵搴斿晢鏁�
Long currentSuppliers = countSuppliers(currentMonthEnd);
Long prevSuppliers = countSuppliers(prevMonthEnd);
dto.setTotalSupplier(currentSuppliers);
@@ -642,14 +694,12 @@
}
private Long countStaff(LocalDateTime dateTime) {
- Long sysUserCount = sysUserMapper.selectCount(new LambdaQueryWrapper<SysUser>()
- .eq(SysUser::getDelFlag, "0")
- .le(SysUser::getCreateTime, dateTime));
Long staffCountItem = staffOnJobMapper.selectCount(new LambdaQueryWrapper<StaffOnJob>()
+ .isNotNull(StaffOnJob::getStaffState)
+ .eq(StaffOnJob::getStaffState, 1)
.le(StaffOnJob::getCreateTime, dateTime));
- return sysUserCount + staffCountItem;
+ return staffCountItem;
}
-
private Long countCustomers(LocalDateTime dateTime) {
return customerMapper.selectCount(new LambdaQueryWrapper<Customer>()
@@ -704,7 +754,7 @@
queryWrapper.select("supplier_name", "SUM(contract_amount) as total_amount")
.ge("entry_date", startDate)
.le("entry_date", endDate)
-// .ne("approval_status", 3)
+ // .ne("approval_status", 3)
.groupBy("supplier_name")
.orderByDesc("total_amount")
.last("LIMIT 5");
@@ -779,7 +829,8 @@
String dayName = d.getMonthValue() + "/" + d.getDayOfMonth();
BigDecimal sum = list.stream()
.filter(l -> l.getEntryDate() != null)
- .filter(l -> l.getEntryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().equals(d))
+ .filter(l -> l.getEntryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
+ .equals(d))
.map(SalesLedger::getContractAmount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
@@ -895,9 +946,1470 @@
for (Map<String, Object> map : maps) {
CustomerContributionRankingDto rankingDto = new CustomerContributionRankingDto();
rankingDto.setCustomerName(map.get("customer_name").toString());
- rankingDto.setTotalAmount(map.get("total_amount") != null ? new BigDecimal(map.get("total_amount").toString()) : BigDecimal.ZERO);
+ rankingDto
+ .setTotalAmount(map.get("total_amount") != null ? new BigDecimal(map.get("total_amount").toString())
+ : BigDecimal.ZERO);
result.add(rankingDto);
}
return result;
}
-}
+
+ @Override
+ public List<MapDto> productSalesAnalysis() {
+ // 鑾峰彇鎵�鏈変骇鍝佸ぇ绫荤殑閿�鍞
+ List<Map<String, Object>> analysisResults = salesLedgerProductMapper.selectProductSalesAnalysis();
+ if (CollectionUtils.isEmpty(analysisResults)) {
+ return new ArrayList<>();
+ }
+
+ // 璁$畻鎬婚攢鍞
+ BigDecimal totalSalesAmount = analysisResults.stream()
+ .map(r -> (BigDecimal) r.get("value"))
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ return analysisResults.stream()
+ .map(result -> {
+ MapDto mapDto = new MapDto();
+ String name = (String) result.get("name");
+ BigDecimal value = (BigDecimal) result.get("value");
+
+ mapDto.setName(name);
+ mapDto.setValue(value != null ? value.setScale(2, RoundingMode.HALF_UP).toString() : "0.00");
+
+ if (totalSalesAmount.compareTo(BigDecimal.ZERO) == 0 || value == null) {
+ mapDto.setRate("0.00");
+ } else {
+ String rate = value.divide(totalSalesAmount, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ mapDto.setRate(rate);
+ }
+ return mapDto;
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<MapDto> rawMaterialPurchaseAmountRatio() {
+ // 鑾峰彇鎵�鏈夊師鏉愭枡鐨勯噰璐
+ List<Map<String, Object>> analysisResults = salesLedgerProductMapper.selectRawMaterialPurchaseAnalysis();
+ if (CollectionUtils.isEmpty(analysisResults)) {
+ return new ArrayList<>();
+ }
+
+ // 璁$畻鎬婚噰璐
+ BigDecimal totalPurchaseAmount = analysisResults.stream()
+ .map(r -> (BigDecimal) r.get("value"))
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ return analysisResults.stream()
+ .map(result -> {
+ MapDto mapDto = new MapDto();
+ String name = (String) result.get("name");
+ BigDecimal value = (BigDecimal) result.get("value");
+
+ mapDto.setName(name);
+ mapDto.setValue(value != null ? value.setScale(2, RoundingMode.HALF_UP).toString() : "0.00");
+
+ if (totalPurchaseAmount.compareTo(BigDecimal.ZERO) == 0 || value == null) {
+ mapDto.setRate("0.00");
+ } else {
+ String rate = value.divide(totalPurchaseAmount, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ mapDto.setRate(rate);
+ }
+ return mapDto;
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<MapDto> salesPurchaseStorageProductCount() {
+ LocalDate now = LocalDate.now();
+ DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ String currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).format(dtf);
+ String currentMonthNow = now.format(dtf);
+
+ LocalDate lastMonth = now.minusMonths(1);
+ String lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).format(dtf);
+ String lastMonthEnd = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).format(dtf);
+
+ // 閿�鍞�
+ int currentSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, currentMonthStart,
+ currentMonthNow);
+ int lastSales = salesLedgerProductMapper.selectProductCountByTypeAndDate(1, lastMonthStart, lastMonthEnd);
+
+ // 閲囪喘
+ int currentPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, currentMonthStart,
+ currentMonthNow);
+ int lastPurchase = salesLedgerProductMapper.selectProductCountByTypeAndDate(2, lastMonthStart, lastMonthEnd);
+
+ // 鍌ㄥ瓨
+ int currentStorage = stockInventoryMapper.selectStorageProductCountByDate(currentMonthStart, currentMonthNow);
+ int lastStorage = stockInventoryMapper.selectStorageProductCountByDate(lastMonthStart, lastMonthEnd);
+
+ List<MapDto> list = new ArrayList<>();
+ list.add(createMapDto("閿�鍞骇鍝佹暟", currentSales, lastSales));
+ list.add(createMapDto("閲囪喘浜у搧鏁�", currentPurchase, lastPurchase));
+ list.add(createMapDto("鍌ㄥ瓨浜у搧鏁�", currentStorage, lastStorage));
+
+ return list;
+ }
+
+ private MapDto createMapDto(String name, int current, int last) {
+ MapDto dto = new MapDto();
+ dto.setName(name);
+ dto.setValue(String.valueOf(current));
+
+ if (last == 0) {
+ dto.setRate(current > 0 ? "100.00" : "0.00");
+ } else {
+ BigDecimal curDec = new BigDecimal(current);
+ BigDecimal lastDec = new BigDecimal(last);
+ // 澧為暱鐜�
+ String rate = curDec.subtract(lastDec)
+ .divide(lastDec, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setRate(rate);
+ }
+ return dto;
+ }
+
+ @Override
+ public List<Map<String, Object>> productInOutAnalysis(Integer type) {
+ String targetName;
+ if (type == 1) {
+ targetName = "鍘熸潗鏂�";
+ } else if (type == 2) {
+ targetName = "鎴愬搧";
+ } else if (type == 3) {
+ targetName = "鍗婃垚鍝�";
+ } else {
+ return new ArrayList<>();
+ }
+
+ LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(Product::getProductName, targetName).isNull(Product::getParentId);
+ Product rootCategory = productMapper.selectOne(queryWrapper);
+
+ if (rootCategory == null) {
+ log.warn("鏈壘鍒板悕绉颁负 {} 鐨勯《绾т骇鍝佸垎绫�", targetName);
+ return new ArrayList<>();
+ }
+ Long rootCategoryId = rootCategory.getId();
+
+ LocalDate now = LocalDate.now();
+ DateTimeFormatter displayDtf = DateTimeFormatter.ofPattern("M/d");
+
+ String startDate = now.minusDays(6).toString();
+ String endDate = now.toString();
+
+ List<Map<String, Object>> inCounts = stockInventoryMapper.selectDailyStockInCounts(rootCategoryId, startDate,
+ endDate + " 23:59:59");
+
+ List<Map<String, Object>> outCounts = stockInventoryMapper.selectDailyStockOutCounts(rootCategoryId, startDate,
+ endDate + " 23:59:59");
+
+ Map<LocalDate, BigDecimal> inMap = inCounts.stream()
+ .collect(Collectors.toMap(
+ m -> ((java.sql.Date) m.get("date")).toLocalDate(),
+ m -> (BigDecimal) m.get("count"),
+ BigDecimal::add));
+
+ Map<LocalDate, BigDecimal> outMap = outCounts.stream()
+ .collect(Collectors.toMap(
+ m -> ((java.sql.Date) m.get("date")).toLocalDate(),
+ m -> (BigDecimal) m.get("count"),
+ BigDecimal::add));
+
+ List<Map<String, Object>> result = new ArrayList<>();
+
+ for (int i = 6; i >= 0; i--) {
+ LocalDate date = now.minusDays(i);
+
+ Map<String, Object> dataPoint = new LinkedHashMap<>();
+ dataPoint.put("date", date.format(displayDtf)); // 1/23
+ dataPoint.put("inCount", inMap.getOrDefault(date, BigDecimal.ZERO));
+ dataPoint.put("outCount", outMap.getOrDefault(date, BigDecimal.ZERO));
+
+ result.add(dataPoint);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<MapDto> productTurnoverDays() {
+ return homeMapper.productTurnoverDays();
+ }
+
+ @Autowired
+ private AccountExpenseMapper accountExpenseMapper;
+
+ @Autowired
+ private AccountIncomeMapper accountIncomeMapper;
+
+ public List<Map<String, Object>> incomeExpenseAnalysis(Integer type) {
+
+ LocalDate today = LocalDate.now();
+ LocalDate startDate;
+ LocalDate endDate;
+ String dateFormat;
+ DateTimeFormatter formatter;
+ List<String> xAxis = new ArrayList<>();
+
+ // 1. 鏃堕棿鑼冨洿 & X 杞�
+ if (type == 3) {
+ // 鏈搴︼紙鎸夋湀锛�
+ Month currentMonth = today.getMonth();
+ Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter();
+ startDate = today.withMonth(firstMonthOfQuarter.getValue())
+ .with(TemporalAdjusters.firstDayOfMonth());
+ endDate = startDate.plusMonths(2)
+ .with(TemporalAdjusters.lastDayOfMonth());
+
+ dateFormat = "%Y-%m";
+ formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+ LocalDate tmp = startDate;
+ while (!tmp.isAfter(endDate)) {
+ xAxis.add(tmp.format(formatter));
+ tmp = tmp.plusMonths(1);
+ }
+
+ } else {
+ // 鍛� / 鏈堬紙鎸夊ぉ锛�
+ dateFormat = "%Y-%m-%d";
+ formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ if (type == 1) {
+ startDate = today.with(DayOfWeek.MONDAY);
+ endDate = today.with(DayOfWeek.SUNDAY);
+ } else {
+ startDate = today.with(TemporalAdjusters.firstDayOfMonth());
+ endDate = today.with(TemporalAdjusters.lastDayOfMonth());
+ }
+
+ LocalDate tmp = startDate;
+ while (!tmp.isAfter(endDate)) {
+ xAxis.add(tmp.format(formatter));
+ tmp = tmp.plusDays(1);
+ }
+ }
+
+ String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+
+ // 2. 鏌ヨ鏁版嵁
+ List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
+
+ // List<IncomeExpenseAnalysisDto> purchaseList =
+ // purchaseLedgerMapper.selectPurchaseStats(startStr, endStr, dateFormat);
+
+ List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr,
+ dateFormat);
+
+ // 3. 杞� Map锛堣嚜鍔ㄥ悎骞讹級
+ Map<String, BigDecimal> incomeMap = incomeList.stream()
+ .collect(Collectors.toMap(
+ IncomeExpenseAnalysisDto::getDateStr,
+ IncomeExpenseAnalysisDto::getAmount,
+ BigDecimal::add));
+
+ // Map<String, BigDecimal> purchaseMap = purchaseList.stream()
+ // .collect(Collectors.toMap(
+ // IncomeExpenseAnalysisDto::getDateStr,
+ // IncomeExpenseAnalysisDto::getAmount,
+ // BigDecimal::add));
+
+ Map<String, BigDecimal> expenseMap = expenseList.stream()
+ .collect(Collectors.toMap(
+ IncomeExpenseAnalysisDto::getDateStr,
+ IncomeExpenseAnalysisDto::getAmount,
+ BigDecimal::add));
+
+ // 4. 缁勮杩斿洖
+ List<Map<String, Object>> result = new ArrayList<>();
+
+ for (String dateStr : xAxis) {
+ Map<String, Object> item = new HashMap<>();
+ item.put("date", dateStr);
+
+ // 鏀跺叆
+ BigDecimal income = incomeMap.getOrDefault(dateStr, BigDecimal.ZERO);
+ item.put("income", income.setScale(2, RoundingMode.HALF_UP));
+
+ // 鏀嚭 = 閲囪喘 + 璐㈠姟鏀嚭
+ // BigDecimal purchase = purchaseMap.getOrDefault(dateStr, BigDecimal.ZERO);
+ BigDecimal expense = expenseMap.getOrDefault(dateStr, BigDecimal.ZERO);
+ // BigDecimal totalExpense = purchase.add(expense);
+ BigDecimal totalExpense = expense;
+
+ item.put("expense", totalExpense.setScale(2, RoundingMode.HALF_UP));
+
+ result.add(item);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<MapDto> profitTrendAnalysis() {
+ LocalDate today = LocalDate.now();
+ LocalDate startDate = today.minusMonths(11).with(TemporalAdjusters.firstDayOfMonth());
+ LocalDate endDate = today.with(TemporalAdjusters.lastDayOfMonth());
+
+ String dateFormat = "%Y-%m";
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+ List<String> months = new ArrayList<>();
+ LocalDate temp = startDate;
+ while (!temp.isAfter(endDate)) {
+ months.add(temp.format(formatter));
+ temp = temp.plusMonths(1);
+ }
+
+ String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+
+ // List<IncomeExpenseAnalysisDto> incomeList =
+ // salesLedgerMapper.selectIncomeStats(startStr, endStr, dateFormat);
+ List<IncomeExpenseAnalysisDto> incomeList = new ArrayList<>();
+ List<IncomeExpenseAnalysisDto> purchaseList = purchaseLedgerMapper.selectPurchaseStats(startStr, endStr,
+ dateFormat);
+ List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr,
+ dateFormat);
+
+ Map<String, BigDecimal> incomeMap = incomeList.stream().collect(Collectors
+ .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
+ Map<String, BigDecimal> purchaseMap = purchaseList.stream().collect(Collectors
+ .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
+ Map<String, BigDecimal> expenseMap = expenseList.stream().collect(Collectors
+ .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
+
+ List<MapDto> result = new ArrayList<>();
+
+ for (String month : months) {
+ MapDto dto = new MapDto();
+ dto.setName(month);
+
+ BigDecimal income = incomeMap.getOrDefault(month, BigDecimal.ZERO);
+
+ BigDecimal purchase = purchaseMap.getOrDefault(month, BigDecimal.ZERO);
+ income = BigDecimal.ZERO;
+ BigDecimal expense = expenseMap.getOrDefault(month, BigDecimal.ZERO);
+ BigDecimal totalExpense = purchase.add(expense);
+
+ BigDecimal profit = income.subtract(totalExpense);
+
+ dto.setValue(profit.setScale(2, RoundingMode.HALF_UP).toString());
+ result.add(dto);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<MapDto> expenseCompositionAnalysis(Integer type) {
+ List<MapDto> result = new ArrayList<>();
+
+ if (type == 2) {
+ List<MapDto> customerList = salesLedgerMapper.selectCustomerSalesComposition();
+ if (customerList != null) {
+ result.addAll(customerList);
+ }
+ } else {
+ BigDecimal rawMaterialAmount = salesLedgerProductMapper.selectRawMaterialExpense();
+ MapDto rawMaterialDto = new MapDto();
+ rawMaterialDto.setName("鍘熸潗鏂�");
+ rawMaterialDto.setValue(rawMaterialAmount != null ? rawMaterialAmount.toString() : "0");
+ result.add(rawMaterialDto);
+
+ List<MapDto> expenseList = accountExpenseMapper.selectExpenseComposition(null, null);
+ if (expenseList != null) {
+ result.addAll(expenseList);
+ }
+ }
+
+ BigDecimal total = BigDecimal.ZERO;
+ for (MapDto dto : result) {
+ if (dto.getValue() != null) {
+ total = total.add(new BigDecimal(dto.getValue()));
+ }
+ }
+
+ if (total.compareTo(BigDecimal.ZERO) > 0) {
+ for (MapDto dto : result) {
+ if (dto.getValue() != null) {
+ BigDecimal val = new BigDecimal(dto.getValue());
+ String rate = val.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setRate(rate);
+ } else {
+ dto.setRate("0.00");
+ }
+ }
+ } else {
+ for (MapDto dto : result) {
+ dto.setRate("0.00");
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public MonthlyIncomeDto monthlyIncome() {
+ MonthlyIncomeDto dto = new MonthlyIncomeDto();
+ LocalDate now = LocalDate.now();
+ YearMonth currentMonth = YearMonth.from(now);
+ LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
+ LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
+
+ LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(SalesLedgerProduct::getType, 1);
+ wrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
+ wrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
+
+ List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(wrapper);
+
+ if (CollectionUtils.isEmpty(products)) {
+ return dto;
+ }
+
+ BigDecimal collected = products.stream()
+ .map(SalesLedgerProduct::getInvoiceTotal)
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ dto.setMonthlyIncome(collected);
+
+ BigDecimal overdue = products.stream()
+ .map(SalesLedgerProduct::getPendingInvoiceTotal)
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ dto.setOverdueNum(overdue);
+
+ BigDecimal total = collected.add(overdue);
+
+ if (total.compareTo(BigDecimal.ZERO) > 0) {
+ String collectionRate = collected.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setCollectionRate(collectionRate);
+
+ String overdueRate = overdue.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setOverdueRate(overdueRate);
+ }
+
+ return dto;
+ }
+
+ public MonthlyExpenditureDto monthlyExpenditure() {
+
+ MonthlyExpenditureDto dto = new MonthlyExpenditureDto();
+
+ // 褰撴湀鏃堕棿鑼冨洿
+ LocalDate now = LocalDate.now();
+ YearMonth currentMonth = YearMonth.from(now);
+ LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
+ LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
+
+ // 閲囪喘鍙拌处锛坱ype = 2锛�
+ LambdaQueryWrapper<SalesLedgerProduct> purchaseWrapper = new LambdaQueryWrapper<>();
+ purchaseWrapper.eq(SalesLedgerProduct::getType, 2);
+ purchaseWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
+ purchaseWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
+
+ List<SalesLedgerProduct> purchaseProducts = salesLedgerProductMapper.selectList(purchaseWrapper);
+
+ BigDecimal rawMaterialCost = BigDecimal.ZERO; // 鍘熸潗鏂欐垚鏈�
+ BigDecimal paidAmount = BigDecimal.ZERO; // 宸蹭粯娆鹃噾棰�
+ BigDecimal pendingAmount = BigDecimal.ZERO; // 寰呬粯娆鹃噾棰�
+
+ if (!CollectionUtils.isEmpty(purchaseProducts)) {
+ for (SalesLedgerProduct p : purchaseProducts) {
+
+ if (p.getTaxInclusiveTotalPrice() != null) {
+ rawMaterialCost = rawMaterialCost.add(p.getTaxInclusiveTotalPrice());
+ }
+
+ if (p.getTicketsTotal() != null) {
+ paidAmount = paidAmount.add(p.getTicketsTotal());
+ }
+
+ if (p.getPendingTicketsTotal() != null) {
+ pendingAmount = pendingAmount.add(p.getPendingTicketsTotal());
+ }
+ }
+ }
+
+ // 鍏朵粬璐圭敤
+ LambdaQueryWrapper<AccountExpense> expenseWrapper = new LambdaQueryWrapper<>();
+ expenseWrapper.ge(AccountExpense::getExpenseDate,
+ java.sql.Date.valueOf(currentMonth.atDay(1)));
+ expenseWrapper.le(AccountExpense::getExpenseDate,
+ java.sql.Date.valueOf(currentMonth.atEndOfMonth()));
+
+ List<AccountExpense> expenses = accountExpenseMapper.selectList(expenseWrapper);
+
+ BigDecimal otherExpense = BigDecimal.ZERO;
+ if (!CollectionUtils.isEmpty(expenses)) {
+ for (AccountExpense e : expenses) {
+ if (e.getExpenseMoney() != null) {
+ otherExpense = otherExpense.add(e.getExpenseMoney());
+ }
+ }
+ }
+
+ // 鏈堝害鎬绘敮鍑�
+ // BigDecimal monthlyExpenditure = rawMaterialCost.add(otherExpense);
+ BigDecimal monthlyExpenditure = otherExpense;
+ dto.setMonthlyExpenditure(monthlyExpenditure);
+
+ // 宸蹭粯娆� 梅锛堝凡浠樻 + 寰呬粯娆撅級
+ BigDecimal totalPayable = paidAmount.add(pendingAmount);
+ if (totalPayable.compareTo(BigDecimal.ZERO) > 0) {
+ String paymentRate = paidAmount
+ .divide(totalPayable, 4, RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+ dto.setPaymentRate(paymentRate);
+ }
+
+ // 鍞彴璐︼紙type = 1锛�
+ LambdaQueryWrapper<SalesLedgerProduct> salesWrapper = new LambdaQueryWrapper<>();
+ salesWrapper.eq(SalesLedgerProduct::getType, 1);
+ salesWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
+ salesWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
+
+ List<SalesLedgerProduct> salesProducts = salesLedgerProductMapper.selectList(salesWrapper);
+
+ BigDecimal revenue = BigDecimal.ZERO;
+ if (!CollectionUtils.isEmpty(salesProducts)) {
+ for (SalesLedgerProduct s : salesProducts) {
+ if (s.getInvoiceAmount() != null) {
+ revenue = revenue.add(s.getInvoiceAmount());
+ }
+ }
+ }
+
+ // 姣涘埄娑� & 鍒╂鼎鐜�
+ if (revenue.compareTo(BigDecimal.ZERO) > 0) {
+
+ // 姣涘埄娑� = 閿�鍞敹鍏� - 鍘熸潗鏂欐垚鏈�
+ BigDecimal grossProfit = revenue.subtract(rawMaterialCost);
+ dto.setGrossProfit(grossProfit);
+
+ // 鍒╂鼎鐜� = (閿�鍞敹鍏� - 鏈堝害鎬绘敮鍑�) / 閿�鍞敹鍏�
+ BigDecimal profit = revenue.subtract(monthlyExpenditure);
+ String profitMarginRate = profit
+ .divide(revenue, 4, RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100))
+ .setScale(2, RoundingMode.HALF_UP)
+ .toString();
+
+ dto.setProfitMarginRate(profitMarginRate);
+ }
+
+ return dto;
+ }
+
+ @Autowired
+ private ProductionProductInputMapper productionProductInputMapper;
+
+ @Override
+ public List<InputOutputAnalysisDto> inputOutputAnalysis(Integer type) {
+ LocalDate today = LocalDate.now();
+ LocalDate startDate;
+
+ switch (type) {
+ case 1: // 鍛�
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ case 2: // 鏈�
+ startDate = today.withDayOfMonth(1);
+ break;
+ case 3: // 瀛e害
+ int currentMonth = today.getMonthValue();
+ int startMonth = ((currentMonth - 1) / 3) * 3 + 1;
+ startDate = LocalDate.of(today.getYear(), startMonth, 1);
+ break;
+ default:
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ }
+
+ LocalDate endDate = today.plusDays(1);
+
+ String startStr = startDate.atStartOfDay()
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ String endStr = endDate.atStartOfDay()
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ List<Map<String, Object>> inputList = productionProductInputMapper.selectInputStats(startStr, endStr);
+ List<Map<String, Object>> outputList = productionProductOutputMapper.selectDailyOutputStats(startStr, endStr);
+
+ Map<String, InputOutputAnalysisDto> dateMap = new HashMap<>();
+
+ if (!CollectionUtils.isEmpty(inputList)) {
+ for (Map<String, Object> map : inputList) {
+ String date = (String) map.get("date");
+ if (date == null)
+ continue;
+ InputOutputAnalysisDto dto = dateMap.getOrDefault(date, new InputOutputAnalysisDto());
+ dto.setDate(date);
+ BigDecimal qty = (BigDecimal) map.get("quantity");
+ dto.setInputSum(dto.getInputSum() != null ? dto.getInputSum().add(qty) : qty);
+ dateMap.put(date, dto);
+ }
+ }
+
+ if (!CollectionUtils.isEmpty(outputList)) {
+ for (Map<String, Object> map : outputList) {
+ String date = (String) map.get("date");
+ if (date == null)
+ continue;
+ InputOutputAnalysisDto dto = dateMap.getOrDefault(date, new InputOutputAnalysisDto());
+ dto.setDate(date);
+ BigDecimal qty = (BigDecimal) map.get("quantity");
+ dto.setOutputSum(dto.getOutputSum() != null ? dto.getOutputSum().add(qty) : qty);
+ dateMap.put(date, dto);
+ }
+ }
+
+ dateMap.values().forEach(dto -> {
+ if (dto.getInputSum() == null)
+ dto.setInputSum(BigDecimal.ZERO);
+ if (dto.getOutputSum() == null)
+ dto.setOutputSum(BigDecimal.ZERO);
+ });
+
+ return dateMap.values().stream()
+ .sorted(Comparator.comparing(InputOutputAnalysisDto::getDate))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<MapDto> processOutputAnalysis(Integer type) {
+ LocalDate today = LocalDate.now();
+ LocalDate startDate;
+ LocalDate endDate = today;
+
+ switch (type) {
+ case 1: // 鍛�
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ case 2: // 鏈�
+ startDate = today.withDayOfMonth(1);
+ break;
+ case 3: // 瀛e害
+ int currentMonth = today.getMonthValue();
+ int startMonth = ((currentMonth - 1) / 3) * 3 + 1;
+ startDate = LocalDate.of(today.getYear(), startMonth, 1);
+ break;
+ default:
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ }
+
+ ProductWorkOrderDto queryDto = new ProductWorkOrderDto();
+ queryDto.setPlanStartTime(startDate);
+ queryDto.setPlanEndTime(endDate);
+
+ List<ProductWorkOrderDto> list = productWorkOrderMapper.pageProductWorkOrder(new Page<>(1, -1), queryDto)
+ .getRecords();
+
+ if (CollectionUtils.isEmpty(list)) {
+ return new ArrayList<>();
+ }
+
+ Map<String, BigDecimal> processOutputMap = list.stream()
+ .filter(item -> item.getProcessName() != null && item.getCompleteQuantity() != null)
+ .collect(Collectors.groupingBy(
+ ProductWorkOrderDto::getProcessName,
+ Collectors.reducing(BigDecimal.ZERO,
+ ProductWorkOrderDto::getCompleteQuantity,
+ BigDecimal::add)));
+
+ BigDecimal total = processOutputMap.values().stream()
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ if (BigDecimal.ZERO.compareTo(total) == 0) {
+ return new ArrayList<>();
+ }
+
+ List<MapDto> result = new ArrayList<>();
+ processOutputMap.forEach((name, value) -> {
+ MapDto dto = new MapDto();
+ dto.setName(name);
+ dto.setValue(value.stripTrailingZeros().toPlainString());
+
+ BigDecimal rate = value
+ .divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"));
+
+ dto.setRate(rate.setScale(2, RoundingMode.HALF_UP) + "%");
+ result.add(dto);
+ });
+
+ return result;
+ }
+
+ @Override
+ public List<WorkOrderEfficiencyDto> workOrderEfficiencyAnalysis(Integer type) {
+
+ LocalDate today = LocalDate.now();
+ LocalDate startDate;
+ LocalDate endDate = today;
+
+ switch (type) {
+ case 1: // 鍛�
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ case 2: // 鏈�
+ startDate = today.withDayOfMonth(1);
+ break;
+ case 3: // 瀛e害
+ int currentMonth = today.getMonthValue();
+ int startMonth = ((currentMonth - 1) / 3) * 3 + 1;
+ startDate = LocalDate.of(today.getYear(), startMonth, 1);
+ break;
+ default:
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ }
+
+ String startStr = startDate.atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+ String endStr = endDate.atTime(LocalTime.MAX).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ List<ProductWorkOrderDto> startList = productWorkOrderMapper.selectWorkOrderStartStats(startStr, endStr);
+
+ List<com.ruoyi.production.dto.ProductionProductOutputDto> outputList = productionProductOutputMapper
+ .selectOutputStats(startStr, endStr);
+
+ Map<String, WorkOrderEfficiencyDto> dateMap = new HashMap<>();
+
+ if (!CollectionUtils.isEmpty(startList)) {
+ for (ProductWorkOrderDto item : startList) {
+ if (item.getPlanStartTime() != null) {
+ String date = item.getPlanStartTime().toString();
+ WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
+ dto.setDate(date);
+ BigDecimal qty = item.getPlanQuantity() != null ? item.getPlanQuantity() : BigDecimal.ZERO;
+ dto.setStartQuantity(dto.getStartQuantity() != null ? dto.getStartQuantity().add(qty) : qty);
+ dateMap.put(date, dto);
+ }
+ }
+ }
+
+ // 瀹屽伐鏁伴噺鍜岃壇鍝佺巼
+ if (!CollectionUtils.isEmpty(outputList)) {
+ for (com.ruoyi.production.dto.ProductionProductOutputDto item : outputList) {
+ if (item.getCreateTime() != null) {
+ String date = item.getCreateTime().toLocalDate().toString();
+ WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
+ dto.setDate(date);
+
+ BigDecimal finishQty = item.getQuantity() != null ? item.getQuantity() : BigDecimal.ZERO;
+ BigDecimal scrapQty = item.getScrapQty() != null ? item.getScrapQty() : BigDecimal.ZERO;
+
+ dto.setFinishQuantity(
+ dto.getFinishQuantity() != null ? dto.getFinishQuantity().add(finishQty) : finishQty);
+ }
+ }
+
+ Map<String, BigDecimal> scrapMap = outputList.stream()
+ .filter(i -> i.getCreateTime() != null)
+ .collect(Collectors.groupingBy(
+ i -> i.getCreateTime().toLocalDate().toString(),
+ Collectors.reducing(BigDecimal.ZERO,
+ i -> i.getScrapQty() != null ? i.getScrapQty() : BigDecimal.ZERO,
+ BigDecimal::add)));
+
+ Map<String, BigDecimal> finishMap = outputList.stream()
+ .filter(i -> i.getCreateTime() != null)
+ .collect(Collectors.groupingBy(
+ i -> i.getCreateTime().toLocalDate().toString(),
+ Collectors.reducing(BigDecimal.ZERO,
+ i -> i.getQuantity() != null ? i.getQuantity() : BigDecimal.ZERO,
+ BigDecimal::add)));
+
+ finishMap.forEach((date, qty) -> {
+ WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
+ dto.setDate(date);
+ dto.setFinishQuantity(qty);
+ dateMap.put(date, dto);
+ });
+
+ dateMap.forEach((date, dto) -> {
+ BigDecimal finish = dto.getFinishQuantity() != null ? dto.getFinishQuantity() : BigDecimal.ZERO;
+ BigDecimal scrap = scrapMap.getOrDefault(date, BigDecimal.ZERO);
+ BigDecimal total = finish.add(scrap);
+
+ if (total.compareTo(BigDecimal.ZERO) > 0) {
+ BigDecimal rate = finish.divide(total, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP);
+ dto.setYieldRate(rate.toString());
+ } else {
+ dto.setYieldRate("0.00");
+ }
+
+ if (dto.getStartQuantity() == null)
+ dto.setStartQuantity(BigDecimal.ZERO);
+ if (dto.getFinishQuantity() == null)
+ dto.setFinishQuantity(BigDecimal.ZERO);
+ });
+ }
+
+ dateMap.values().forEach(dto -> {
+ if (dto.getStartQuantity() == null)
+ dto.setStartQuantity(BigDecimal.ZERO);
+ if (dto.getFinishQuantity() == null)
+ dto.setFinishQuantity(BigDecimal.ZERO);
+ if (dto.getYieldRate() == null)
+ dto.setYieldRate("0.00");
+ });
+
+ return dateMap.values().stream()
+ .sorted(Comparator.comparing(WorkOrderEfficiencyDto::getDate))
+ .collect(Collectors.toList());
+ }
+
+ @Autowired
+ private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
+
+ @Override
+ public List<ProductionAccountingDto> productionAccountingAnalysis(Integer type) {
+ LocalDate today = LocalDate.now();
+ LocalDate startDate;
+ LocalDate endDate = today;
+
+ switch (type) {
+ case 1: // 鍛�
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ case 2: // 鏈�
+ startDate = today.withDayOfMonth(1);
+ break;
+ case 3: // 瀛e害
+ int currentMonth = today.getMonthValue();
+ int startMonth = ((currentMonth - 1) / 3) * 3 + 1;
+ startDate = LocalDate.of(today.getYear(), startMonth, 1);
+ break;
+ default:
+ startDate = today.with(DayOfWeek.MONDAY);
+ break;
+ }
+
+ String startStr = startDate.atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ String endStr = endDate.plusDays(1).atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ List<Map<String, Object>> wagesList = salesLedgerProductionAccountingMapper.selectDailyWagesStats(startStr,
+ endStr);
+
+ if (CollectionUtils.isEmpty(wagesList)) {
+ return new ArrayList<>();
+ }
+
+ List<ProductionAccountingDto> result = new ArrayList<>();
+ for (Map<String, Object> map : wagesList) {
+ ProductionAccountingDto dto = new ProductionAccountingDto();
+ dto.setDateStr(map.get("dateStr").toString());
+ dto.setNumberOfCompleted(((BigDecimal) map.get("numberOfCompleted")).intValue());
+ dto.setAmount(map.get("amount") != null ? (BigDecimal) map.get("amount") : BigDecimal.ZERO);
+ dto.setPassRate(map.get("passRate") != null ? (BigDecimal) map.get("passRate") : BigDecimal.ZERO);
+ result.add(dto);
+ }
+
+ result.sort(Comparator.comparing(ProductionAccountingDto::getDateStr));
+
+ return result;
+ }
+
+ @Override
+ public List<MapDto> orderCount() {
+ LocalDate now = LocalDate.now();
+
+ String currentStart = now.withDayOfMonth(1).atStartOfDay()
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+ String currentEnd = now.atTime(LocalTime.MAX).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ LocalDate lastMonthDate = now.minusMonths(1);
+ String lastStart = lastMonthDate.withDayOfMonth(1).atStartOfDay()
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+ String lastEnd = lastMonthDate.withDayOfMonth(lastMonthDate.lengthOfMonth()).atTime(LocalTime.MAX)
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ int currentCreated = productOrderMapper.countCreated(currentStart, currentEnd);
+ int lastCreated = productOrderMapper.countCreated(lastStart, lastEnd);
+ MapDto createdDto = createOrderCountDto("鐢熶骇璁㈠崟鏁�", currentCreated, lastCreated);
+
+ int currentCompleted = productOrderMapper.countCompleted(currentStart, currentEnd);
+ int lastCompleted = productOrderMapper.countCompleted(lastStart, lastEnd);
+ MapDto completedDto = createOrderCountDto("宸插畬鎴愯鍗曟暟", currentCompleted, lastCompleted);
+
+ int currentPending = productOrderMapper.countPending(currentStart, currentEnd);
+ int lastPending = productOrderMapper.countPending(lastStart, lastEnd);
+ MapDto pendingDto = createOrderCountDto("寰呯敓浜ц鍗曟暟", currentPending, lastPending);
+
+ return Arrays.asList(createdDto, completedDto, pendingDto);
+ }
+
+ private MapDto createOrderCountDto(String name, int current, int last) {
+ MapDto dto = new MapDto();
+ dto.setName(name);
+ dto.setValue(String.valueOf(current));
+
+ BigDecimal currentVal = new BigDecimal(current);
+ BigDecimal lastVal = new BigDecimal(last);
+
+ if (lastVal.compareTo(BigDecimal.ZERO) == 0) {
+ dto.setRate(currentVal.compareTo(BigDecimal.ZERO) > 0 ? "100" : "0");
+ } else {
+ // (Current - Last) / Last * 100
+ BigDecimal diff = currentVal.subtract(lastVal);
+ BigDecimal rate = diff.divide(lastVal, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")).setScale(0,
+ RoundingMode.HALF_UP);
+ dto.setRate(rate.toString());
+ }
+ return dto;
+ }
+
+
+ @Override
+ public List<QualityQualifiedAnalysisDto> rawMaterialDetection(Integer type) {
+ return commonDetection(type, 0);
+ }
+
+ @Override
+ public List<QualityQualifiedAnalysisDto> processDetection(Integer type) {
+ return commonDetection(type, 1);
+ }
+
+ @Override
+ public List<QualityQualifiedAnalysisDto> factoryDetection(Integer type) {
+ return commonDetection(type, 2);
+ }
+
+ private List<QualityQualifiedAnalysisDto> commonDetection(Integer type, Integer inspectType) {
+
+ LocalDate[] range = calcDateRange(type);
+ LocalDate startDate = range[0];
+ LocalDate endDate = range[1];
+
+ String startStr = startDate.atStartOfDay()
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+ String endStr = endDate.atTime(LocalTime.MAX)
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ List<QualityInspect> list = qualityInspectMapper.selectList(
+ new LambdaQueryWrapper<QualityInspect>()
+ .eq(QualityInspect::getInspectType, inspectType)
+ .eq(QualityInspect::getInspectState, 1)
+ .ge(QualityInspect::getCheckTime, startStr)
+ .le(QualityInspect::getCheckTime, endStr));
+
+ return buildQualifiedAnalysis(list);
+ }
+
+ private LocalDate[] calcDateRange(Integer type) {
+ LocalDate today = LocalDate.now();
+ LocalDate startDate;
+ LocalDate endDate;
+
+ switch (type) {
+ case 1: // 鍛�
+ startDate = today.with(DayOfWeek.MONDAY);
+ endDate = today.with(DayOfWeek.SUNDAY);
+ break;
+ case 2: // 鏈�
+ startDate = today.with(TemporalAdjusters.firstDayOfMonth());
+ endDate = today.with(TemporalAdjusters.lastDayOfMonth());
+ break;
+ case 3: // 瀛e害
+ int currentMonth = today.getMonthValue();
+ int startMonth = ((currentMonth - 1) / 3) * 3 + 1;
+ startDate = LocalDate.of(today.getYear(), startMonth, 1);
+ endDate = LocalDate.of(today.getYear(), startMonth + 2, 1)
+ .with(TemporalAdjusters.lastDayOfMonth());
+ break;
+ default:
+ startDate = today.with(DayOfWeek.MONDAY);
+ endDate = today.with(DayOfWeek.SUNDAY);
+ }
+
+ return new LocalDate[]{startDate, endDate};
+ }
+
+ private List<QualityQualifiedAnalysisDto> buildQualifiedAnalysis(List<QualityInspect> list) {
+ List<QualityQualifiedAnalysisDto> result = new ArrayList<>();
+ QualityQualifiedAnalysisDto dto = new QualityQualifiedAnalysisDto();
+
+ if (CollectionUtils.isEmpty(list)) {
+ dto.setQualifiedCount(0);
+ dto.setUnqualifiedCount(0);
+ dto.setQualifiedRate(BigDecimal.ZERO.setScale(2));
+ dto.setUnqualifiedRate(BigDecimal.ZERO.setScale(2));
+ result.add(dto);
+ return result;
+ }
+
+ BigDecimal qualifiedCount = BigDecimal.ZERO;
+ BigDecimal unqualifiedCount = BigDecimal.ZERO;
+
+ for (QualityInspect item : list) {
+ if ("鍚堟牸".equals(item.getCheckResult())) {
+ qualifiedCount = qualifiedCount.add(item.getQuantity());
+ } else {
+ unqualifiedCount = unqualifiedCount.add(item.getQuantity());
+ }
+ }
+
+ BigDecimal totalCount = qualifiedCount.add(unqualifiedCount);
+
+ dto.setQualifiedCount(qualifiedCount.intValue());
+ dto.setUnqualifiedCount(unqualifiedCount.intValue());
+
+ if (totalCount.compareTo(BigDecimal.ZERO) == 0) {
+ dto.setQualifiedRate(BigDecimal.ZERO.setScale(2));
+ dto.setUnqualifiedRate(BigDecimal.ZERO.setScale(2));
+ result.add(dto);
+ return result;
+ }
+
+ BigDecimal hundred = BigDecimal.valueOf(100);
+
+ dto.setQualifiedRate(qualifiedCount.divide(totalCount, 4, RoundingMode.HALF_UP)
+ .multiply(hundred)
+ .setScale(2, RoundingMode.HALF_UP));
+
+ dto.setUnqualifiedRate(unqualifiedCount.divide(totalCount, 4, RoundingMode.HALF_UP)
+ .multiply(hundred)
+ .setScale(2, RoundingMode.HALF_UP));
+
+ result.add(dto);
+ return result;
+ }
+
+ @Override
+ public QualityInspectionCountDto qualityInspectionCount() {
+ // 鑾峰彇浠婂ぉ鐨勫紑濮嬪拰缁撴潫鏃ユ湡,鍖呭惈鏃跺垎绉�
+ LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
+ LocalDateTime todayEnd = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(0);
+ // 鑾峰彇鍓嶄竴澶╃殑寮�濮嬪拰缁撴潫鏃ユ湡,鍖呭惈鏃跺垎绉�
+ LocalDateTime prevStart = todayStart.minusDays(1);
+ LocalDateTime prevEnd = todayEnd.minusDays(1);
+ // 鏌ヨ鍑烘埅姝粖鏃ョ殑鎬绘楠屾暟
+ List<QualityInspect> todayList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
+ // .eq(QualityInspect::getInspectState, 1)
+ .le(QualityInspect::getCheckTime, todayEnd));
+ // 鏌ヨ鍑烘埅姝㈠墠涓�澶╃殑鎬绘楠屾暟
+ List<QualityInspect> prevList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
+ // .eq(QualityInspect::getInspectState, 1)
+ .le(QualityInspect::getCheckTime, prevEnd));
+ // 璁$畻浠婃棩鐨勬�绘楠屾暟
+ BigDecimal todayCount = todayList.stream()
+ .map(QualityInspect::getQuantity)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ // 璁$畻鍓嶄竴澶╃殑鎬绘楠屾暟
+ BigDecimal prevCount = prevList.stream()
+ .map(QualityInspect::getQuantity)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ // 璁$畻浠婃棩鐩稿鏄ㄥぉ鐨勪竴涓�绘瘮澧為暱
+ BigDecimal growthRate = calcGrowthRate(todayCount, prevCount);
+
+ // 璁$畻浠婂ぉ鐨勫緟瀹屾垚鏁伴噺
+ List<QualityInspect> todayPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
+ .eq(QualityInspect::getInspectState, 0)
+ .ge(QualityInspect::getCheckTime, todayStart)
+ .le(QualityInspect::getCheckTime, todayEnd));
+
+ // 璁$畻鍓嶄竴澶╃殑寰呭畬鎴愭暟閲�
+ List<QualityInspect> prevPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
+ .eq(QualityInspect::getInspectState, 0)
+ .ge(QualityInspect::getCheckTime, prevStart)
+ .le(QualityInspect::getCheckTime, prevEnd));
+ // 璁$畻浠婂ぉ鐨勫緟瀹屾垚鏁伴噺
+ BigDecimal todayPendingCount = todayPendingList.stream()
+ .map(QualityInspect::getQuantity)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ // 璁$畻鍓嶄竴澶╃殑寰呭畬鎴愭暟閲�
+ BigDecimal prevPendingCount = prevPendingList.stream()
+ .map(QualityInspect::getQuantity)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ // 璁$畻浠婂ぉ鐨勫緟瀹屾垚鏁伴噺鐩稿鏄ㄥぉ鐨勪竴涓悓姣斿闀�
+ BigDecimal todayPendingCountGrowthRate = calcGrowthRate(todayPendingCount, prevPendingCount);
+ // 璁$畻浠婂ぉ鐨勫凡瀹屾垚鏁伴噺
+ List<QualityInspect> todayCompletedList = qualityInspectMapper
+ .selectList(new LambdaQueryWrapper<QualityInspect>()
+ .eq(QualityInspect::getInspectState, 1)
+ .ge(QualityInspect::getCheckTime, todayStart)
+ .le(QualityInspect::getCheckTime, todayEnd));
+ // 璁$畻鍓嶄竴澶╃殑宸插畬鎴愭暟閲�
+ List<QualityInspect> prevCompletedList = qualityInspectMapper
+ .selectList(new LambdaQueryWrapper<QualityInspect>()
+ .eq(QualityInspect::getInspectState, 1)
+ .ge(QualityInspect::getCheckTime, prevStart)
+ .le(QualityInspect::getCheckTime, prevEnd));
+ // 璁$畻浠婂ぉ鐨勫凡瀹屾垚鏁伴噺
+ BigDecimal todayCompletedCount = todayCompletedList.stream()
+ .map(QualityInspect::getQuantity)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ // 璁$畻鍓嶄竴澶╃殑宸插畬鎴愭暟閲�
+ BigDecimal prevCompletedCount = prevCompletedList.stream()
+ .map(QualityInspect::getQuantity)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ // 璁$畻浠婂ぉ鐨勫凡瀹屾垚鏁伴噺鐩稿鏄ㄥぉ鐨勪竴涓悓姣斿闀�
+ BigDecimal todayCompletedCountGrowthRate = calcGrowthRate(todayCompletedCount, prevCompletedCount);
+ QualityInspectionCountDto dto = new QualityInspectionCountDto();
+ dto.setTotalCount(todayCount);
+ dto.setTotalCountGrowthRate(growthRate);
+ dto.setTodayPendingCount(todayPendingCount);
+ dto.setTodayPendingCountGrowthRate(todayPendingCountGrowthRate);
+ dto.setTodayCompletedCount(todayCompletedCount);
+ dto.setTodayCompletedCountGrowthRate(todayCompletedCountGrowthRate);
+ return dto;
+ }
+
+ private BigDecimal calcGrowthRate(BigDecimal today, BigDecimal prev) {
+ if (prev == null || prev.compareTo(BigDecimal.ZERO) == 0) {
+ return BigDecimal.ZERO.setScale(2);
+ }
+ return today.subtract(prev)
+ .divide(prev, 4, RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100))
+ .setScale(2, RoundingMode.HALF_UP);
+ }
+
+ @Override
+ public NonComplianceWarningDto nonComplianceWarning() {
+
+ // 杩戜竷澶╂椂闂村尯闂�
+ LocalDateTime[] range = lastSevenDaysRange();
+ LocalDateTime startTime = range[0];
+ LocalDateTime endTime = range[1];
+
+ // 鏌ヨ杩戜竷澶╁凡澶勭悊涓嶅悎鏍兼暟鎹�
+ List<QualityUnqualified> list = qualityUnqualifiedMapper.selectList(
+ new LambdaQueryWrapper<QualityUnqualified>()
+ .eq(QualityUnqualified::getInspectState, 1)
+ .ge(QualityUnqualified::getCheckTime, startTime)
+ .le(QualityUnqualified::getCheckTime, endTime));
+
+ NonComplianceWarningDto dto = new NonComplianceWarningDto();
+
+ if (CollectionUtils.isEmpty(list)) {
+ dto.setRawMaterialRatio(BigDecimal.ZERO);
+ dto.setSemiFinishedProductRatio(BigDecimal.ZERO);
+ dto.setFinishedProductRatio(BigDecimal.ZERO);
+ dto.setChildren(new ArrayList<>());
+ return dto;
+ }
+
+ // 鏌ヨ鎵�鏈変骇鍝�
+ List<Product> products = productMapper.selectList(null);
+
+ Map<Long, Product> productMap = products.stream()
+ .collect(Collectors.toMap(Product::getId, p -> p));
+
+ BigDecimal rawMaterialCount = BigDecimal.ZERO;
+ BigDecimal semiFinishedCount = BigDecimal.ZERO;
+ BigDecimal finishedCount = BigDecimal.ZERO;
+
+ List<NonComplianceWarningDto.Item> children = new ArrayList<>();
+
+ for (QualityUnqualified item : list) {
+
+ BigDecimal quantity = item.getQuantity();
+ Long productId = item.getProductId();
+
+ Product product = productMap.get(productId);
+ if (product == null) {
+ continue;
+ }
+
+ // 鎵惧埌浜у搧澶х被
+ Product parent = product.getParentId() == null
+ ? product
+ : productMap.get(product.getParentId());
+
+ if (parent == null) {
+ continue;
+ }
+
+ switch (parent.getProductName()) {
+ case "鍘熸潗鏂�":
+ rawMaterialCount = rawMaterialCount.add(quantity);
+ break;
+ case "鍗婃垚鍝�":
+ semiFinishedCount = semiFinishedCount.add(quantity);
+ break;
+ case "鎴愬搧":
+ finishedCount = finishedCount.add(quantity);
+ break;
+ default:
+ break;
+ }
+
+ // 缁勮鏄庣粏
+ NonComplianceWarningDto.Item child = new NonComplianceWarningDto.Item();
+ // child.setProductTitle(item.getProductName());
+ child.setProductTitle(parent.getProductName());
+ child.setDescription(item.getDefectivePhenomena());
+ child.setDate(formatDate(item.getCheckTime()));
+ children.add(child);
+ }
+
+ BigDecimal total = rawMaterialCount
+ .add(semiFinishedCount)
+ .add(finishedCount);
+
+ dto.setRawMaterialRatio(calcRate(rawMaterialCount, total));
+ dto.setSemiFinishedProductRatio(calcRate(semiFinishedCount, total));
+ dto.setFinishedProductRatio(calcRate(finishedCount, total));
+ dto.setChildren(children);
+
+ return dto;
+ }
+
+ private BigDecimal calcRate(BigDecimal part, BigDecimal total) {
+ if (total == null || total.compareTo(BigDecimal.ZERO) == 0) {
+ return BigDecimal.ZERO.setScale(2);
+ }
+ return part.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100))
+ .setScale(2, RoundingMode.HALF_UP);
+ }
+
+ public static String formatDate(Date date) {
+ if (date == null) {
+ return null;
+ }
+ return date.toInstant()
+ .atZone(ZoneId.systemDefault())
+ .toLocalDate()
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ }
+
+ /**
+ * 鑾峰彇杩戜竷澶╃殑鏃堕棿鍖洪棿锛堝寘鍚粖澶╋級
+ */
+ public static LocalDateTime[] lastSevenDaysRange() {
+ LocalDate today = LocalDate.now();
+
+ LocalDateTime startTime = today.minusDays(6).atStartOfDay();
+ LocalDateTime endTime = today.atTime(23, 59, 59);
+
+ return new LocalDateTime[]{startTime, endTime};
+ }
+
+ @Override
+ public List<CompletedInspectionCountDto> completedInspectionCount() {
+ // 杩戜竷澶╂椂闂村尯闂�
+ LocalDateTime[] range = lastSevenDaysRange();
+ LocalDateTime startTime = range[0];
+ LocalDateTime endTime = range[1];
+
+ // 鏌ヨ杩戜竷澶╁凡瀹屾垚鐨勬楠屾暟鎹�
+ List<QualityInspect> list = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
+ .eq(QualityInspect::getInspectState, 1)
+ .ge(QualityInspect::getCheckTime, startTime)
+ .le(QualityInspect::getCheckTime, endTime));
+
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
+
+ Map<String, CompletedInspectionCountDto> resultMap = new LinkedHashMap<>();
+
+ for (int i = 6; i >= 0; i--) {
+ LocalDate date = LocalDate.now().minusDays(i);
+ String dateStr = date.format(formatter);
+
+ CompletedInspectionCountDto dto = new CompletedInspectionCountDto();
+ dto.setDateStr(dateStr);
+ dto.setQualifiedCount(BigDecimal.ZERO);
+ dto.setUnqualifiedCount(BigDecimal.ZERO);
+ dto.setPassRate(BigDecimal.ZERO);
+
+ resultMap.put(dateStr, dto);
+ }
+
+ // 绱姞鍚堟牸 / 涓嶅悎鏍兼暟閲�
+ for (QualityInspect item : list) {
+
+ String dateStr = item.getCheckTime()
+ .toInstant()
+ .atZone(ZoneId.systemDefault())
+ .toLocalDate()
+ .format(formatter);
+
+ CompletedInspectionCountDto dto = resultMap.get(dateStr);
+ if (dto == null) {
+ continue;
+ }
+
+ BigDecimal quantity = item.getQuantity();
+
+ if ("鍚堟牸".equals(item.getCheckResult())) {
+ dto.setQualifiedCount(dto.getQualifiedCount().add(quantity));
+ } else {
+ dto.setUnqualifiedCount(dto.getUnqualifiedCount().add(quantity));
+ }
+ }
+
+ // 璁$畻鍚堟牸鐜�
+ for (CompletedInspectionCountDto dto : resultMap.values()) {
+ BigDecimal total = dto.getQualifiedCount().add(dto.getUnqualifiedCount());
+ dto.setPassRate(calcRate(dto.getQualifiedCount(), total));
+ }
+
+ return new ArrayList<>(resultMap.values());
+ }
+
+ @Override
+ public List<UnqualifiedProductRankDto> unqualifiedProductRanking() {
+
+ List<QualityInspect> list = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
+ .eq(QualityInspect::getInspectState, 1));
+
+ if (CollectionUtils.isEmpty(list)) {
+ return new ArrayList<>();
+ }
+
+ Map<Long, String> productNameMap = productMapper.selectList(null)
+ .stream()
+ .collect(Collectors.toMap(Product::getId, Product::getProductName));
+
+ Map<Long, List<QualityInspect>> groupMap = list.stream()
+ .collect(Collectors.groupingBy(QualityInspect::getProductId));
+
+ List<UnqualifiedProductRankDto> resultList = new ArrayList<>();
+
+ for (Map.Entry<Long, List<QualityInspect>> entry : groupMap.entrySet()) {
+
+ Long productId = entry.getKey();
+ List<QualityInspect> items = entry.getValue();
+
+ BigDecimal totalCount = BigDecimal.ZERO;
+ BigDecimal qualifiedCount = BigDecimal.ZERO;
+ BigDecimal unqualifiedCount = BigDecimal.ZERO;
+
+ for (QualityInspect item : items) {
+ BigDecimal qty = item.getQuantity();
+ totalCount = totalCount.add(qty);
+
+ if ("鍚堟牸".equals(item.getCheckResult())) {
+ qualifiedCount = qualifiedCount.add(qty);
+ } else {
+ unqualifiedCount = unqualifiedCount.add(qty);
+ }
+ }
+
+ if (totalCount.compareTo(BigDecimal.ZERO) == 0) {
+ continue;
+ }
+
+ BigDecimal passRate = qualifiedCount
+ .divide(totalCount, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(2, RoundingMode.HALF_UP);
+
+ UnqualifiedProductRankDto dto = new UnqualifiedProductRankDto();
+ dto.setProductName(productNameMap.get(productId));
+ dto.setTotalCount(totalCount);
+ dto.setCompletedCount(qualifiedCount);
+ dto.setPassRate(passRate);
+
+ resultList.add(dto);
+ }
+
+ resultList.sort(Comparator.comparing(UnqualifiedProductRankDto::getPassRate));
+
+ return resultList.stream().limit(5).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<MapDto> unqualifiedProductProcessingAnalysis() {
+
+ List<QualityUnqualified> list = qualityUnqualifiedMapper.selectList(null);
+ if (CollectionUtils.isEmpty(list)) {
+ return new ArrayList<>();
+ }
+
+ // 缁熻姣忕澶勭悊缁撴灉鐨勬暟閲�
+ Map<String, BigDecimal> countMap = new HashMap<>();
+ for (QualityUnqualified item : list) {
+ if (StringUtils.isEmpty(item.getDealResult()) || item.getQuantity() == null) {
+ continue;
+ }
+ countMap.merge(item.getDealResult(), item.getQuantity(), BigDecimal::add);
+ }
+
+ if (countMap.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ // 璁$畻鎬绘暟
+ BigDecimal totalCount = countMap.values()
+ .stream()
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ if (totalCount.compareTo(BigDecimal.ZERO) == 0) {
+ return new ArrayList<>();
+ }
+
+ // 鎸夋暟閲忓�掑簭鎺掑簭
+ List<Map.Entry<String, BigDecimal>> sortedList = countMap.entrySet()
+ .stream()
+ .sorted((a, b) -> b.getValue().compareTo(a.getValue()))
+ .collect(Collectors.toList());
+
+ List<MapDto> result = new ArrayList<>();
+
+ int limit = Math.min(3, sortedList.size());
+ BigDecimal otherCount = BigDecimal.ZERO;
+
+ for (int i = 0; i < sortedList.size(); i++) {
+ Map.Entry<String, BigDecimal> entry = sortedList.get(i);
+
+ if (i < limit) {
+ MapDto dto = new MapDto();
+ dto.setName(entry.getKey());
+ dto.setValue(entry.getValue().setScale(2, RoundingMode.HALF_UP).toPlainString());
+ dto.setRate(calcRate(entry.getValue(), totalCount).toString());
+ result.add(dto);
+ } else {
+ otherCount = otherCount.add(entry.getValue());
+ }
+ }
+
+ if (otherCount.compareTo(BigDecimal.ZERO) > 0) {
+ MapDto otherDto = new MapDto();
+ otherDto.setName("鍏朵粬");
+ otherDto.setValue(otherCount.setScale(2, RoundingMode.HALF_UP).toPlainString());
+ otherDto.setRate(calcRate(otherCount, totalCount).toString());
+ result.add(otherDto);
+ }
+
+ return result;
+ }
+
+}
\ No newline at end of file
--
Gitblit v1.9.3