172 lines
5.4 KiB
Java
172 lines
5.4 KiB
Java
|
|
package com.ruoyi.cms.util;
|
|||
|
|
|
|||
|
|
import com.ruoyi.cms.constant.enums.QueryTimeTypeEnum;
|
|||
|
|
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 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 + dto.getCount();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (QueryResultVo dto : list) {
|
|||
|
|
dto.setCountPercentage(calculatePercentage(totalCount, dto.getCount()));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 计算同比和环比
|
|||
|
|
*
|
|||
|
|
* @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)));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|