add 新增查询经营规模曲线图接口

This commit is contained in:
Lemon
2026-04-10 10:47:25 +08:00
parent 80a0f2ec22
commit 0eb86c999d
8 changed files with 547 additions and 11 deletions

View File

@@ -9,9 +9,11 @@ import com.jsowell.common.response.RestApiResponse;
import com.jsowell.pile.dto.MerchantOrderReportDTO;
import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO;
import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO;
import com.jsowell.pile.dto.business.BusinessScaleQueryDTO;
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.uniapp.business.BusinessOperationAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO;
import com.jsowell.pile.vo.web.MerchantOrderReportVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -120,28 +122,28 @@ public class BusinessFinancialController extends BaseController {
}
/**
* 查询枪均效率分析
* 查询经营规模
*
* @param dto 查询参数
* @return 枪均效率分析
* @return 经营规模数据(含指标卡片和曲线图)
*/
@PostMapping("/gunEfficiencyAnalysis")
public RestApiResponse<?> getBusinessGunEfficiencyAnalysis(@RequestBody BusinessOperationAnalysisQueryDTO dto) {
logger.info("查询枪均效率分析 params:{}", JSONObject.toJSONString(dto));
@PostMapping("/businessScale")
public RestApiResponse<?> getBusinessScale(@RequestBody BusinessScaleQueryDTO 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);
BusinessScaleVO result = businessFinancialService.getBusinessScale(dto);
response = new RestApiResponse<>(result);
logger.info("查询枪均效率分析成功 startTime:{}, endTime:{}",
dto.getStartTime(), dto.getEndTime());
logger.info("查询经营规模成功 startTime:{}, endTime:{}, selectedMetricCode:{}",
dto.getStartTime(), dto.getEndTime(), dto.getSelectedMetricCode());
} catch (BusinessException e) {
logger.warn("查询枪均效率分析业务异常 code:{}, message:{}", e.getCode(), e.getMessage(), 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);
logger.error("查询经营规模系统异常 params:{}", JSONObject.toJSONString(dto), e);
response = new RestApiResponse<>(e);
}
return response;

View File

@@ -0,0 +1,43 @@
package com.jsowell.pile.dto.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 经营规模查询DTO
*
* @author zhangziao
* @date 2026/4/10
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BusinessScaleQueryDTO {
/**
* 开始时间格式yyyy-MM-dd
*/
private String startTime;
/**
* 结束时间格式yyyy-MM-dd
*/
private String endTime;
/**
* 站点id列表
*/
private List<String> stationIdList;
/**
* 当前选中的指标编码,用于查询对应的曲线图数据
* ORDER_AMOUNT-订单总额, ORDER_COUNT-充电订单量,
* SERVICE_AMOUNT-充电服务费, USE_ELECTRICITY-充电电量
*/
private String selectedMetricCode;
}

View File

@@ -4,8 +4,10 @@ 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.dto.business.BusinessScaleQueryDTO;
import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO;
import com.jsowell.pile.vo.web.MerchantOrderReportVO;
import com.jsowell.pile.vo.web.ParkingCouponRecordVO;
@@ -35,4 +37,12 @@ public interface BusinessFinancialService {
* @return 枪均效率分析
*/
BusinessGunEfficiencyAnalysisVO getBusinessGunEfficiencyAnalysis(BusinessOperationAnalysisQueryDTO dto);
/**
* 查询经营规模
*
* @param dto 查询条件
* @return 经营规模数据(含指标卡片和曲线图)
*/
BusinessScaleVO getBusinessScale(BusinessScaleQueryDTO dto);
}

View File

