mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-08-12 09:13:48 +08:00
创建service
This commit is contained in:
@@ -5,33 +5,20 @@ import com.jsowell.common.core.controller.BaseController;
|
|||||||
import com.jsowell.common.response.RestApiResponse;
|
import com.jsowell.common.response.RestApiResponse;
|
||||||
import com.jsowell.common.util.StringUtils;
|
import com.jsowell.common.util.StringUtils;
|
||||||
import com.jsowell.pile.dto.IndexQueryDTO;
|
import com.jsowell.pile.dto.IndexQueryDTO;
|
||||||
import com.jsowell.pile.service.MemberBasicInfoService;
|
import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO;
|
||||||
|
import com.jsowell.pile.service.IndexDataService;
|
||||||
|
import com.jsowell.pile.service.BusinessFinancialService;
|
||||||
import com.jsowell.pile.service.OrderBasicInfoService;
|
import com.jsowell.pile.service.OrderBasicInfoService;
|
||||||
import com.jsowell.pile.service.PileBasicInfoService;
|
import com.jsowell.pile.service.PileBasicInfoService;
|
||||||
import com.jsowell.pile.service.PileConnectorInfoService;
|
|
||||||
import com.jsowell.pile.service.PileStationInfoService;
|
import com.jsowell.pile.service.PileStationInfoService;
|
||||||
import com.jsowell.pile.service.PileMerchantInfoService;
|
|
||||||
import com.jsowell.pile.service.BusinessFinancialService;
|
|
||||||
import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO;
|
|
||||||
import com.jsowell.pile.util.UserUtils;
|
|
||||||
import com.jsowell.pile.vo.web.*;
|
import com.jsowell.pile.vo.web.*;
|
||||||
import com.jsowell.common.core.domain.vo.AuthorizedDeptVO;
|
|
||||||
import com.jsowell.common.util.SecurityUtils;
|
|
||||||
import com.jsowell.common.constant.Constants;
|
|
||||||
import com.jsowell.pile.domain.PileMerchantInfo;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 首页数据展示Controller
|
* 首页数据展示Controller
|
||||||
@@ -48,23 +35,14 @@ public class indexController extends BaseController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private OrderBasicInfoService orderBasicInfoService;
|
private OrderBasicInfoService orderBasicInfoService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private MemberBasicInfoService memberBasicInfoService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PileStationInfoService pileStationInfoService;
|
private PileStationInfoService pileStationInfoService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private PileConnectorInfoService pileConnectorInfoService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private PileMerchantInfoService pileMerchantInfoService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private BusinessFinancialService businessFinancialService;
|
private BusinessFinancialService businessFinancialService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Executor threadPoolTaskExecutor;
|
private IndexDataService indexDataService;
|
||||||
|
|
||||||
@PostMapping("/getGeneralSituation")
|
@PostMapping("/getGeneralSituation")
|
||||||
public RestApiResponse<?> getGeneralSituation(@RequestBody IndexQueryDTO dto) {
|
public RestApiResponse<?> getGeneralSituation(@RequestBody IndexQueryDTO dto) {
|
||||||
@@ -141,7 +119,7 @@ public class indexController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 大数据平台-总览数据(性能优化版)
|
* 大数据平台-总览数据(性能优化版)
|
||||||
* 权限解析在主线程完成,按merchantId或stationId维度查询,不用SQL SUM,Java汇总
|
* 业务逻辑在IndexDataService中实现
|
||||||
*/
|
*/
|
||||||
@PostMapping("/getBigDataOverview")
|
@PostMapping("/getBigDataOverview")
|
||||||
public RestApiResponse<?> getBigDataOverview(@RequestBody(required = false) IndexQueryDTO dto) {
|
public RestApiResponse<?> getBigDataOverview(@RequestBody(required = false) IndexQueryDTO dto) {
|
||||||
@@ -149,168 +127,7 @@ public class indexController extends BaseController {
|
|||||||
logger.info("大数据平台总览数据查询 param:{}", JSON.toJSONString(dto));
|
logger.info("大数据平台总览数据查询 param:{}", JSON.toJSONString(dto));
|
||||||
RestApiResponse<?> response;
|
RestApiResponse<?> response;
|
||||||
try {
|
try {
|
||||||
BigDataOverviewVO overviewVO = new BigDataOverviewVO();
|
BigDataOverviewVO overviewVO = indexDataService.getOverview();
|
||||||
|
|
||||||
// === 第一步:主线程做权限解析(依赖SecurityContext,不可异步) ===
|
|
||||||
// 平台管理员:merchantIdList为空,直接查全量(不加任何过滤)
|
|
||||||
// 运营商管理员:使用merchantId维度
|
|
||||||
// 站点管理员:使用stationId维度
|
|
||||||
AuthParams authParams = resolveAuthParams();
|
|
||||||
|
|
||||||
// demo账号标记
|
|
||||||
boolean isDemo = false;
|
|
||||||
try {
|
|
||||||
isDemo = "demo".equals(SecurityUtils.getUsername());
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
|
|
||||||
// === 第二步:所有DB查询并行执行 ===
|
|
||||||
final List<String> finalMerchantIdList = authParams.merchantIdList;
|
|
||||||
final List<String> finalStationIdList = authParams.stationIdList;
|
|
||||||
final boolean isPlatformAdmin = authParams.isPlatformAdmin;
|
|
||||||
|
|
||||||
// 带权限过滤的查询:根据账号级别选择维度
|
|
||||||
CompletableFuture<IndexGeneralSituationVO> situationFuture;
|
|
||||||
|
|
||||||
if (isPlatformAdmin) {
|
|
||||||
// 平台管理员:直接查全量,不加merchant_id/station_id过滤
|
|
||||||
situationFuture = CompletableFuture.supplyAsync(
|
|
||||||
() -> pileBasicInfoService.aggregateReportByMerchantIds(null), threadPoolTaskExecutor);
|
|
||||||
} else if (!CollectionUtils.isEmpty(finalMerchantIdList)) {
|
|
||||||
// 运营商管理员:按merchantId查
|
|
||||||
final List<String> midList = finalMerchantIdList;
|
|
||||||
situationFuture = CompletableFuture.supplyAsync(
|
|
||||||
() -> pileBasicInfoService.aggregateReportByMerchantIds(midList), threadPoolTaskExecutor);
|
|
||||||
} else if (!CollectionUtils.isEmpty(finalStationIdList)) {
|
|
||||||
// 站点管理员:按stationId查
|
|
||||||
final List<String> sidList = finalStationIdList;
|
|
||||||
situationFuture = CompletableFuture.supplyAsync(
|
|
||||||
() -> pileBasicInfoService.aggregateReportByStationIds(sidList), threadPoolTaskExecutor);
|
|
||||||
} else {
|
|
||||||
// 非平台管理员但未解析出任何可查维度(商户未绑定/部门下无站点):
|
|
||||||
// 返回空数据,避免空列表退化为无过滤的全量查询导致越权
|
|
||||||
logger.warn("大数据平台总览数据查询:当前账号无任何可查的商户/站点维度,返回空数据");
|
|
||||||
situationFuture = CompletableFuture.completedFuture(emptySituationVO());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数据范围:平台管理员不限制(null),下级账号按各自的merchantIdList/stationIdList过滤
|
|
||||||
final boolean hasDataScope = isPlatformAdmin
|
|
||||||
|| !CollectionUtils.isEmpty(finalMerchantIdList)
|
|
||||||
|| !CollectionUtils.isEmpty(finalStationIdList);
|
|
||||||
final List<String> scopeMerchantIds = isPlatformAdmin ? null : finalMerchantIdList;
|
|
||||||
final List<String> scopeStationIds = isPlatformAdmin ? null : finalStationIdList;
|
|
||||||
|
|
||||||
// 其余指标查询(与累计字段同一数据范围;日期在代码中生成,不在数据库中运算)
|
|
||||||
java.time.LocalDate today = java.time.LocalDate.now();
|
|
||||||
String todayStart = today.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
|
|
||||||
String todayEnd = today.plusDays(1).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
|
|
||||||
String monthStart = today.withDayOfMonth(1).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
|
||||||
String monthEnd = today.plusDays(1).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
|
||||||
final String fTodayStart = todayStart;
|
|
||||||
final String fTodayEnd = todayEnd;
|
|
||||||
final String fMonthStart = monthStart;
|
|
||||||
final String fMonthEnd = monthEnd;
|
|
||||||
|
|
||||||
CompletableFuture<Long> totalUsersFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> memberBasicInfoService.countTotalMembers(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(0L);
|
|
||||||
CompletableFuture<Long> totalStationsFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> pileStationInfoService.countTotalStations(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(0L);
|
|
||||||
CompletableFuture<Long> dailyNewUsersFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> memberBasicInfoService.countTodayNewMembers(fTodayStart, fTodayEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(0L);
|
|
||||||
CompletableFuture<BigDecimal> todayAmountFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> orderBasicInfoService.getTodayTransactionAmount(fTodayStart, fTodayEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(java.math.BigDecimal.ZERO);
|
|
||||||
CompletableFuture<BigDecimal> todayElecFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> orderBasicInfoService.getTodayElectricity(fTodayStart, fTodayEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(java.math.BigDecimal.ZERO);
|
|
||||||
CompletableFuture<BigDecimal> monthlyAvgFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> pileBasicInfoService.getMonthlyAvgElectricity(fMonthStart, fMonthEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(java.math.BigDecimal.ZERO);
|
|
||||||
CompletableFuture<Long> totalGunsFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> pileConnectorInfoService.countTotalConnectors(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(0L);
|
|
||||||
CompletableFuture<Long> onlinePilesFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> pileConnectorInfoService.countOnlinePiles(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(0L);
|
|
||||||
// 充电桩数量统计:总数/直流/交流同源(保证 直流 + 交流 = 总数)
|
|
||||||
CompletableFuture<PileCountStatVO> pilesStatFuture = hasDataScope
|
|
||||||
? CompletableFuture.supplyAsync(
|
|
||||||
() -> pileBasicInfoService.countPilesStat(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
|
||||||
: CompletableFuture.completedFuture(new PileCountStatVO());
|
|
||||||
|
|
||||||
// 等待所有异步查询完成
|
|
||||||
CompletableFuture.allOf(
|
|
||||||
situationFuture,
|
|
||||||
totalUsersFuture, totalStationsFuture, dailyNewUsersFuture,
|
|
||||||
todayAmountFuture, todayElecFuture, monthlyAvgFuture,
|
|
||||||
totalGunsFuture, onlinePilesFuture, pilesStatFuture
|
|
||||||
).join();
|
|
||||||
|
|
||||||
// === 第三步:组装结果 ===
|
|
||||||
IndexGeneralSituationVO situation = situationFuture.get();
|
|
||||||
String totalChargingAmount = situation.getTotalChargingAmount();
|
|
||||||
String totalChargingDegree = situation.getTotalChargingDegree();
|
|
||||||
PileCountStatVO pilesStat = pilesStatFuture.get();
|
|
||||||
Long totalPileCount = pilesStat != null ? pilesStat.getTotalPiles() : null;
|
|
||||||
Long dcPileCount = pilesStat != null ? pilesStat.getDcPileCount() : null;
|
|
||||||
Long acPileCount = pilesStat != null ? pilesStat.getAcPileCount() : null;
|
|
||||||
|
|
||||||
// 总订单数从settle_order_report的GROUP BY结果中获取(charge_num汇总)
|
|
||||||
String totalOrderCountStr = situation.getTotalChargingQuantity();
|
|
||||||
Long totalOrderCount = (totalOrderCountStr != null && !totalOrderCountStr.isEmpty())
|
|
||||||
? Long.parseLong(totalOrderCountStr.replaceAll("[.](.*)", "")) : 0L;
|
|
||||||
|
|
||||||
overviewVO.setTotalUsers(totalUsersFuture.get());
|
|
||||||
overviewVO.setTotalOrders(totalOrderCount);
|
|
||||||
overviewVO.setTotalTransactionAmount(totalChargingAmount);
|
|
||||||
overviewVO.setTotalElectricity(totalChargingDegree);
|
|
||||||
overviewVO.setTotalPiles(totalPileCount != null ? totalPileCount : 0L);
|
|
||||||
overviewVO.setTotalStations(totalStationsFuture.get());
|
|
||||||
overviewVO.setDailyNewUsers(dailyNewUsersFuture.get());
|
|
||||||
BigDecimal todayAmount = todayAmountFuture.get();
|
|
||||||
overviewVO.setTodayTransactionAmount(todayAmount != null ? todayAmount.toPlainString() : "0");
|
|
||||||
BigDecimal todayElec = todayElecFuture.get();
|
|
||||||
overviewVO.setTodayElectricity(todayElec != null ? todayElec.toPlainString() : "0");
|
|
||||||
BigDecimal monthlyAvg = monthlyAvgFuture.get();
|
|
||||||
overviewVO.setMonthlyAvgElectricity(monthlyAvg != null ? monthlyAvg.toPlainString() : "0");
|
|
||||||
overviewVO.setTotalGuns(totalGunsFuture.get());
|
|
||||||
overviewVO.setOnlinePiles(onlinePilesFuture.get());
|
|
||||||
overviewVO.setDcPileCount(dcPileCount != null ? dcPileCount : 0L);
|
|
||||||
overviewVO.setAcPileCount(acPileCount != null ? acPileCount : 0L);
|
|
||||||
|
|
||||||
// 节能减排计算
|
|
||||||
BigDecimal totalElecKwh = new BigDecimal(totalChargingDegree);
|
|
||||||
BigDecimal carbonKg = totalElecKwh.multiply(new BigDecimal("0.5306"));
|
|
||||||
BigDecimal carbonTon = carbonKg.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP);
|
|
||||||
overviewVO.setCarbonReduction(carbonTon.toPlainString());
|
|
||||||
if (totalOrderCount != null && totalOrderCount > 0) {
|
|
||||||
BigDecimal avgCarbon = carbonKg.divide(new BigDecimal(totalOrderCount), 2, RoundingMode.HALF_UP);
|
|
||||||
overviewVO.setAvgCarbonPerOrder(avgCarbon.toPlainString());
|
|
||||||
} else {
|
|
||||||
overviewVO.setAvgCarbonPerOrder("0");
|
|
||||||
}
|
|
||||||
BigDecimal fuelSaved = totalElecKwh.multiply(new BigDecimal("8"))
|
|
||||||
.divide(new BigDecimal("15"), 2, RoundingMode.HALF_UP);
|
|
||||||
overviewVO.setFuelSaved(fuelSaved.toPlainString());
|
|
||||||
BigDecimal coalSaved = totalElecKwh.multiply(new BigDecimal("0.000404"))
|
|
||||||
.setScale(2, RoundingMode.HALF_UP);
|
|
||||||
overviewVO.setStandardCoalSaved(coalSaved.toPlainString());
|
|
||||||
|
|
||||||
// demo账号展示效果处理(节能减排基于处理后的电量/订单数重算)
|
|
||||||
if (isDemo) {
|
|
||||||
applyDemoEffect(overviewVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
response = new RestApiResponse<>(overviewVO);
|
response = new RestApiResponse<>(overviewVO);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("大数据平台总览数据查询错误", e);
|
logger.error("大数据平台总览数据查询错误", e);
|
||||||
@@ -319,114 +136,6 @@ public class indexController extends BaseController {
|
|||||||
logger.info("大数据平台总览数据查询 result:{}", JSON.toJSONString(response));
|
logger.info("大数据平台总览数据查询 result:{}", JSON.toJSONString(response));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 权限参数内部类
|
|
||||||
*/
|
|
||||||
private static class AuthParams {
|
|
||||||
boolean isPlatformAdmin = false;
|
|
||||||
List<String> merchantIdList = new ArrayList<>();
|
|
||||||
List<String> stationIdList = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析当前用户权限参数
|
|
||||||
* - 平台管理员:标记isPlatformAdmin=true,不需要任何过滤条件
|
|
||||||
* - 运营商管理员:根据deptId获取merchantId
|
|
||||||
* - 站点管理员:使用stationId
|
|
||||||
*/
|
|
||||||
private AuthParams resolveAuthParams() {
|
|
||||||
AuthParams params = new AuthParams();
|
|
||||||
AuthorizedDeptVO authorizedMap = UserUtils.getAuthorizedMap();
|
|
||||||
if (authorizedMap == null) {
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
List<String> stationDeptIds = authorizedMap.getStationDeptIds();
|
|
||||||
List<String> merchantDeptIds = authorizedMap.getMerchantDeptIds();
|
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(stationDeptIds)) {
|
|
||||||
// 站点管理员:使用站点维度
|
|
||||||
List<String> list = pileStationInfoService.queryByStationDeptIds(stationDeptIds);
|
|
||||||
if (!CollectionUtils.isEmpty(list)) {
|
|
||||||
params.stationIdList.addAll(list);
|
|
||||||
}
|
|
||||||
} else if (!CollectionUtils.isEmpty(merchantDeptIds)) {
|
|
||||||
// 运营商管理员:根据deptId获取merchantId
|
|
||||||
for (String deptId : merchantDeptIds) {
|
|
||||||
PileMerchantInfo merchant = pileMerchantInfoService.queryInfoByDeptId(deptId);
|
|
||||||
if (merchant != null && merchant.getId() != null) {
|
|
||||||
params.merchantIdList.add(String.valueOf(merchant.getId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 平台管理员:直接查全量,不需要任何过滤
|
|
||||||
params.isPlatformAdmin = true;
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 空权限维度时的占位汇总数据(全为0,避免下游NPE)
|
|
||||||
*/
|
|
||||||
private static IndexGeneralSituationVO emptySituationVO() {
|
|
||||||
IndexGeneralSituationVO vo = new IndexGeneralSituationVO();
|
|
||||||
vo.setTotalChargingAmount("0");
|
|
||||||
vo.setTotalSettleAmount("0");
|
|
||||||
vo.setTotalChargingDegree("0");
|
|
||||||
vo.setTotalChargingQuantity("0");
|
|
||||||
return vo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* demo账号展示效果处理
|
|
||||||
* 所有总量类指标(用户、订单、金额、电量、站点、桩、枪等)按统一倍数调整,保证各维度数据比例一致;
|
|
||||||
* 节能减排基于调整后的累计电量/订单数重算,其中"单次充电平均减碳量"为比值型指标,调整后保持不变
|
|
||||||
*/
|
|
||||||
private static void applyDemoEffect(BigDataOverviewVO vo) {
|
|
||||||
BigDecimal multiplier = new BigDecimal(Constants.THREE);
|
|
||||||
vo.setTotalUsers(multiply(vo.getTotalUsers(), multiplier));
|
|
||||||
vo.setTotalOrders(multiply(vo.getTotalOrders(), multiplier));
|
|
||||||
vo.setTotalTransactionAmount(multiply(vo.getTotalTransactionAmount(), multiplier));
|
|
||||||
vo.setTotalElectricity(multiply(vo.getTotalElectricity(), multiplier));
|
|
||||||
vo.setTotalPiles(multiply(vo.getTotalPiles(), multiplier));
|
|
||||||
vo.setTotalStations(multiply(vo.getTotalStations(), multiplier));
|
|
||||||
vo.setDailyNewUsers(multiply(vo.getDailyNewUsers(), multiplier));
|
|
||||||
vo.setTodayTransactionAmount(multiply(vo.getTodayTransactionAmount(), multiplier));
|
|
||||||
vo.setTodayElectricity(multiply(vo.getTodayElectricity(), multiplier));
|
|
||||||
vo.setMonthlyAvgElectricity(multiply(vo.getMonthlyAvgElectricity(), multiplier));
|
|
||||||
vo.setTotalGuns(multiply(vo.getTotalGuns(), multiplier));
|
|
||||||
vo.setOnlinePiles(multiply(vo.getOnlinePiles(), multiplier));
|
|
||||||
vo.setDcPileCount(multiply(vo.getDcPileCount(), multiplier));
|
|
||||||
vo.setAcPileCount(multiply(vo.getAcPileCount(), multiplier));
|
|
||||||
|
|
||||||
// 节能减排按调整后的累计电量/订单数重算
|
|
||||||
BigDecimal totalElecKwh = new BigDecimal(vo.getTotalElectricity());
|
|
||||||
BigDecimal carbonKg = totalElecKwh.multiply(new BigDecimal("0.5306"));
|
|
||||||
BigDecimal carbonTon = carbonKg.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP);
|
|
||||||
vo.setCarbonReduction(carbonTon.toPlainString());
|
|
||||||
Long totalOrderCount = vo.getTotalOrders();
|
|
||||||
if (totalOrderCount != null && totalOrderCount > 0) {
|
|
||||||
BigDecimal avgCarbon = carbonKg.divide(new BigDecimal(totalOrderCount), 2, RoundingMode.HALF_UP);
|
|
||||||
vo.setAvgCarbonPerOrder(avgCarbon.toPlainString());
|
|
||||||
} else {
|
|
||||||
vo.setAvgCarbonPerOrder("0");
|
|
||||||
}
|
|
||||||
BigDecimal fuelSaved = totalElecKwh.multiply(new BigDecimal("8"))
|
|
||||||
.divide(new BigDecimal("15"), 2, RoundingMode.HALF_UP);
|
|
||||||
vo.setFuelSaved(fuelSaved.toPlainString());
|
|
||||||
BigDecimal coalSaved = totalElecKwh.multiply(new BigDecimal("0.000404"))
|
|
||||||
.setScale(2, RoundingMode.HALF_UP);
|
|
||||||
vo.setStandardCoalSaved(coalSaved.toPlainString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Long multiply(Long value, BigDecimal multiplier) {
|
|
||||||
return value == null ? null : new BigDecimal(value).multiply(multiplier).longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String multiply(String value, BigDecimal multiplier) {
|
|
||||||
return value == null ? null : new BigDecimal(value).multiply(multiplier).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 大数据平台-充电站地图数据
|
* 大数据平台-充电站地图数据
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.jsowell.pile.service;
|
||||||
|
|
||||||
|
import com.jsowell.pile.vo.web.BigDataOverviewVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页数据Service(供indexController使用)
|
||||||
|
* 大数据平台-总览数据
|
||||||
|
*
|
||||||
|
* @author jsowell
|
||||||
|
*/
|
||||||
|
public interface IndexDataService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取大数据平台总览数据
|
||||||
|
* 权限解析依赖SecurityContext(不可异步),按当前登录账号的商户/站点维度过滤;
|
||||||
|
* 所有指标与累计字段使用同一数据范围,保证口径一致
|
||||||
|
*
|
||||||
|
* @return 总览数据
|
||||||
|
*/
|
||||||
|
BigDataOverviewVO getOverview();
|
||||||
|
}
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
package com.jsowell.pile.service.impl;
|
||||||
|
|
||||||
|
import com.jsowell.common.constant.Constants;
|
||||||
|
import com.jsowell.common.core.domain.vo.AuthorizedDeptVO;
|
||||||
|
import com.jsowell.common.util.SecurityUtils;
|
||||||
|
import com.jsowell.pile.domain.PileMerchantInfo;
|
||||||
|
import com.jsowell.pile.service.IndexDataService;
|
||||||
|
import com.jsowell.pile.service.MemberBasicInfoService;
|
||||||
|
import com.jsowell.pile.service.OrderBasicInfoService;
|
||||||
|
import com.jsowell.pile.service.PileBasicInfoService;
|
||||||
|
import com.jsowell.pile.service.PileConnectorInfoService;
|
||||||
|
import com.jsowell.pile.service.PileMerchantInfoService;
|
||||||
|
import com.jsowell.pile.service.PileStationInfoService;
|
||||||
|
import com.jsowell.pile.util.UserUtils;
|
||||||
|
import com.jsowell.pile.vo.web.BigDataOverviewVO;
|
||||||
|
import com.jsowell.pile.vo.web.IndexGeneralSituationVO;
|
||||||
|
import com.jsowell.pile.vo.web.PileCountStatVO;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页数据Service(供indexController使用)- 大数据平台总览数据(性能优化版)
|
||||||
|
* 权限解析在主线程完成,按merchantId或stationId维度查询,不用SQL SUM,Java汇总
|
||||||
|
*
|
||||||
|
* @author jsowell
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class IndexDataServiceImpl implements IndexDataService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PileBasicInfoService pileBasicInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderBasicInfoService orderBasicInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MemberBasicInfoService memberBasicInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PileStationInfoService pileStationInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PileConnectorInfoService pileConnectorInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PileMerchantInfoService pileMerchantInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Executor threadPoolTaskExecutor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDataOverviewVO getOverview() {
|
||||||
|
BigDataOverviewVO overviewVO = new BigDataOverviewVO();
|
||||||
|
|
||||||
|
// === 第一步:主线程做权限解析(依赖SecurityContext,不可异步) ===
|
||||||
|
// 平台管理员:merchantIdList为空,直接查全量(不加任何过滤)
|
||||||
|
// 运营商管理员:使用merchantId维度
|
||||||
|
// 站点管理员:使用stationId维度
|
||||||
|
AuthParams authParams = resolveAuthParams();
|
||||||
|
|
||||||
|
// demo账号标记
|
||||||
|
boolean isDemo = false;
|
||||||
|
try {
|
||||||
|
isDemo = "demo".equals(SecurityUtils.getUsername());
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
// === 第二步:所有DB查询并行执行 ===
|
||||||
|
final List<String> finalMerchantIdList = authParams.merchantIdList;
|
||||||
|
final List<String> finalStationIdList = authParams.stationIdList;
|
||||||
|
final boolean isPlatformAdmin = authParams.isPlatformAdmin;
|
||||||
|
|
||||||
|
// 带权限过滤的查询:根据账号级别选择维度
|
||||||
|
CompletableFuture<IndexGeneralSituationVO> situationFuture;
|
||||||
|
|
||||||
|
if (isPlatformAdmin) {
|
||||||
|
// 平台管理员:直接查全量,不加merchant_id/station_id过滤
|
||||||
|
situationFuture = CompletableFuture.supplyAsync(
|
||||||
|
() -> pileBasicInfoService.aggregateReportByMerchantIds(null), threadPoolTaskExecutor);
|
||||||
|
} else if (!CollectionUtils.isEmpty(finalMerchantIdList)) {
|
||||||
|
// 运营商管理员:按merchantId查
|
||||||
|
final List<String> midList = finalMerchantIdList;
|
||||||
|
situationFuture = CompletableFuture.supplyAsync(
|
||||||
|
() -> pileBasicInfoService.aggregateReportByMerchantIds(midList), threadPoolTaskExecutor);
|
||||||
|
} else if (!CollectionUtils.isEmpty(finalStationIdList)) {
|
||||||
|
// 站点管理员:按stationId查
|
||||||
|
final List<String> sidList = finalStationIdList;
|
||||||
|
situationFuture = CompletableFuture.supplyAsync(
|
||||||
|
() -> pileBasicInfoService.aggregateReportByStationIds(sidList), threadPoolTaskExecutor);
|
||||||
|
} else {
|
||||||
|
// 非平台管理员但未解析出任何可查维度(商户未绑定/部门下无站点):
|
||||||
|
// 返回空数据,避免空列表退化为无过滤的全量查询导致越权
|
||||||
|
log.warn("大数据平台总览数据查询:当前账号无任何可查的商户/站点维度,返回空数据");
|
||||||
|
situationFuture = CompletableFuture.completedFuture(emptySituationVO());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据范围:平台管理员不限制(null),下级账号按各自的merchantIdList/stationIdList过滤
|
||||||
|
final boolean hasDataScope = isPlatformAdmin
|
||||||
|
|| !CollectionUtils.isEmpty(finalMerchantIdList)
|
||||||
|
|| !CollectionUtils.isEmpty(finalStationIdList);
|
||||||
|
final List<String> scopeMerchantIds = isPlatformAdmin ? null : finalMerchantIdList;
|
||||||
|
final List<String> scopeStationIds = isPlatformAdmin ? null : finalStationIdList;
|
||||||
|
|
||||||
|
// 其余指标查询(与累计字段同一数据范围;日期在代码中生成,不在数据库中运算)
|
||||||
|
java.time.LocalDate today = java.time.LocalDate.now();
|
||||||
|
String todayStart = today.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
|
||||||
|
String todayEnd = today.plusDays(1).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
|
||||||
|
String monthStart = today.withDayOfMonth(1).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
|
String monthEnd = today.plusDays(1).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
|
final String fTodayStart = todayStart;
|
||||||
|
final String fTodayEnd = todayEnd;
|
||||||
|
final String fMonthStart = monthStart;
|
||||||
|
final String fMonthEnd = monthEnd;
|
||||||
|
|
||||||
|
CompletableFuture<Long> totalUsersFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> memberBasicInfoService.countTotalMembers(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(0L);
|
||||||
|
CompletableFuture<Long> totalStationsFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> pileStationInfoService.countTotalStations(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(0L);
|
||||||
|
CompletableFuture<Long> dailyNewUsersFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> memberBasicInfoService.countTodayNewMembers(fTodayStart, fTodayEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(0L);
|
||||||
|
CompletableFuture<BigDecimal> todayAmountFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> orderBasicInfoService.getTodayTransactionAmount(fTodayStart, fTodayEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(java.math.BigDecimal.ZERO);
|
||||||
|
CompletableFuture<BigDecimal> todayElecFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> orderBasicInfoService.getTodayElectricity(fTodayStart, fTodayEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(java.math.BigDecimal.ZERO);
|
||||||
|
CompletableFuture<BigDecimal> monthlyAvgFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> pileBasicInfoService.getMonthlyAvgElectricity(fMonthStart, fMonthEnd, scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(java.math.BigDecimal.ZERO);
|
||||||
|
CompletableFuture<Long> totalGunsFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> pileConnectorInfoService.countTotalConnectors(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(0L);
|
||||||
|
CompletableFuture<Long> onlinePilesFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> pileConnectorInfoService.countOnlinePiles(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(0L);
|
||||||
|
// 充电桩数量统计:总数/直流/交流同源(保证 直流 + 交流 = 总数)
|
||||||
|
CompletableFuture<PileCountStatVO> pilesStatFuture = hasDataScope
|
||||||
|
? CompletableFuture.supplyAsync(
|
||||||
|
() -> pileBasicInfoService.countPilesStat(scopeMerchantIds, scopeStationIds), threadPoolTaskExecutor)
|
||||||
|
: CompletableFuture.completedFuture(new PileCountStatVO());
|
||||||
|
|
||||||
|
// 等待所有异步查询完成
|
||||||
|
CompletableFuture.allOf(
|
||||||
|
situationFuture,
|
||||||
|
totalUsersFuture, totalStationsFuture, dailyNewUsersFuture,
|
||||||
|
todayAmountFuture, todayElecFuture, monthlyAvgFuture,
|
||||||
|
totalGunsFuture, onlinePilesFuture, pilesStatFuture
|
||||||
|
).join();
|
||||||
|
|
||||||
|
// === 第三步:组装结果 ===
|
||||||
|
IndexGeneralSituationVO situation = situationFuture.join();
|
||||||
|
String totalChargingAmount = situation.getTotalChargingAmount();
|
||||||
|
String totalChargingDegree = situation.getTotalChargingDegree();
|
||||||
|
PileCountStatVO pilesStat = pilesStatFuture.join();
|
||||||
|
Long totalPileCount = pilesStat != null ? pilesStat.getTotalPiles() : null;
|
||||||
|
Long dcPileCount = pilesStat != null ? pilesStat.getDcPileCount() : null;
|
||||||
|
Long acPileCount = pilesStat != null ? pilesStat.getAcPileCount() : null;
|
||||||
|
|
||||||
|
// 总订单数从settle_order_report的GROUP BY结果中获取(charge_num汇总)
|
||||||
|
String totalOrderCountStr = situation.getTotalChargingQuantity();
|
||||||
|
Long totalOrderCount = (totalOrderCountStr != null && !totalOrderCountStr.isEmpty())
|
||||||
|
? Long.parseLong(totalOrderCountStr.replaceAll("[.](.*)", "")) : 0L;
|
||||||
|
|
||||||
|
overviewVO.setTotalUsers(totalUsersFuture.join());
|
||||||
|
overviewVO.setTotalOrders(totalOrderCount);
|
||||||
|
overviewVO.setTotalTransactionAmount(totalChargingAmount);
|
||||||
|
overviewVO.setTotalElectricity(totalChargingDegree);
|
||||||
|
overviewVO.setTotalPiles(totalPileCount != null ? totalPileCount : 0L);
|
||||||
|
overviewVO.setTotalStations(totalStationsFuture.join());
|
||||||
|
overviewVO.setDailyNewUsers(dailyNewUsersFuture.join());
|
||||||
|
BigDecimal todayAmount = todayAmountFuture.join();
|
||||||
|
overviewVO.setTodayTransactionAmount(todayAmount != null ? todayAmount.toPlainString() : "0");
|
||||||
|
BigDecimal todayElec = todayElecFuture.join();
|
||||||
|
overviewVO.setTodayElectricity(todayElec != null ? todayElec.toPlainString() : "0");
|
||||||
|
BigDecimal monthlyAvg = monthlyAvgFuture.join();
|
||||||
|
overviewVO.setMonthlyAvgElectricity(monthlyAvg != null ? monthlyAvg.toPlainString() : "0");
|
||||||
|
overviewVO.setTotalGuns(totalGunsFuture.join());
|
||||||
|
overviewVO.setOnlinePiles(onlinePilesFuture.join());
|
||||||
|
overviewVO.setDcPileCount(dcPileCount != null ? dcPileCount : 0L);
|
||||||
|
overviewVO.setAcPileCount(acPileCount != null ? acPileCount : 0L);
|
||||||
|
|
||||||
|
// 节能减排计算
|
||||||
|
BigDecimal totalElecKwh = new BigDecimal(totalChargingDegree);
|
||||||
|
BigDecimal carbonKg = totalElecKwh.multiply(new BigDecimal("0.5306"));
|
||||||
|
BigDecimal carbonTon = carbonKg.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP);
|
||||||
|
overviewVO.setCarbonReduction(carbonTon.toPlainString());
|
||||||
|
if (totalOrderCount != null && totalOrderCount > 0) {
|
||||||
|
BigDecimal avgCarbon = carbonKg.divide(new BigDecimal(totalOrderCount), 2, RoundingMode.HALF_UP);
|
||||||
|
overviewVO.setAvgCarbonPerOrder(avgCarbon.toPlainString());
|
||||||
|
} else {
|
||||||
|
overviewVO.setAvgCarbonPerOrder("0");
|
||||||
|
}
|
||||||
|
BigDecimal fuelSaved = totalElecKwh.multiply(new BigDecimal("8"))
|
||||||
|
.divide(new BigDecimal("15"), 2, RoundingMode.HALF_UP);
|
||||||
|
overviewVO.setFuelSaved(fuelSaved.toPlainString());
|
||||||
|
BigDecimal coalSaved = totalElecKwh.multiply(new BigDecimal("0.000404"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
overviewVO.setStandardCoalSaved(coalSaved.toPlainString());
|
||||||
|
|
||||||
|
// demo账号展示效果处理(节能减排基于处理后的电量/订单数重算)
|
||||||
|
if (isDemo) {
|
||||||
|
applyDemoEffect(overviewVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return overviewVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限参数内部类
|
||||||
|
*/
|
||||||
|
private static class AuthParams {
|
||||||
|
boolean isPlatformAdmin = false;
|
||||||
|
List<String> merchantIdList = new ArrayList<>();
|
||||||
|
List<String> stationIdList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析当前用户权限参数
|
||||||
|
* - 平台管理员:标记isPlatformAdmin=true,不需要任何过滤条件
|
||||||
|
* - 运营商管理员:根据deptId获取merchantId
|
||||||
|
* - 站点管理员:使用stationId
|
||||||
|
*/
|
||||||
|
private AuthParams resolveAuthParams() {
|
||||||
|
AuthParams params = new AuthParams();
|
||||||
|
AuthorizedDeptVO authorizedMap = UserUtils.getAuthorizedMap();
|
||||||
|
if (authorizedMap == null) {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
List<String> stationDeptIds = authorizedMap.getStationDeptIds();
|
||||||
|
List<String> merchantDeptIds = authorizedMap.getMerchantDeptIds();
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(stationDeptIds)) {
|
||||||
|
// 站点管理员:使用站点维度
|
||||||
|
List<String> list = pileStationInfoService.queryByStationDeptIds(stationDeptIds);
|
||||||
|
if (!CollectionUtils.isEmpty(list)) {
|
||||||
|
params.stationIdList.addAll(list);
|
||||||
|
}
|
||||||
|
} else if (!CollectionUtils.isEmpty(merchantDeptIds)) {
|
||||||
|
// 运营商管理员:根据deptId获取merchantId
|
||||||
|
for (String deptId : merchantDeptIds) {
|
||||||
|
PileMerchantInfo merchant = pileMerchantInfoService.queryInfoByDeptId(deptId);
|
||||||
|
if (merchant != null && merchant.getId() != null) {
|
||||||
|
params.merchantIdList.add(String.valueOf(merchant.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 平台管理员:直接查全量,不需要任何过滤
|
||||||
|
params.isPlatformAdmin = true;
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空权限维度时的占位汇总数据(全为0,避免下游NPE)
|
||||||
|
*/
|
||||||
|
private static IndexGeneralSituationVO emptySituationVO() {
|
||||||
|
IndexGeneralSituationVO vo = new IndexGeneralSituationVO();
|
||||||
|
vo.setTotalChargingAmount("0");
|
||||||
|
vo.setTotalSettleAmount("0");
|
||||||
|
vo.setTotalChargingDegree("0");
|
||||||
|
vo.setTotalChargingQuantity("0");
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* demo账号展示效果处理
|
||||||
|
* 所有总量类指标(用户、订单、金额、电量、站点、桩、枪等)按统一倍数调整,保证各维度数据比例一致;
|
||||||
|
* 节能减排基于调整后的累计电量/订单数重算,其中"单次充电平均减碳量"为比值型指标,调整后保持不变
|
||||||
|
*/
|
||||||
|
private static void applyDemoEffect(BigDataOverviewVO vo) {
|
||||||
|
BigDecimal multiplier = new BigDecimal(Constants.THREE);
|
||||||
|
vo.setTotalUsers(multiply(vo.getTotalUsers(), multiplier));
|
||||||
|
vo.setTotalOrders(multiply(vo.getTotalOrders(), multiplier));
|
||||||
|
vo.setTotalTransactionAmount(multiply(vo.getTotalTransactionAmount(), multiplier));
|
||||||
|
vo.setTotalElectricity(multiply(vo.getTotalElectricity(), multiplier));
|
||||||
|
vo.setTotalPiles(multiply(vo.getTotalPiles(), multiplier));
|
||||||
|
vo.setTotalStations(multiply(vo.getTotalStations(), multiplier));
|
||||||
|
vo.setDailyNewUsers(multiply(vo.getDailyNewUsers(), multiplier));
|
||||||
|
vo.setTodayTransactionAmount(multiply(vo.getTodayTransactionAmount(), multiplier));
|
||||||
|
vo.setTodayElectricity(multiply(vo.getTodayElectricity(), multiplier));
|
||||||
|
vo.setMonthlyAvgElectricity(multiply(vo.getMonthlyAvgElectricity(), multiplier));
|
||||||
|
vo.setTotalGuns(multiply(vo.getTotalGuns(), multiplier));
|
||||||
|
vo.setOnlinePiles(multiply(vo.getOnlinePiles(), multiplier));
|
||||||
|
vo.setDcPileCount(multiply(vo.getDcPileCount(), multiplier));
|
||||||
|
vo.setAcPileCount(multiply(vo.getAcPileCount(), multiplier));
|
||||||
|
|
||||||
|
// 节能减排按调整后的累计电量/订单数重算
|
||||||
|
BigDecimal totalElecKwh = new BigDecimal(vo.getTotalElectricity());
|
||||||
|
BigDecimal carbonKg = totalElecKwh.multiply(new BigDecimal("0.5306"));
|
||||||
|
BigDecimal carbonTon = carbonKg.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP);
|
||||||
|
vo.setCarbonReduction(carbonTon.toPlainString());
|
||||||
|
Long totalOrderCount = vo.getTotalOrders();
|
||||||
|
if (totalOrderCount != null && totalOrderCount > 0) {
|
||||||
|
BigDecimal avgCarbon = carbonKg.divide(new BigDecimal(totalOrderCount), 2, RoundingMode.HALF_UP);
|
||||||
|
vo.setAvgCarbonPerOrder(avgCarbon.toPlainString());
|
||||||
|
} else {
|
||||||
|
vo.setAvgCarbonPerOrder("0");
|
||||||
|
}
|
||||||
|
BigDecimal fuelSaved = totalElecKwh.multiply(new BigDecimal("8"))
|
||||||
|
.divide(new BigDecimal("15"), 2, RoundingMode.HALF_UP);
|
||||||
|
vo.setFuelSaved(fuelSaved.toPlainString());
|
||||||
|
BigDecimal coalSaved = totalElecKwh.multiply(new BigDecimal("0.000404"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
vo.setStandardCoalSaved(coalSaved.toPlainString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Long multiply(Long value, BigDecimal multiplier) {
|
||||||
|
return value == null ? null : new BigDecimal(value).multiply(multiplier).longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String multiply(String value, BigDecimal multiplier) {
|
||||||
|
return value == null ? null : new BigDecimal(value).multiply(multiplier).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user