243 lines
7.7 KiB
Java
243 lines
7.7 KiB
Java
package com.ruoyi.cms.util;
|
|
|
|
import com.ruoyi.cms.constant.CommonConstant;
|
|
import com.ruoyi.cms.constant.enums.QueryTimeTypeEnum;
|
|
import com.ruoyi.cms.domain.vo.HeatmapVo;
|
|
import com.ruoyi.cms.domain.vo.QueryResultVo;
|
|
import com.ruoyi.cms.domain.vo.TreadVo;
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.RoundingMode;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
|
|
/**
|
|
* 数学工具
|
|
*
|
|
* @author 马宝龙
|
|
* @date 2026/1/21
|
|
*/
|
|
public class MathUtil {
|
|
private MathUtil() {
|
|
}
|
|
|
|
|
|
/**
|
|
* 除以 10000
|
|
*
|
|
* @param n 原数
|
|
* @return 结果
|
|
*/
|
|
public static BigDecimal divideTenThousand(Long n) {
|
|
if (Objects.isNull(n)) {
|
|
return null;
|
|
}
|
|
BigDecimal bigDecimal = new BigDecimal(n.toString());
|
|
return divideTenThousand(bigDecimal);
|
|
}
|
|
|
|
|
|
/**
|
|
* 除以 10000
|
|
*
|
|
* @param bigDecimal 原数
|
|
* @return 结果
|
|
*/
|
|
public static BigDecimal divideTenThousand(BigDecimal bigDecimal) {
|
|
if (Objects.isNull(bigDecimal)) {
|
|
return null;
|
|
}
|
|
String plainString = bigDecimal.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)
|
|
.stripTrailingZeros().toPlainString();
|
|
return new BigDecimal(plainString);
|
|
}
|
|
|
|
/**
|
|
* 计算比率
|
|
*
|
|
* @param divisor 除数(分母)
|
|
* @param dividend 被除数(分子)
|
|
* @return 比率
|
|
*/
|
|
public static BigDecimal divide(BigDecimal divisor, BigDecimal dividend) {
|
|
|
|
if (Objects.isNull(divisor) || Objects.isNull(dividend)) {
|
|
return null;
|
|
}
|
|
|
|
String plainString = dividend.divide(divisor, 2, RoundingMode.HALF_UP)
|
|
.stripTrailingZeros().toPlainString();
|
|
return new BigDecimal(plainString);
|
|
}
|
|
|
|
|
|
/**
|
|
* 计算比率
|
|
*
|
|
* @param divisor 除数(分母)
|
|
* @param dividend 被除数(分子)
|
|
* @return 比率
|
|
*/
|
|
public static BigDecimal calculatePercentage(Long divisor, Long dividend) {
|
|
BigDecimal divisorBigDecimal = Optional.ofNullable(divisor)
|
|
.map(item -> new BigDecimal(item.toString())).orElse(null);
|
|
BigDecimal dividendBigDecimal = Optional.ofNullable(dividend)
|
|
.map(item -> new BigDecimal(item.toString())).orElse(null);
|
|
return calculatePercentage(divisorBigDecimal, dividendBigDecimal);
|
|
}
|
|
|
|
/**
|
|
* 计算比率
|
|
*
|
|
* @param divisor 除数(分母)
|
|
* @param dividend 被除数(分子)
|
|
* @return 比率
|
|
*/
|
|
public static BigDecimal calculatePercentage(BigDecimal divisor, BigDecimal dividend) {
|
|
if (null == dividend || BigDecimal.ZERO.compareTo(dividend) == 0) {
|
|
return BigDecimal.ZERO;
|
|
} else {
|
|
if (null == divisor || BigDecimal.ZERO.compareTo(divisor) == 0) {
|
|
return new BigDecimal("100");
|
|
} else {
|
|
String plainString = dividend.multiply(new BigDecimal("100"))
|
|
.divide(divisor, 2, RoundingMode.HALF_UP)
|
|
.stripTrailingZeros().toPlainString();
|
|
return new BigDecimal(plainString);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 计算占比
|
|
*
|
|
* @param list 数据
|
|
*/
|
|
public static void calculatePercentage(List<QueryResultVo> list) {
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
return;
|
|
}
|
|
long totalCount = 0;
|
|
for (QueryResultVo dto : list) {
|
|
totalCount = totalCount + Optional.ofNullable(dto.getCount()).orElse(0L);
|
|
}
|
|
|
|
for (QueryResultVo dto : list) {
|
|
dto.setCountPercentage(calculatePercentage(totalCount, dto.getCount()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算环比
|
|
*
|
|
* @param lastCount 上期数据
|
|
* @param currentCount 本期数据
|
|
* @return 环比
|
|
*/
|
|
public static BigDecimal calculatePercentageGrowthRate(Long lastCount, Long currentCount) {
|
|
lastCount = Optional.ofNullable(lastCount).orElse(0L);
|
|
currentCount = Optional.ofNullable(currentCount).orElse(0L);
|
|
return calculatePercentage(lastCount, (currentCount - lastCount));
|
|
}
|
|
|
|
/**
|
|
* 计算环比
|
|
*
|
|
* @param lastBigDecimal 上期数据
|
|
* @param currentBigDecimal 本期数据
|
|
* @return 环比
|
|
*/
|
|
public static BigDecimal calculatePercentageGrowthRate(BigDecimal lastBigDecimal, BigDecimal currentBigDecimal) {
|
|
lastBigDecimal = Optional.ofNullable(lastBigDecimal).orElse(BigDecimal.ZERO);
|
|
currentBigDecimal = Optional.ofNullable(currentBigDecimal).orElse(BigDecimal.ZERO);
|
|
|
|
return calculatePercentage(lastBigDecimal, (currentBigDecimal.subtract(lastBigDecimal)));
|
|
}
|
|
|
|
/**
|
|
* 计算同比和环比
|
|
*
|
|
* @param queryTimeType 查询时间类型
|
|
* @param list 趋势数据列表
|
|
*/
|
|
public static void calculatePercentageGrowthRate(QueryTimeTypeEnum queryTimeType,
|
|
List<TreadVo> list) {
|
|
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
return;
|
|
}
|
|
|
|
// 按月份正序排序
|
|
list.sort(Comparator.comparingInt(TreadVo::getSort));
|
|
|
|
for (int i = 0; i < list.size(); i++) {
|
|
|
|
TreadVo item = list.get(i);
|
|
|
|
long currentCount = Optional.ofNullable(item.getCurrentCount())
|
|
.orElse(0L);
|
|
long lastYearCount = Optional.ofNullable(item.getLastYearCount())
|
|
.orElse(0L);
|
|
// 年度不计算同比
|
|
if (queryTimeType != QueryTimeTypeEnum.YEAR) {
|
|
// 计算同比
|
|
item.setYearOnYearGrowthDiff(currentCount - lastYearCount);
|
|
if (0 == currentCount) {
|
|
item.setYearOnYearGrowthRate(BigDecimal.ZERO);
|
|
} else if (0 == lastYearCount) {
|
|
item.setYearOnYearGrowthRate(new BigDecimal("100.00"));
|
|
} else {
|
|
item.setYearOnYearGrowthRate(calculatePercentage(lastYearCount, (currentCount - lastYearCount)));
|
|
}
|
|
}
|
|
|
|
// 计算环比
|
|
long lastMonthCount;
|
|
if (0 == i) {
|
|
// 第一个取上期的最后一个数据
|
|
lastMonthCount = Optional.ofNullable(list.get(list.size() - 1).getLastYearCount())
|
|
.orElse(0L);
|
|
} else {
|
|
lastMonthCount = Optional.ofNullable(list.get(i - 1).getLastYearCount())
|
|
.orElse(0L);
|
|
}
|
|
item.setLastMonthCount(lastMonthCount);
|
|
item.setMonthOnMonthGrowthDiff(currentCount - lastMonthCount);
|
|
if (0 == currentCount) {
|
|
item.setMonthOnMonthGrowthRate(BigDecimal.ZERO);
|
|
} else if (0 == lastMonthCount) {
|
|
item.setMonthOnMonthGrowthRate(new BigDecimal("100.00"));
|
|
} else {
|
|
item.setMonthOnMonthGrowthRate(calculatePercentage(lastMonthCount, (currentCount - lastMonthCount)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算占比 - 热力图
|
|
*
|
|
* @param list 热力图数据
|
|
*/
|
|
public static void calculatePercentageHeatmap(List<HeatmapVo> list) {
|
|
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
return;
|
|
}
|
|
|
|
// 计算占比
|
|
long totalCount = 0;
|
|
for (HeatmapVo vo : list) {
|
|
totalCount = totalCount + Optional.ofNullable(vo.getCount()).orElse(0L);
|
|
}
|
|
|
|
for (HeatmapVo vo : list) {
|
|
vo.setPercentage(calculatePercentage(totalCount, vo.getCount()));
|
|
vo.setAreaName(Optional.ofNullable(CommonConstant.AREA_MAP.get(vo.getAreaCode())).orElse("未知"));
|
|
}
|
|
}
|
|
}
|