@@ -15,6 +15,7 @@ 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.dto.business.BusinessScaleQueryDTO;
import com.jsowell.pile.domain.PileConnectorInfo;
import com.jsowell.pile.domain.SettleOrderReport;
import com.jsowell.pile.service.BusinessFinancialService;
@@ -28,6 +29,9 @@ 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;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleChartVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleMetricVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO;
import com.jsowell.pile.vo.web.MerchantOrderReportVO;
import com.jsowell.pile.vo.web.ParkingCouponRecordVO;
import lombok.extern.slf4j.Slf4j;
@@ -39,9 +43,12 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -59,6 +66,11 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService {
private static final String FACTOR_AVG_ELECTRICITY = "AVG_ELECTRICITY";
private static final String FACTOR_AVG_CHARGE_TIME = "AVG_CHARGE_TIME";
private static final String SCALE_METRIC_ORDER_AMOUNT = "ORDER_AMOUNT";
private static final String SCALE_METRIC_ORDER_COUNT = "ORDER_COUNT";
private static final String SCALE_METRIC_SERVICE_AMOUNT = "SERVICE_AMOUNT";
private static final String SCALE_METRIC_USE_ELECTRICITY = "USE_ELECTRICITY";
@Autowired
private SettleOrderReportService settleOrderReportService;
@@ -500,4 +512,233 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService {
long remainMinutes = totalMinutes % 60;
return String.format("%02dh%02dm", hours, remainMinutes);
}
/**
* 查询经营规模
*
* @param dto 查询条件
* @return 经营规模数据
*/
@Override
public BusinessScaleVO getBusinessScale(BusinessScaleQueryDTO 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 = buildDateRangeFromScale(dto);
List<String> stationIdList = resolveStationIds(dto.getStationIdList());
// 当前周期汇总
BusinessOperationSummaryDTO currentSummary = buildOperationSummary(
stationIdList, range.getCurrentStart(), range.getCurrentEnd());
// 上周期汇总
BusinessOperationSummaryDTO previousSummary = buildOperationSummary(
stationIdList, range.getPreviousStart(), range.getPreviousEnd());
// 构建指标卡片
List<BusinessScaleMetricVO> metricList = new ArrayList<>();
metricList.add(buildScaleMetric(SCALE_METRIC_ORDER_AMOUNT, "订单总额", "",
currentSummary.getOrderAmount(), previousSummary.getOrderAmount()));
metricList.add(buildScaleMetric(SCALE_METRIC_ORDER_COUNT, "充电订单量", "",
currentSummary.getOrderCount(), previousSummary.getOrderCount()));
metricList.add(buildScaleMetric(SCALE_METRIC_SERVICE_AMOUNT, "充电服务费", "",
currentSummary.getServiceAmount(), previousSummary.getServiceAmount()));
metricList.add(buildScaleMetric(SCALE_METRIC_USE_ELECTRICITY, "充电电量", "",
currentSummary.getUseElectricity(), previousSummary.getUseElectricity()));
// 构建选中指标的曲线图数据
String selectedMetricCode = StringUtils.isBlank(dto.getSelectedMetricCode())
? SCALE_METRIC_USE_ELECTRICITY : dto.getSelectedMetricCode();
BusinessScaleChartVO chartData = buildScaleChart(
selectedMetricCode, stationIdList, range);
return BusinessScaleVO.builder()
.currentStartTime(range.getCurrentStart())
.currentEndTime(range.getCurrentEnd())
.previousStartTime(range.getPreviousStart())
.previousEndTime(range.getPreviousEnd())
.metricList(metricList)
.chartData(chartData)
.build();
}
/**
* 构建经营规模日期区间
*/
private BusinessOperationDateRangeDTO buildDateRangeFromScale(BusinessScaleQueryDTO dto) {
try {
LocalDate currentStart = LocalDate.parse(dto.getStartTime());
LocalDate currentEnd = LocalDate.parse(dto.getEndTime());
if (currentEnd.isBefore(currentStart)) {
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
}
long days = ChronoUnit.DAYS.between(currentStart, currentEnd) + 1;
LocalDate previousEnd = currentStart.minusDays(1);
LocalDate previousStart = previousEnd.minusDays(days - 1);
return BusinessOperationDateRangeDTO.builder()
.currentStart(currentStart.toString())
.currentEnd(currentEnd.toString())
.previousStart(previousStart.toString())
.previousEnd(previousEnd.toString())
.build();
} catch (BusinessException e) {
throw e;
} catch (Exception e) {
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
}
}
/**
* 构建经营规模指标卡片
*/
private BusinessScaleMetricVO buildScaleMetric(String metricCode, String metricName, String unit,
BigDecimal currentValue, BigDecimal previousValue) {
BigDecimal safeCurrentValue = BigDecimalUtils.nullToZero(currentValue);
BigDecimal safePreviousValue = BigDecimalUtils.nullToZero(previousValue);
BigDecimal changeValue = BigDecimalUtils.normalize(safeCurrentValue.subtract(safePreviousValue));
return BusinessScaleMetricVO.builder()
.metricCode(metricCode)
.metricName(metricName)
.unit(unit)
.currentValue(BigDecimalUtils.normalize(safeCurrentValue))
.previousValue(BigDecimalUtils.normalize(safePreviousValue))
.changeValue(changeValue)
.changeRate(BigDecimalUtils.calculateRate(safeCurrentValue, safePreviousValue))
.build();
}
/**
* 构建经营规模曲线图数据
*/
private BusinessScaleChartVO buildScaleChart(String metricCode, List<String> stationIdList,
BusinessOperationDateRangeDTO range) {
String metricName;
String unit;
switch (metricCode) {
case SCALE_METRIC_ORDER_AMOUNT:
metricName = "订单总额";
unit = "";
break;
case SCALE_METRIC_ORDER_COUNT:
metricName = "充电订单量";
unit = "";
break;
case SCALE_METRIC_SERVICE_AMOUNT:
metricName = "充电服务费";
unit = "";
break;
default:
metricName = "充电电量";
unit = "";
break;
}
// 查询当前周期每日数据
Map<String, SettleOrderReport> currentDailyMap = queryDailyReportMap(
stationIdList, range.getCurrentStart(), range.getCurrentEnd());
// 查询上周期每日数据
Map<String, SettleOrderReport> previousDailyMap = queryDailyReportMap(
stationIdList, range.getPreviousStart(), range.getPreviousEnd());
LocalDate currentStart = LocalDate.parse(range.getCurrentStart());
LocalDate currentEnd = LocalDate.parse(range.getCurrentEnd());
LocalDate previousStart = LocalDate.parse(range.getPreviousStart());
long dayCount = ChronoUnit.DAYS.between(currentStart, currentEnd) + 1;
DateTimeFormatter displayFormatter = DateTimeFormatter.ofPattern("MM/dd");
List<BusinessScaleChartVO.ChartPoint> chartPoints = new ArrayList<>();
for (long i = 0; i < dayCount; i++) {
LocalDate currentDate = currentStart.plusDays(i);
LocalDate previousDate = previousStart.plusDays(i);
String dateKey = currentDate.toString();
SettleOrderReport currentReport = currentDailyMap.get(dateKey);
SettleOrderReport previousReport = previousDailyMap.get(previousDate.toString());
BigDecimal currentValue = extractMetricValue(metricCode, currentReport);
BigDecimal previousValue = extractMetricValue(metricCode, previousReport);
chartPoints.add(BusinessScaleChartVO.ChartPoint.builder()
.date(currentDate.format(displayFormatter))
.fullDate(dateKey)
.value(BigDecimalUtils.normalize(currentValue))
.previousValue(BigDecimalUtils.normalize(previousValue))
.changeRate(BigDecimalUtils.calculateRate(
BigDecimalUtils.nullToZero(currentValue),
BigDecimalUtils.nullToZero(previousValue)))
.build());
}
return BusinessScaleChartVO.builder()
.metricCode(metricCode)
.metricName(metricName)
.unit(unit)
.chartData(chartPoints)
.build();
}
/**
* 查询每日报表数据按日期分组返回Map
*/
private Map<String, SettleOrderReport> queryDailyReportMap(List<String> stationIdList,
String startTime, String endTime) {
if (stationIdList != null && stationIdList.isEmpty()) {
return new LinkedHashMap<>();
}
List<SettleOrderReport> reportList = settleOrderReportService.queryOrderReport(
stationIdList, startTime, endTime);
// 按tradeDate分组汇总
Map<String, SettleOrderReport> dailyMap = new LinkedHashMap<>();
if (!CollectionUtils.isEmpty(reportList)) {
for (SettleOrderReport report : reportList) {
String tradeDate = report.getTradeDate();
if (StringUtils.isBlank(tradeDate)) {
continue;
}
SettleOrderReport existing = dailyMap.get(tradeDate);
if (existing == null) {
dailyMap.put(tradeDate, report);
} else {
// 合并同一天多个站点的数据
existing.setTotalAmount(existing.getTotalAmount().add(
BigDecimalUtils.nullToZero(report.getTotalAmount())));
existing.setServiceAmount(existing.getServiceAmount().add(
BigDecimalUtils.nullToZero(report.getServiceAmount())));
existing.setUseElectricity(existing.getUseElectricity().add(
BigDecimalUtils.nullToZero(report.getUseElectricity())));
existing.setChargeNum(String.valueOf(
BigDecimalUtils.parseOrZero(existing.getChargeNum())
.add(BigDecimalUtils.parseOrZero(report.getChargeNum()))));
}
}
}
return dailyMap;
}
/**
* 从报表记录中提取指定指标的值
*/
private BigDecimal extractMetricValue(String metricCode, SettleOrderReport report) {
if (report == null) {
return BigDecimal.ZERO;
}
switch (metricCode) {
case SCALE_METRIC_ORDER_AMOUNT:
return BigDecimalUtils.nullToZero(report.getTotalAmount());
case SCALE_METRIC_ORDER_COUNT:
return BigDecimalUtils.parseOrZero(report.getChargeNum());
case SCALE_METRIC_SERVICE_AMOUNT:
return BigDecimalUtils.nullToZero(report.getServiceAmount());
case SCALE_METRIC_USE_ELECTRICITY:
default:
return BigDecimalUtils.nullToZero(report.getUseElectricity());
}
}
}

