From 80a0f2ec229568038ce0368b306c5aed5371048a Mon Sep 17 00:00:00 2001 From: Lemon Date: Tue, 7 Apr 2026 10:33:47 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E6=96=B0=E5=A2=9E=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=9E=AA=E5=9D=87=E6=95=88=E7=8E=87=E5=88=86=E6=9E=90=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessFinancialController.java | 35 +++-- .../service/BusinessFinancialService.java | 9 ++ .../impl/BusinessFinancialServiceImpl.java | 126 +++++++++++++++++- 3 files changed, 156 insertions(+), 14 deletions(-) diff --git a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java index a37e9cc1f..8955228fd 100644 --- a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java +++ b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java @@ -11,6 +11,7 @@ import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.service.BusinessFinancialService; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; +import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.web.MerchantOrderReportVO; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -101,7 +102,9 @@ public class BusinessFinancialController extends BaseController { logger.info("查询经营分析 params:{}", JSONObject.toJSONString(dto)); RestApiResponse response; try { - validateBusinessOperationQuery(dto); + if (dto == null) { + throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); + } BusinessOperationAnalysisVO result = businessFinancialService.getBusinessOperationAnalysis(dto); response = new RestApiResponse<>(result); logger.info("查询经营分析成功 startTime:{}, endTime:{}, selectedMetricCode:{}", @@ -117,18 +120,30 @@ public class BusinessFinancialController extends BaseController { } /** - * 校验经营分析查询参数 + * 查询枪均效率分析 * * @param dto 查询参数 + * @return 枪均效率分析 */ - private void validateBusinessOperationQuery(BusinessOperationAnalysisQueryDTO dto) { - if (dto == null) { - throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); - } - boolean startTimeBlank = StringUtils.isBlank(dto.getStartTime()); - boolean endTimeBlank = StringUtils.isBlank(dto.getEndTime()); - if (startTimeBlank ^ endTimeBlank) { - throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); + @PostMapping("/gunEfficiencyAnalysis") + public RestApiResponse getBusinessGunEfficiencyAnalysis(@RequestBody BusinessOperationAnalysisQueryDTO dto) { + logger.info("查询枪均效率分析 params:{}", JSONObject.toJSONString(dto)); + RestApiResponse response; + try { + if (dto == null) { + throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); + } + BusinessGunEfficiencyAnalysisVO result = businessFinancialService.getBusinessGunEfficiencyAnalysis(dto); + response = new RestApiResponse<>(result); + logger.info("查询枪均效率分析成功 startTime:{}, endTime:{}", + dto.getStartTime(), dto.getEndTime()); + } catch (BusinessException e) { + logger.warn("查询枪均效率分析业务异常 code:{}, message:{}", e.getCode(), e.getMessage(), e); + response = new RestApiResponse<>(e.getCode(), e.getMessage()); + } catch (Exception e) { + logger.error("查询枪均效率分析系统异常 params:{}", JSONObject.toJSONString(dto), e); + response = new RestApiResponse<>(e); } + return response; } } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java index 4b306a772..3abc86bf1 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java @@ -4,6 +4,7 @@ import com.jsowell.common.core.page.PageResponse; import com.jsowell.pile.dto.MerchantOrderReportDTO; import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; +import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.web.MerchantOrderReportVO; import com.jsowell.pile.vo.web.ParkingCouponRecordVO; @@ -26,4 +27,12 @@ public interface BusinessFinancialService { * @return 经营分析 */ BusinessOperationAnalysisVO getBusinessOperationAnalysis(BusinessOperationAnalysisQueryDTO dto); + + /** + * 查询枪均效率分析 + * + * @param dto 查询条件 + * @return 枪均效率分析 + */ + BusinessGunEfficiencyAnalysisVO getBusinessGunEfficiencyAnalysis(BusinessOperationAnalysisQueryDTO dto); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java index d78eaf7c1..ae2576b38 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java @@ -15,13 +15,16 @@ import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationDateRangeDTO; import com.jsowell.pile.dto.business.BusinessOperationSummaryDTO; +import com.jsowell.pile.domain.PileConnectorInfo; import com.jsowell.pile.domain.SettleOrderReport; import com.jsowell.pile.service.BusinessFinancialService; import com.jsowell.pile.service.CarCouponRecordService; import com.jsowell.pile.service.ClearingWithdrawInfoService; +import com.jsowell.pile.service.PileConnectorInfoService; import com.jsowell.pile.service.PileStationInfoService; import com.jsowell.pile.service.SettleOrderReportService; import com.jsowell.pile.util.UserUtils; +import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationDiagnosisItemVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationMetricVO; @@ -34,10 +37,12 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * 运营端小程序财务相关Service @@ -69,6 +74,9 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { @Autowired private PileStationInfoService pileStationInfoService; + @Autowired + private PileConnectorInfoService pileConnectorInfoService; + /** * 我的钱包查询 * @param dto @@ -217,6 +225,53 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { .build(); } + /** + * 查询枪均效率分析 + * + * @param dto 查询条件 + * @return 枪均效率分析 + */ + @Override + public BusinessGunEfficiencyAnalysisVO getBusinessGunEfficiencyAnalysis(BusinessOperationAnalysisQueryDTO dto) { + if (dto == null) { + return null; + } + if (StringUtils.isBlank(dto.getStartTime()) && StringUtils.isBlank(dto.getEndTime())) { + LocalDate endDate = LocalDate.now(); + LocalDate startDate = endDate.minusDays(6); + dto.setStartTime(startDate.toString()); + dto.setEndTime(endDate.toString()); + } + + BusinessOperationDateRangeDTO range = buildDateRange(dto); + List stationIdList = resolveStationIds(dto.getStationIdList()); + BusinessOperationSummaryDTO summary = buildOperationSummary( + stationIdList, range.getCurrentStart(), range.getCurrentEnd()); + + BigDecimal connectorCount = BigDecimal.valueOf(countConnectors(stationIdList)); + BigDecimal dayCount = BigDecimal.valueOf(calculateInclusiveDays(range.getCurrentStart(), range.getCurrentEnd())); + BigDecimal connectorDayCount = connectorCount.multiply(dayCount); + + BigDecimal gunAvgDailyServiceFee = BigDecimalUtils.safeDivide(summary.getServiceAmount(), connectorDayCount, 2); + BigDecimal gunAvgDailyElectricity = BigDecimalUtils.safeDivide(summary.getUseElectricity(), connectorDayCount, 4); + BigDecimal avgServiceFeePerDegree = BigDecimalUtils.safeDivide(summary.getServiceAmount(), summary.getUseElectricity(), 4); + BigDecimal gunAvgDailyChargeTimeMinutes = BigDecimalUtils.safeDivide(summary.getChargeTime(), connectorDayCount, 2); + BigDecimal avgPower = BigDecimalUtils.safeDivide( + summary.getUseElectricity().multiply(new BigDecimal("60")), + summary.getChargeTime(), + 4); + + return BusinessGunEfficiencyAnalysisVO.builder() + .startTime(range.getCurrentStart()) + .endTime(range.getCurrentEnd()) + .gunAvgDailyServiceFee(BigDecimalUtils.normalize(gunAvgDailyServiceFee)) + .gunAvgDailyElectricity(BigDecimalUtils.normalize(gunAvgDailyElectricity)) + .avgServiceFeePerDegree(BigDecimalUtils.normalize(avgServiceFeePerDegree)) + .gunAvgDailyChargeTime(formatMinutesToHourMinute(gunAvgDailyChargeTimeMinutes)) + .avgPower(BigDecimalUtils.normalize(avgPower)) + .build(); + } + /** * 构建当前选中指标对应的最大影响因素 * @@ -333,13 +388,29 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { * @return 实际查询站点ID列表 */ private List resolveStationIds(List stationIdList) { - if (!CollectionUtils.isEmpty(stationIdList)) { - return stationIdList; + List authorizedStationIds = getAuthorizedStationIds(); + if (authorizedStationIds == null) { + return CollectionUtils.isEmpty(stationIdList) ? null : stationIdList; } + if (!CollectionUtils.isEmpty(stationIdList)) { + return stationIdList.stream() + .filter(authorizedStationIds::contains) + .distinct() + .collect(Collectors.toList()); + } + return authorizedStationIds; + } + + /** + * 获取当前账号可访问的站点ID列表,平台账号返回null表示不限制 + * + * @return 站点ID列表 + */ + private List getAuthorizedStationIds() { try { AuthorizedDeptVO authorizedMap = UserUtils.getAuthorizedMap(); if (authorizedMap == null) { - return stationIdList; + return null; } if (!CollectionUtils.isEmpty(authorizedMap.getStationDeptIds())) { return pileStationInfoService.queryByStationDeptIds(authorizedMap.getStationDeptIds()); @@ -350,7 +421,7 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { } catch (Exception e) { log.warn("解析经营分析站点权限失败", e); } - return stationIdList; + return null; } /** @@ -364,6 +435,9 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { private BusinessOperationSummaryDTO buildOperationSummary(List stationIdList, String startTime, String endTime) { + if (stationIdList != null && stationIdList.isEmpty()) { + return new BusinessOperationSummaryDTO(); + } List reportList = settleOrderReportService.queryOrderReport( stationIdList, startTime, endTime); if (CollectionUtils.isEmpty(reportList)) { @@ -382,4 +456,48 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { summary.setAvgChargeTime(BigDecimalUtils.safeDivide(summary.getChargeTime(), summary.getOrderCount(), 2)); return summary; } + + /** + * 统计站点范围内的枪口数量 + * + * @param stationIdList 站点ID列表 + * @return 枪口数量 + */ + private int countConnectors(List stationIdList) { + if (stationIdList == null) { + return pileConnectorInfoService.selectPileConnectorInfoList(new PileConnectorInfo()).size(); + } + if (stationIdList.isEmpty()) { + return 0; + } + return pileConnectorInfoService.batchSelectConnectorList(stationIdList).size(); + } + + /** + * 计算包含起止日期在内的天数 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 天数 + */ + private long calculateInclusiveDays(String startTime, String endTime) { + LocalDate startDate = LocalDate.parse(startTime); + LocalDate endDate = LocalDate.parse(endTime); + return ChronoUnit.DAYS.between(startDate, endDate) + 1; + } + + /** + * 将分钟数转换为xxhxxm格式 + * + * @param minutes 分钟数 + * @return 格式化结果 + */ + private String formatMinutesToHourMinute(BigDecimal minutes) { + long totalMinutes = BigDecimalUtils.nullToZero(minutes) + .setScale(0, RoundingMode.HALF_UP) + .longValue(); + long hours = totalMinutes / 60; + long remainMinutes = totalMinutes % 60; + return String.format("%02dh%02dm", hours, remainMinutes); + } }