From 8b6616572a6c73c3ae25df1302880cd3817d17f7 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期三, 28 一月 2026 15:38:52 +0800
Subject: [PATCH] feat: 进销存大屏数据分析接口

---
 src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java |  204 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 201 insertions(+), 3 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..137c5fb 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,8 @@
 
 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.home.mapper.HomeMapper;
 import com.ruoyi.approve.mapper.ApproveProcessMapper;
 import com.ruoyi.approve.pojo.ApproveProcess;
 import com.ruoyi.basic.mapper.CustomerMapper;
@@ -12,7 +12,6 @@
 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;
@@ -86,6 +85,9 @@
     private SalesLedgerProductMapper salesLedgerProductMapper;
 
     @Autowired
+    private StockInventoryMapper stockInventoryMapper;
+
+    @Autowired
     private ProcurementRecordMapper procurementRecordStorageMapper;
 
     @Autowired
@@ -125,8 +127,9 @@
     private SysUserMapper sysUserMapper;
     @Autowired
     private SysUserDeptMapper sysUserDeptMapper;
+
     @Autowired
-    private StockInventoryMapper stockInventoryMapper;
+    private HomeMapper homeMapper;
 
     @Override
     public HomeBusinessDto business() {
@@ -900,4 +903,199 @@
         }
         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();
+    }
 }

--
Gitblit v1.9.3