Merge branch 'master-jdk21' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
package cn.iocoder.yudao.framework.common.enums;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 时间间隔的枚举
|
||||
*
|
||||
* @author dhb52
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DateIntervalEnum implements IntArrayValuable {
|
||||
|
||||
DAY(1, "天"),
|
||||
WEEK(2, "周"),
|
||||
MONTH(3, "月"),
|
||||
QUARTER(4, "季度"),
|
||||
YEAR(5, "年")
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getInterval).toArray();
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer interval;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
public static DateIntervalEnum valueOf(Integer interval) {
|
||||
return ArrayUtil.firstMatch(item -> item.getInterval().equals(interval), DateIntervalEnum.values());
|
||||
}
|
||||
|
||||
}
|
@@ -7,6 +7,7 @@ import com.google.common.cache.LoadingCache;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
@@ -17,8 +18,11 @@ import java.util.concurrent.Executors;
|
||||
public class CacheUtils {
|
||||
|
||||
public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(Duration duration, CacheLoader<K, V> loader) {
|
||||
Executor executor = Executors.newCachedThreadPool( // TODO 芋艿:可能要思考下,未来要不要做成可配置
|
||||
TtlExecutors.getDefaultDisableInheritableThreadFactory()); // TTL 保证 ThreadLocal 可以透传
|
||||
// 1. 使用 TTL 包装 ExecutorService,实现 ThreadLocal 的透传
|
||||
// https://github.com/YunaiV/ruoyi-vue-pro/issues/432
|
||||
ExecutorService executorService = Executors.newCachedThreadPool(); // TODO 芋艿:可能要思考下,未来要不要做成可配置
|
||||
Executor executor = TtlExecutors.getTtlExecutorService(executorService);
|
||||
// 2. 创建 Guava LoadingCache
|
||||
return CacheBuilder.newBuilder()
|
||||
// 只阻塞当前数据加载线程,其他线程返回旧值
|
||||
.refreshAfterWrite(duration)
|
||||
|
@@ -78,7 +78,7 @@ public class CollectionUtils {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T, U, R> List<R> convertListByFlatMap(Collection<T> from,
|
||||
@@ -87,7 +87,7 @@ public class CollectionUtils {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <K, V> List<V> mergeValuesFromMap(Map<K, List<V>> map) {
|
||||
@@ -123,7 +123,7 @@ public class CollectionUtils {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, U, R> Set<R> convertSetByFlatMap(Collection<T> from,
|
||||
@@ -132,7 +132,7 @@ public class CollectionUtils {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||
@@ -315,4 +315,4 @@ public class CollectionUtils {
|
||||
return list.stream().flatMap(Collection::stream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -27,8 +27,6 @@ public class DateUtils {
|
||||
|
||||
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";
|
||||
|
||||
/**
|
||||
* 将 LocalDateTime 转换成 Date
|
||||
*
|
||||
@@ -67,19 +65,11 @@ public class DateUtils {
|
||||
return new Date(System.currentTimeMillis() + duration.toMillis());
|
||||
}
|
||||
|
||||
public static boolean isExpired(Date time) {
|
||||
return System.currentTimeMillis() > time.getTime();
|
||||
}
|
||||
|
||||
public static boolean isExpired(LocalDateTime time) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return now.isAfter(time);
|
||||
}
|
||||
|
||||
public static long diff(Date endTime, Date startTime) {
|
||||
return endTime.getTime() - startTime.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
@@ -136,37 +126,6 @@ public class DateUtils {
|
||||
return a.isAfter(b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当期时间相差的日期
|
||||
*
|
||||
* @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
|
||||
* @param amount 相差的数值
|
||||
* @return 计算后的日志
|
||||
*/
|
||||
public static Date addDate(int field, int amount) {
|
||||
return addDate(null, field, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当期时间相差的日期
|
||||
*
|
||||
* @param date 设置时间
|
||||
* @param field 日历字段 例如说,{@link Calendar#DAY_OF_MONTH} 等
|
||||
* @param amount 相差的数值
|
||||
* @return 计算后的日志
|
||||
*/
|
||||
public static Date addDate(Date date, int field, int amount) {
|
||||
if (amount == 0) {
|
||||
return date;
|
||||
}
|
||||
Calendar c = Calendar.getInstance();
|
||||
if (date != null) {
|
||||
c.setTime(date);
|
||||
}
|
||||
c.add(field, amount);
|
||||
return c.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否今天
|
||||
*
|
||||
|
@@ -1,13 +1,18 @@
|
||||
package cn.iocoder.yudao.framework.common.util.date;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 时间工具类,用于 {@link java.time.LocalDateTime}
|
||||
@@ -21,6 +26,22 @@ public class LocalDateTimeUtils {
|
||||
*/
|
||||
public static LocalDateTime EMPTY = buildTime(1970, 1, 1);
|
||||
|
||||
/**
|
||||
* 解析时间
|
||||
*
|
||||
* 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功
|
||||
*
|
||||
* @param time 时间
|
||||
* @return 时间字符串
|
||||
*/
|
||||
public static LocalDateTime parse(String time) {
|
||||
try {
|
||||
return LocalDateTimeUtil.parse(time, DatePattern.NORM_DATE_PATTERN);
|
||||
} catch (DateTimeParseException e) {
|
||||
return LocalDateTimeUtil.parse(time);
|
||||
}
|
||||
}
|
||||
|
||||
public static LocalDateTime addTime(Duration duration) {
|
||||
return LocalDateTime.now().plus(duration);
|
||||
}
|
||||
@@ -54,6 +75,21 @@ public class LocalDateTimeUtils {
|
||||
return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
|
||||
}
|
||||
|
||||
/**
|
||||
* 判指定断时间,是否在该时间范围内
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @param time 指定时间
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, String time) {
|
||||
if (startTime == null || endTime == null || time == null) {
|
||||
return false;
|
||||
}
|
||||
return LocalDateTimeUtil.isIn(parse(time), startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前时间是否在该时间范围内
|
||||
*
|
||||
@@ -122,6 +158,16 @@ public class LocalDateTimeUtils {
|
||||
return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定日期所在季度
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 所在季度
|
||||
*/
|
||||
public static int getQuarterOfYear(LocalDateTime date) {
|
||||
return (date.getMonthValue() - 1) / 3 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负
|
||||
*
|
||||
@@ -168,4 +214,96 @@ public class LocalDateTimeUtils {
|
||||
return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
|
||||
}
|
||||
|
||||
public static List<LocalDateTime[]> getDateRangeList(LocalDateTime startTime,
|
||||
LocalDateTime endTime,
|
||||
Integer interval) {
|
||||
// 1.1 找到枚举
|
||||
DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
|
||||
Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
|
||||
// 1.2 将时间对齐
|
||||
startTime = LocalDateTimeUtil.beginOfDay(startTime);
|
||||
endTime = LocalDateTimeUtil.endOfDay(endTime);
|
||||
|
||||
// 2. 循环,生成时间范围
|
||||
List<LocalDateTime[]> timeRanges = new ArrayList<>();
|
||||
switch (intervalEnum) {
|
||||
case DateIntervalEnum.DAY:
|
||||
while (startTime.isBefore(endTime)) {
|
||||
timeRanges.add(new LocalDateTime[]{startTime, startTime.plusDays(1).minusNanos(1)});
|
||||
startTime = startTime.plusDays(1);
|
||||
}
|
||||
break;
|
||||
case DateIntervalEnum.WEEK:
|
||||
while (startTime.isBefore(endTime)) {
|
||||
LocalDateTime endOfWeek = startTime.with(DayOfWeek.SUNDAY).plusDays(1).minusNanos(1);
|
||||
timeRanges.add(new LocalDateTime[]{startTime, endOfWeek});
|
||||
startTime = endOfWeek.plusNanos(1);
|
||||
}
|
||||
break;
|
||||
case DateIntervalEnum.MONTH:
|
||||
while (startTime.isBefore(endTime)) {
|
||||
LocalDateTime endOfMonth = startTime.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1).minusNanos(1);
|
||||
timeRanges.add(new LocalDateTime[]{startTime, endOfMonth});
|
||||
startTime = endOfMonth.plusNanos(1);
|
||||
}
|
||||
break;
|
||||
case DateIntervalEnum.QUARTER:
|
||||
while (startTime.isBefore(endTime)) {
|
||||
int quarterOfYear = getQuarterOfYear(startTime);
|
||||
LocalDateTime quarterEnd = quarterOfYear == 4
|
||||
? startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1)
|
||||
: startTime.withMonth(quarterOfYear * 3 + 1).withDayOfMonth(1).minusNanos(1);
|
||||
timeRanges.add(new LocalDateTime[]{startTime, quarterEnd});
|
||||
startTime = quarterEnd.plusNanos(1);
|
||||
}
|
||||
break;
|
||||
case DateIntervalEnum.YEAR:
|
||||
while (startTime.isBefore(endTime)) {
|
||||
LocalDateTime endOfYear = startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1);
|
||||
timeRanges.add(new LocalDateTime[]{startTime, endOfYear});
|
||||
startTime = endOfYear.plusNanos(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid interval: " + interval);
|
||||
}
|
||||
// 3. 兜底,最后一个时间,需要保持在 endTime 之前
|
||||
LocalDateTime[] lastTimeRange = CollUtil.getLast(timeRanges);
|
||||
if (lastTimeRange != null) {
|
||||
lastTimeRange[1] = endTime;
|
||||
}
|
||||
return timeRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间范围
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @param interval 时间间隔
|
||||
* @return 时间范围
|
||||
*/
|
||||
public static String formatDateRange(LocalDateTime startTime, LocalDateTime endTime, Integer interval) {
|
||||
// 1. 找到枚举
|
||||
DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
|
||||
Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
|
||||
|
||||
// 2. 循环,生成时间范围
|
||||
switch (intervalEnum) {
|
||||
case DateIntervalEnum.DAY:
|
||||
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN);
|
||||
case DateIntervalEnum.WEEK:
|
||||
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN)
|
||||
+ StrUtil.format("(第 {} 周)", LocalDateTimeUtil.weekOfYear(startTime));
|
||||
case DateIntervalEnum.MONTH:
|
||||
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_MONTH_PATTERN);
|
||||
case DateIntervalEnum.QUARTER:
|
||||
return StrUtil.format("{}-Q{}", startTime.getYear(), getQuarterOfYear(startTime));
|
||||
case DateIntervalEnum.YEAR:
|
||||
return LocalDateTimeUtil.format(startTime, DatePattern.NORM_YEAR_PATTERN);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid interval: " + interval);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user