View File

@@ -0,0 +1,56 @@
package com.jsowell.pile.vo.uniapp.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 枪均效率分析VO
*
* @author Auto
* @Date 2026/4/3
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BusinessGunEfficiencyAnalysisVO {
/**
* 开始时间
*/
private String startTime;
/**
* 结束时间
*/
private String endTime;
/**
* 枪日均服务费(元)
*/
private BigDecimal gunAvgDailyServiceFee;
/**
* 枪日均充电量(度)
*/
private BigDecimal gunAvgDailyElectricity;
/**
* 度均服务费(元)
*/
private BigDecimal avgServiceFeePerDegree;
/**
* 枪日均充电时长格式xxhxxm
*/
private String gunAvgDailyChargeTime;
/**
* 平均功率(KW)
*/
private BigDecimal avgPower;
}

View File

@@ -0,0 +1,77 @@
package com.jsowell.pile.vo.uniapp.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
/**
* 经营规模曲线图数据VO
*
* @author zhangziao
* @date 2026/4/10
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BusinessScaleChartVO {
/**
* 指标编码
*/
private String metricCode;
/**
* 指标名称
*/
private String metricName;
/**
* 指标单位
*/
private String unit;
/**
* 曲线图数据点列表
*/
private List<ChartPoint> chartData;
/**
* 曲线图单个数据点
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class ChartPoint {
/**
* 日期格式MM/dd
*/
private String date;
/**
* 完整日期格式yyyy-MM-dd
*/
private String fullDate;
/**
* 当前周期值
*/
private BigDecimal value;
/**
* 上周期同日值
*/
private BigDecimal previousValue;
/**
* 环比
*/
private String changeRate;
}
}

