From f6f57ba70679a0b050031f3cdf81b5bf5d4cbd60 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 11 七月 2025 15:28:37 +0800
Subject: [PATCH] 1.生产加工优化 2.销售,库存查询优化

---
 main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java |  404 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 399 insertions(+), 5 deletions(-)

diff --git a/main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java b/main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java
index 8d2899c..145cf5b 100644
--- a/main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java
+++ b/main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java
@@ -1,13 +1,17 @@
 package com.ruoyi.business.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.basic.entity.CoalInfo;
 import com.ruoyi.basic.entity.Customer;
+import com.ruoyi.basic.mapper.CoalInfoMapper;
 import com.ruoyi.basic.mapper.CustomerMapper;
 import com.ruoyi.business.dto.SalesRecordDto;
+import com.ruoyi.business.dto.YearlyQueryDto;
 import com.ruoyi.business.entity.OfficialInventory;
 import com.ruoyi.business.entity.SalesRecord;
 import com.ruoyi.business.mapper.OfficialInventoryMapper;
@@ -15,13 +19,28 @@
 import com.ruoyi.business.service.SalesRecordService;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.system.mapper.SysUserMapper;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
 import java.time.LocalDate;
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.TemporalAdjusters;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.*;
 
 /**
  * <p>
@@ -43,12 +62,86 @@
 
     private final OfficialInventoryMapper officialInventoryMapper;
 
+    private final CoalInfoMapper coalInfoMapper;
+
     @Override
-    public IPage<SalesRecord> selectSalesRecordList(Page page, SalesRecordDto salesRecordDto) {
+    public IPage<SalesRecordDto> selectSalesRecordList(Page<SalesRecord> page, SalesRecordDto salesRecordDto) {
+        // 1. 鍒涘缓鏌ヨ鏉′欢锛屾寜鍒涘缓鏃堕棿鍊掑簭鎺掑簭
         LambdaQueryWrapper<SalesRecord> queryWrapper = new LambdaQueryWrapper<>();
+
+        if (StringUtils.isNotBlank(salesRecordDto.getSearchAll())) {
+            String searchValue = salesRecordDto.getSearchAll();
+            // 1. 鍏堝皾璇曚綔涓烘棩鏈熸煡璇�
+            try {
+                LocalDate saleDate = LocalDate.parse(searchValue);
+                queryWrapper.eq(SalesRecord::getSaleDate, saleDate);
+            } catch (DateTimeParseException e) {
+                // 2. 濡傛灉涓嶆槸鏃ユ湡锛屽垯浣滀负鐓ょ鍚嶇О鏌ヨ
+                LambdaQueryWrapper<CoalInfo> coalQueryWrapper = new LambdaQueryWrapper<>();
+                coalQueryWrapper.like(CoalInfo::getCoal, searchValue);
+                List<CoalInfo> coalInfos = coalInfoMapper.selectList(coalQueryWrapper);
+                if (!coalInfos.isEmpty()) {
+                    // 鎻愬彇鎵�鏈夊尮閰嶇殑鐓ょID
+                    List<Long> coalIds = coalInfos.stream()
+                            .map(CoalInfo::getId)
+                            .collect(Collectors.toList());
+                    // 浣跨敤in鏌ヨ鍖归厤浠绘剰涓�涓叅绉岻D
+                    queryWrapper.in(SalesRecord::getCoalId, coalIds);
+                } else {
+                    // 3. 濡傛灉鎵句笉鍒扮叅绉嶏紝鍙互杩斿洖绌虹粨鏋�
+                    queryWrapper.eq(SalesRecord::getCoalId, "-1"); // 浣跨敤涓嶅彲鑳藉瓨鍦ㄧ殑ID
+                }
+            }
+        }
+
         queryWrapper.orderByDesc(SalesRecord::getCreateTime);
-        return salesRecordMapper.selectPage(page, queryWrapper);
+
+        // 2. 鑾峰彇鍒嗛〉鐨勯攢鍞褰�
+        IPage<SalesRecord> salesRecordPage = salesRecordMapper.selectPage(page, queryWrapper);
+
+        // 3. 鎵归噺鏌ヨ鎵�鏈塁oalInfo
+        List<Long> coalIds = salesRecordPage.getRecords().stream()
+                .map(SalesRecord::getCoalId)  // 鑾峰彇鎵�鏈塖alesRecord鐨刢oalId
+                .collect(Collectors.toList());
+        Map<Long, CoalInfo> coalInfoMap;
+
+        // 濡傛灉鏈夌叅鐐璉D锛屾墽琛屾壒閲忔煡璇�
+        if (!coalIds.isEmpty()) {
+            // 浣跨敤selectList杩涜鎵归噺鏌ヨ
+            LambdaQueryWrapper<CoalInfo> coalInfoQueryWrapper = new LambdaQueryWrapper<>();
+            coalInfoQueryWrapper.in(CoalInfo::getId, coalIds);
+            List<CoalInfo> coalInfos = coalInfoMapper.selectList(coalInfoQueryWrapper);
+
+            // 灏嗘煡璇㈢粨鏋滄斁鍏ap涓紝鐓ょ偔ID涓洪敭锛孋oalInfo涓哄��
+            coalInfoMap = coalInfos.stream()
+                    .collect(Collectors.toMap(CoalInfo::getId, Function.identity()));
+        } else {
+            coalInfoMap = new HashMap<>();
+        }
+
+        // 4. 鍒涘缓杩斿洖缁撴灉椤碉紝浣跨敤BeanUtils杩涜灞炴�у鍒�
+        Page<SalesRecordDto> resultPage = new Page<>();
+        BeanUtils.copyProperties(salesRecordPage, resultPage);  // 澶嶅埗鍒嗛〉淇℃伅
+
+        // 5. 杞崲SalesRecord涓篠alesRecordDto锛屽苟璁剧疆姣忔潯閿�鍞褰曠殑鐓ょ偔淇℃伅
+        List<SalesRecordDto> dtoList = salesRecordPage.getRecords().stream().map(salesRecord -> {
+            SalesRecordDto dto = new SalesRecordDto();
+            BeanUtils.copyProperties(salesRecord, dto);  // 灏哠alesRecord鐨勫睘鎬у鍒跺埌SalesRecordDto涓�
+
+            // 璁剧疆Coal淇℃伅
+            CoalInfo coalInfo = coalInfoMap.get(salesRecord.getCoalId());
+            if (coalInfo != null) {
+                dto.setCoal(coalInfo.getCoal());
+            }
+
+            return dto;
+        }).collect(Collectors.toList());
+
+        resultPage.setRecords(dtoList);  // 璁剧疆杞崲鍚庣殑DTO鍒楄〃
+
+        return resultPage;
     }
+
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -61,7 +154,7 @@
         if (officialInventory == null) {
             throw new BaseException("姝e紡搴撶叅绉嶄俊鎭笉瀛樺湪");
         }
-        if (salesRecordDto.getSaleQuantity().compareTo(officialInventory.getInventoryQuantity()) > 0){
+        if (salesRecordDto.getSaleQuantity().compareTo(officialInventory.getInventoryQuantity()) > 0) {
             throw new BaseException("閿�鍞暟閲忎笉鑳藉ぇ浜庡簱瀛樻暟閲�");
         }
         officialInventory.setInventoryQuantity(officialInventory.getInventoryQuantity().subtract(salesRecordDto.getSaleQuantity()));
@@ -69,7 +162,7 @@
         officialInventoryMapper.updateById(officialInventory);
 
         // 鏋勫缓閿�鍞褰曞疄浣�
-        SalesRecord salesRecord = buildSalesRecord(salesRecordDto,officialInventory.getCoalId());
+        SalesRecord salesRecord = buildSalesRecord(salesRecordDto, officialInventory.getCoalId());
 
         // 澶勭悊鏂板/鏇存柊閫昏緫
         if (salesRecordDto.getId() == null) {
@@ -94,7 +187,7 @@
         }
     }
 
-    private SalesRecord buildSalesRecord(SalesRecordDto dto,Long coalId) {
+    private SalesRecord buildSalesRecord(SalesRecordDto dto, Long coalId) {
         SalesRecord record = new SalesRecord();
         BeanUtils.copyProperties(dto, record);
 
@@ -163,4 +256,305 @@
         // 鎵ц鎵归噺閫昏緫鍒犻櫎
         return salesRecordMapper.update(null, updateWrapper);
     }
+
+    @Override
+    public Map<String, Object> getYearlyMonthlySales(YearlyQueryDto query) {
+        // 1. 澶勭悊榛樿鏌ヨ锛堜笉浼犲弬鏁版椂锛�
+        if (query == null || query.getTimeRange() == null || query.getTimeRange().length == 0) {
+            query = getDefaultQuery();
+        }
+
+        // 2. 瑙f瀽鏃堕棿鑼冨洿
+        LocalDate[] dateRange = parseAndValidateDateRange(query.getTimeRange());
+        LocalDate startDate = dateRange[0];
+        LocalDate endDate = dateRange[1];
+
+        // 3. 鏌ヨ鏁版嵁
+        List<SalesRecord> records = salesRecordMapper.findByDateRange(
+                startDate.withDayOfMonth(1),
+                endDate.withDayOfMonth(1).with(TemporalAdjusters.lastDayOfMonth())
+        );
+
+        // 4. 鏋勫缓鍝嶅簲
+        return buildResponse(query.getTimeRange(), records, startDate, endDate);
+    }
+
+    // 鑾峰彇榛樿鏌ヨ锛堝綋鍓嶅勾搴︽渶杩�6涓湀锛�
+    private YearlyQueryDto getDefaultQuery() {
+        LocalDate now = LocalDate.now();
+        LocalDate startDate = now.minusMonths(5).withDayOfMonth(1);
+
+        String[] timeRange = {
+                startDate.format(DateTimeFormatter.ofPattern("yyyy-MM")),
+                now.format(DateTimeFormatter.ofPattern("yyyy-MM"))
+        };
+
+        YearlyQueryDto defaultQuery = new YearlyQueryDto();
+        defaultQuery.setTimeRange(timeRange);
+        return defaultQuery;
+    }
+
+    // 瑙f瀽骞堕獙璇佹棩鏈熻寖鍥�
+    private LocalDate[] parseAndValidateDateRange(String[] timeRange) {
+        if (timeRange == null || timeRange.length != 2) {
+            throw new IllegalArgumentException("鏃堕棿鑼冨洿鍙傛暟鏍煎紡涓嶆纭�");
+        }
+
+        LocalDate startDate = parseDate(timeRange[0]);
+        LocalDate endDate = parseDate(timeRange[1]);
+
+        if (startDate.isAfter(endDate)) {
+            throw new IllegalArgumentException("寮�濮嬫棩鏈熶笉鑳芥櫄浜庣粨鏉熸棩鏈�");
+        }
+
+        return new LocalDate[]{startDate, endDate};
+    }
+
+    // 瑙f瀽鏃ユ湡锛堟牸寮忥細yyyy-MM锛�
+    private LocalDate parseDate(String dateStr) {
+        try {
+            return YearMonth.parse(dateStr).atDay(1);
+        } catch (DateTimeParseException e) {
+            throw new IllegalArgumentException("鏃ユ湡鏍煎紡涓嶆纭紝搴斾负 yyyy-MM", e);
+        }
+    }
+
+    // 鏋勫缓鍝嶅簲鏁版嵁
+    private Map<String, Object> buildResponse(String[] timeRange,
+                                              List<SalesRecord> records,
+                                              LocalDate startDate,
+                                              LocalDate endDate) {
+        Map<String, Object> response = new LinkedHashMap<>();
+        response.put("timeRange", timeRange);
+        response.put("data", formatMonthlyData(records, startDate, endDate));
+        response.put("isDefaultQuery", timeRange.equals(getDefaultQuery().getTimeRange()));
+        return response;
+    }
+
+    // 鏍煎紡鍖栨湀搴︽暟鎹�
+    private Map<String, Integer> formatMonthlyData(List<SalesRecord> records,
+                                                   LocalDate startDate,
+                                                   LocalDate endDate) {
+        // 棰勫畾涔夋牸寮忓寲鍣�
+        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+        // 浣跨敤 TreeMap 鑷姩鎸夐敭鎺掑簭
+        Map<String, Integer> monthlyData = records.stream()
+                .collect(Collectors.groupingBy(
+                        r -> r.getSaleDate().format(monthFormatter),
+                        TreeMap::new,
+                        // 鍏抽敭淇敼锛氬鐞� saleQuantity 涓� null 鐨勬儏鍐碉紝榛樿鎸� 0 璁$畻
+                        Collectors.summingInt(r -> {
+                            BigDecimal quantity = r.getSaleQuantity();
+                            return quantity != null ? quantity.intValue() : 0; // 涓夌洰杩愮畻绗﹀垽鏂�
+                        })
+                ));
+
+        // 濉厖缂哄け鏈堜唤
+        YearMonth start = YearMonth.from(startDate);
+        YearMonth end = YearMonth.from(endDate);
+
+        for (YearMonth month = start; !month.isAfter(end); month = month.plusMonths(1)) {
+            String monthKey = month.format(monthFormatter);
+            monthlyData.putIfAbsent(monthKey, 0);
+        }
+
+        return monthlyData;
+    }
+
+    @Override
+    public Map<String, Object> selectAllInfo() {
+        Map<String, Object> result = new LinkedHashMap<>();
+
+        //钀ユ敹閲戦
+        LocalDate today = LocalDate.now();
+        LocalDate yesterday = today.minusDays(1);
+
+        BigDecimal revenueAmount;
+        List<SalesRecord> salesRecords = salesRecordMapper.selectList(null);
+        revenueAmount = salesRecords.stream()
+                .map(SalesRecord::getTotalAmount)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        //浠婃棩钀ユ敹
+        BigDecimal todayRevenue = salesRecords.stream()
+                .filter(record -> today.equals(record.getSaleDate()))
+                .map(SalesRecord::getTotalAmount)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        //鏄ㄦ棩钀ユ敹
+        BigDecimal yesterdayRevenue = salesRecords.stream()
+                .filter(record -> yesterday.equals(record.getSaleDate()))
+                .map(SalesRecord::getTotalAmount)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        // 璁$畻澧為暱鐧惧垎姣�
+        BigDecimal increases = BigDecimal.ZERO;
+        String trend = "+";
+
+        if (yesterdayRevenue.compareTo(BigDecimal.ZERO) != 0) {
+            increases = todayRevenue.subtract(yesterdayRevenue)
+                    .divide(yesterdayRevenue, 4, RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal(100));
+
+            if (increases.compareTo(BigDecimal.ZERO) > 0) {
+                trend = "+";
+            } else if (increases.compareTo(BigDecimal.ZERO) < 0) {
+                trend = "鈥�";
+            }
+        }
+
+        // 6. 鏍煎紡鍖栫櫨鍒嗘瘮鏄剧ず
+        DecimalFormat formatNo = new DecimalFormat("0.00%");
+        String changeRate = formatNo.format(increases.divide(new BigDecimal(100), 4, RoundingMode.HALF_UP));
+
+        //渚涘簲閲�
+        BigDecimal saleQuantity = salesRecords.stream()
+                .map(SalesRecord::getSaleQuantity)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        //浠婃棩渚涘簲閲�
+        BigDecimal todaySaleQuantity = salesRecords.stream()
+                .filter(record -> today.equals(record.getSaleDate()))
+                .map(SalesRecord::getSaleQuantity)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        //鏄ㄦ棩渚涘簲閲�
+        BigDecimal yesterdaySaleQuantity = salesRecords.stream()
+                .filter(record -> yesterday.equals(record.getSaleDate()))
+                .map(SalesRecord::getSaleQuantity)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+        // 璁$畻澧為暱鐧惧垎姣�
+        BigDecimal increasesQuantity = BigDecimal.ZERO;
+        String trendQuantity = "+";
+
+        if (yesterdaySaleQuantity.compareTo(BigDecimal.ZERO) != 0) {
+            increasesQuantity = todaySaleQuantity.subtract(yesterdaySaleQuantity)
+                    .divide(yesterdaySaleQuantity, 4, RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal(100));
+
+            if (increasesQuantity.compareTo(BigDecimal.ZERO) > 0) {
+                trendQuantity = "+";
+            } else if (increasesQuantity.compareTo(BigDecimal.ZERO) < 0) {
+                trendQuantity = "鈥�";
+            }
+        }
+
+        // 鏍煎紡鍖栨暟閲忕櫨鍒嗘瘮鏄剧ず
+        DecimalFormat formatNoQuantity = new DecimalFormat("0.00%");
+        String saleQuantityRate = formatNoQuantity.format(increasesQuantity.divide(new BigDecimal(100), 4, RoundingMode.HALF_UP));
+
+        //钀ユ敹鍒嗗竷
+        //鑾峰彇鎵�鏈夌叅绉嶄俊鎭�(id鍜屽悕绉扮殑鏄犲皠)
+        Map<Long, String> coalIdToNameMap = coalInfoMapper.selectList(null).stream()
+                .collect(Collectors.toMap(
+                        CoalInfo::getId,
+                        CoalInfo::getCoal
+                ));
+
+        // 3. 鎸夌叅绉岻D缁熻鎬婚噾棰�
+        Map<Long, BigDecimal> revenueByCoalId = salesRecords.stream()
+                .collect(Collectors.groupingBy(
+                        SalesRecord::getCoalId,
+                        Collectors.reducing(
+                                BigDecimal.ZERO,
+                                SalesRecord::getTotalAmount,
+                                BigDecimal::add
+                        )
+                ));
+
+        // 鐓ょ閿�鍞垎甯冿紙鍗曠嫭浣滀负涓�涓瓙Map锛�
+        Map<String, BigDecimal> revenueDistribution = new LinkedHashMap<>();
+        coalIdToNameMap.forEach((id, name) -> {
+            BigDecimal amount = revenueByCoalId.getOrDefault(id, BigDecimal.ZERO)
+                    .setScale(2, RoundingMode.HALF_UP);
+            if (amount.compareTo(BigDecimal.ZERO) > 0) {
+                revenueDistribution.put(name, amount);
+            }
+        });
+
+        //閿�鍞暟鎹�
+        // 鎸塩oalId鍒嗙粍骞跺悎骞舵暟閲忓拰閲戦
+        Map<Long, Map<String, Object>> resultMap = new LinkedHashMap<>();
+
+        for (SalesRecord record : salesRecords) {
+            Long coalId = record.getCoalId();
+
+            // 灏嗘暟閲忓拰閲戦杞崲涓築igDecimal
+            BigDecimal quantity = record.getInventoryQuantity();
+            BigDecimal amount = record.getTotalAmount();
+
+            if (resultMap.containsKey(coalId)) {
+                Map<String, Object> existing = resultMap.get(coalId);
+
+                // 鑾峰彇鐜版湁鐨凚igDecimal鍊�
+                BigDecimal existingQuantity = (BigDecimal) existing.get("inventoryQuantity");
+                BigDecimal existingAmount = (BigDecimal) existing.get("totalAmount");
+
+                // 浣跨敤BigDecimal杩涜鍔犳硶杩愮畻
+                existing.put("inventoryQuantity", existingQuantity.add(quantity));
+                existing.put("totalAmount", existingAmount.add(amount));
+            } else {
+                Map<String, Object> newRecord = new HashMap<>();
+                newRecord.put("coalId", coalId);
+                newRecord.put("inventoryQuantity", quantity);
+                newRecord.put("totalAmount", amount);
+                resultMap.put(coalId, newRecord);
+            }
+        }
+
+        // 3. 鑾峰彇鎵�鏈夋秹鍙婄殑coalId
+        List<Long> coalIds = new ArrayList<>(resultMap.keySet());
+
+        // 4. 鎵归噺鏌ヨ鐓ょ淇℃伅骞跺~鍏呭埌缁撴灉涓�
+        if (!coalIds.isEmpty()) {
+            List<CoalInfo> coalInfos = coalInfoMapper.selectByIds(coalIds);
+            for (CoalInfo coalInfo : coalInfos) {
+                Map<String, Object> record = resultMap.get(coalInfo.getId());
+                if (record != null) {
+                    record.put("coalName", coalInfo.getCoal());
+                }
+            }
+        }
+
+        List<Map<String, Object>> results = new ArrayList<>(resultMap.values());
+
+        //鏈堝害鏁版嵁
+        //鏌ヨ鎵�鏈夌叅绉嶄俊鎭�
+        List<CoalInfo> allCoalTypes = coalInfoMapper.selectList(
+                new QueryWrapper<CoalInfo>().orderByAsc("id")
+        );
+        //棰勮绠楅攢閲忥細鎸塩oalId鍒嗙粍缁熻鎬婚攢閲�
+        Map<Long, BigDecimal> salesByCoalId = salesRecords.stream()
+                .collect(Collectors.groupingBy(
+                        SalesRecord::getCoalId,
+                        Collectors.reducing(
+                                BigDecimal.ZERO,
+                                SalesRecord::getSaleQuantity,
+                                BigDecimal::add
+                        )
+                ));
+
+        // 2. 鍒涘缓 resultMouth锛屽瓨鍌ㄧ叅绉嶅強鍏堕攢閲忥紙Map 缁撴瀯锛�
+        Map<String, BigDecimal> resultMouthMap = new LinkedHashMap<>();
+        for (CoalInfo coal : allCoalTypes) {
+            resultMouthMap.put(
+                    coal.getCoal(),  // 鐓ょ鍚嶇О锛堝 "鏃犵儫鐓�"锛�
+                    salesByCoalId.getOrDefault(coal.getId(), BigDecimal.valueOf(0)) // 閿�閲�
+            );
+        }
+
+        result.put("revenueAmount", revenueAmount.setScale(2, RoundingMode.HALF_UP));
+        result.put("changeRate", changeRate);
+        result.put("trend", trend);
+        result.put("saleQuantity", saleQuantity);
+        result.put("saleQuantityRate", saleQuantityRate);
+        result.put("trendQuantity", trendQuantity);
+        result.put("revenueDistribution", revenueDistribution);
+        result.put("salesResults", results);
+        result.put("resultMouth", resultMouthMap);
+
+        return result;
+    }
 }

--
Gitblit v1.9.3