From f29c8786807015d78b9be8a33397f69478d92a76 Mon Sep 17 00:00:00 2001 From: liding <756868258@qq.com> Date: 星期六, 12 七月 2025 16:52:27 +0800 Subject: [PATCH] 1.设备优化 2.配煤计算器 --- main-business/src/main/java/com/ruoyi/business/service/impl/SalesRecordServiceImpl.java | 421 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 417 insertions(+), 4 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 ae66aa0..01c3e54 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,25 +1,46 @@ 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; import com.ruoyi.business.mapper.SalesRecordMapper; 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> @@ -39,12 +60,85 @@ private final CustomerMapper customerMapper; + 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 (salesRecordDto.getSaleDate() != null) { + queryWrapper.eq(SalesRecord::getSaleDate, salesRecordDto.getSaleDate()); + } + + // 鎸夌叅绉嶅悕绉版煡璇� + if (StringUtils.isNotBlank(salesRecordDto.getCoal())) { + LambdaQueryWrapper<CoalInfo> coalQueryWrapper = new LambdaQueryWrapper<>(); + coalQueryWrapper.like(CoalInfo::getCoal, salesRecordDto.getCoal()); + List<CoalInfo> coalInfos = coalInfoMapper.selectList(coalQueryWrapper); + + if (!coalInfos.isEmpty()) { + List<Long> coalIds = coalInfos.stream() + .map(CoalInfo::getId) + .collect(Collectors.toList()); + queryWrapper.in(SalesRecord::getCoalId, coalIds); + } else { + // 濡傛灉娌℃湁鍖归厤鐨勭叅绉嶏紝鐩存帴杩斿洖绌虹粨鏋� + queryWrapper.eq(SalesRecord::getCoalId, -1L); // 浣跨敤涓嶅彲鑳藉瓨鍦ㄧ殑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) @@ -52,8 +146,20 @@ // 鍙傛暟鏍¢獙 validateSalesRecordDto(salesRecordDto); + // 鏇存柊姝e紡搴撳緟琛ュ簱鏁伴噺 + OfficialInventory officialInventory = officialInventoryMapper.selectById(salesRecordDto.getCoalId()); + if (officialInventory == null) { + throw new BaseException("姝e紡搴撶叅绉嶄俊鎭笉瀛樺湪"); + } + if (salesRecordDto.getSaleQuantity().compareTo(officialInventory.getInventoryQuantity()) > 0) { + throw new BaseException("閿�鍞暟閲忎笉鑳藉ぇ浜庡簱瀛樻暟閲�"); + } + officialInventory.setInventoryQuantity(officialInventory.getInventoryQuantity().subtract(salesRecordDto.getSaleQuantity())); + officialInventory.setPendingReplenishment(salesRecordDto.getSaleQuantity()); + officialInventoryMapper.updateById(officialInventory); + // 鏋勫缓閿�鍞褰曞疄浣� - SalesRecord salesRecord = buildSalesRecord(salesRecordDto); + SalesRecord salesRecord = buildSalesRecord(salesRecordDto, officialInventory.getCoalId()); // 澶勭悊鏂板/鏇存柊閫昏緫 if (salesRecordDto.getId() == null) { @@ -73,9 +179,12 @@ if (dto.getCustomerId() == null) { throw new BaseException("瀹㈡埛ID涓嶈兘涓虹┖"); } + if (dto.getCoalId() == null) { + throw new BaseException("璇烽�夋嫨涓�鏉$叅绉嶄俊鎭�"); + } } - private SalesRecord buildSalesRecord(SalesRecordDto dto) { + private SalesRecord buildSalesRecord(SalesRecordDto dto, Long coalId) { SalesRecord record = new SalesRecord(); BeanUtils.copyProperties(dto, record); @@ -109,6 +218,9 @@ record.setRegistrationDate(existing.getRegistrationDate()); } + // 鐓ょ + record.setCoalId(coalId); + return record; } @@ -141,4 +253,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