View File

@@ -0,0 +1,56 @@
package com.jsowell.pile.vo.uniapp.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 经营规模指标卡片VO
*
* @author zhangziao
* @date 2026/4/10
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BusinessScaleMetricVO {
/**
* 指标编码
*/
private String metricCode;
/**
* 指标名称
*/
private String metricName;
/**
* 指标单位
*/
private String unit;
/**
* 当前周期值
*/
private BigDecimal currentValue;
/**
* 上周期值
*/
private BigDecimal previousValue;
/**
* 变化值
*/
private BigDecimal changeValue;
/**
* 环比,格式如 +3.91% 或 -3.91%
*/
private String changeRate;
}

View File

@@ -0,0 +1,51 @@
package com.jsowell.pile.vo.uniapp.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 经营规模VO
*
* @author zhangziao
* @date 2026/4/10
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BusinessScaleVO {
/**
* 当前周期开始时间
*/
private String currentStartTime;
/**
* 当前周期结束时间
*/
private String currentEndTime;
/**
* 上周期开始时间
*/
private String previousStartTime;
/**
* 上周期结束时间
*/
private String previousEndTime;
/**
* 指标卡片列表(订单总额、充电订单量、充电服务费、充电电量)
*/
private List<BusinessScaleMetricVO> metricList;
/**
* 当前选中指标对应的曲线图数据
*/
private BusinessScaleChartVO chartData;
}