1、新增组织编辑修改首购价格能力;2、账单分页支持非管理端只允许查看本组织下;3、统计公共入参和方法抽象、过期组织接口分离移到system、新增销售额统计接口;

This commit is contained in:
gaoqr
2025-09-30 14:50:57 +08:00
parent 7076c64811
commit 23bc07160d
38 changed files with 736 additions and 772 deletions
@@ -0,0 +1,34 @@
package com.cf.imes.framework.common.enums;
/**
* 统计维度单位
* @author Gqr
* @since 2024/8/6 10:04
*/
public enum StatisticsUnit {
//季度、月、周、日
QUARTER(0),
MONTH(1),
WEEK(2),
DAY(3);
StatisticsUnit(Integer value) {
this.value = value;
}
private Integer value;
public Integer getValue() {
return value;
}
// from value
public static StatisticsUnit fromValue(Integer value) {
for (StatisticsUnit unit : StatisticsUnit.values()) {
if (unit.getValue().equals(value)) {
return unit;
}
}
return null;
}
}
@@ -0,0 +1,29 @@
package com.cf.imes.framework.common.pojo;
import com.cf.imes.framework.common.util.validation.statistics.StatisticsUnitInEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
/**
* 通用统计 ReqVO
* @author Gqr
* @since 2025/9/29 16:50
*/
@Data
public class CommonStatisticsReqVO {
@Schema(description = "创建时间")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate[] createTime;
/**
* 统计维度单位
*/
@Schema(description = "统计维度单位", example = "0", allowableValues = {"0", "1", "2", "3"}, type = "integer")
@NotNull(message = "统计维度单位不能为空")
@StatisticsUnitInEnum
private Integer unit;
}
@@ -1,7 +1,10 @@
package com.cf.imes.framework.common.util.time;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.enums.OrderStatisticsUnit;
import com.cf.imes.framework.common.enums.StatisticsUnit;
import com.cf.imes.framework.common.pojo.CommonStatisticsReqVO;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@@ -22,12 +25,15 @@ public class StatisticsChangeUtils {
* 3、返回所有日期的集合
* @return
*/
public static List<String> getDateList(LocalDate[] createTime, Integer unit) {
public static List<String> getDateList(CommonStatisticsReqVO reqVO) {
// 计算时间跨度
getTimeSpan(createTime, unit);
getTimeSpan(reqVO);
// 重新计算开始时间和结束时间
computeTimeSpan(reqVO);
// 所有的日期集合
return generateDateRange(createTime, unit);
return generateDateRange(reqVO);
}
/**
@@ -35,13 +41,14 @@ public class StatisticsChangeUtils {
* 计算起止时间:前端不传入时间就根据维度单位从当前日期计算
*
*/
public static LocalDate[] getTimeSpan(LocalDate[] createTime, Integer unit) {
public static void getTimeSpan(CommonStatisticsReqVO reqVO) {
LocalDate[] createTime = reqVO.getCreateTime();
LocalDate startTime = null;
LocalDate endTime;
LocalDate now = LocalDate.now();
if (ObjectUtil.isNull(createTime) || ObjectUtil.isNull(createTime[0]) || ObjectUtil.isNull(createTime[1])) {
if (ArrayUtil.isEmpty(createTime) || ObjectUtil.isNull(createTime[0]) || ObjectUtil.isNull(createTime[1])) {
endTime = now;
switch (OrderStatisticsUnit.fromValue(unit)) {
switch (StatisticsUnit.fromValue(reqVO.getUnit())) {
case QUARTER:
// 从now往前的2年
startTime = now.minusYears(2);
@@ -62,10 +69,45 @@ public class StatisticsChangeUtils {
break;
}
// 声明一个LocalDateTime的数组,把startTime和endTime放进去
createTime[0] = startTime;
createTime[1] = endTime;
reqVO.setCreateTime(new LocalDate[]{startTime, endTime});
}
return createTime;
}
/**
* 根据传入信息重新计算时间范围
*
* @param reqVO
*/
public static void computeTimeSpan(CommonStatisticsReqVO reqVO) {
Integer unit = reqVO.getUnit();
// 计算后的开始和结束时间
LocalDate startDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
LocalDate endDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);
if (startDate.isAfter(endDate)) {
startDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);
endDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
}
LocalDate first = startDate;
LocalDate end = endDate;
switch (OrderStatisticsUnit.fromValue(unit)) {
case QUARTER -> {
first = firstDayOfQuarter(startDate);
end = lastDayOfQuarter(endDate);
}
case MONTH -> {
first = startDate.with(TemporalAdjusters.firstDayOfMonth());
end = endDate.with(TemporalAdjusters.lastDayOfMonth());
}
case WEEK -> {
first = startDate.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));
end = endDate.with(TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));
}
default -> {
return;
}
}
reqVO.setCreateTime(new LocalDate[]{first, end});
}
/**
@@ -73,12 +115,13 @@ public class StatisticsChangeUtils {
*
* @return
*/
public static List<String> generateDateRange(LocalDate[] createTime, Integer unit) {
public static List<String> generateDateRange(CommonStatisticsReqVO reqVO) {
Integer unit = reqVO.getUnit();
// 计算时间跨度
getTimeSpan(createTime, unit);
// 计算后的开始和结束时间
LocalDate startDate = ObjectUtil.clone(createTime[0]);
LocalDate endDate = ObjectUtil.clone(createTime[1]);
getTimeSpan(reqVO);
// 计算后的开始和结束时间
LocalDate startDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
LocalDate endDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);
List<String> dates = new ArrayList<>();
while (!startDate.isAfter(endDate)) {
@@ -146,4 +189,30 @@ public class StatisticsChangeUtils {
}
return newDateStrBuffer.toString();
}
/**
* 获取指定日期所在季度的开始日期
*
* @param date
* @return
*/
private static LocalDate firstDayOfQuarter(LocalDate date) {
int month = date.getMonthValue();
int quarter = (month - 1) / 3 + 1;
int startMonth = (quarter - 1) * 3 + 1;
return LocalDate.of(date.getYear(), startMonth, 1);
}
/**
* 获取指定日期所在季度的结束日期
*
* @param date
* @return
*/
private static LocalDate lastDayOfQuarter(LocalDate date) {
int month = date.getMonthValue();
int quarter = (month - 1) / 3 + 1;
int endMonth = (quarter - 1) * 3 + 3;
return LocalDate.of(date.getYear(), endMonth, 1).with(TemporalAdjusters.lastDayOfMonth());
}
}
@@ -0,0 +1,37 @@
package com.cf.imes.framework.common.util.validation.statistics;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 统计维度单位入参校验注解
*
* @author Gqr
* @since 2024/7/17 9:33
*/
@Target({
ElementType.METHOD,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.PARAMETER,
ElementType.TYPE_USE
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {StatisticsUnitInEnumValidator.class}
)
public @interface StatisticsUnitInEnum {
String message() default "统计维度单位[unit]错误,请检查";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@@ -0,0 +1,35 @@
package com.cf.imes.framework.common.util.validation.statistics;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.enums.StatisticsUnit;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* 统计维度单位入参校验器
*
* @author Gqr
* @since 2024/7/17 9:33
*/
public class StatisticsUnitInEnumValidator implements ConstraintValidator<StatisticsUnitInEnum, Integer> {
@Override
public void initialize(StatisticsUnitInEnum constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (ObjectUtil.isNull(value)) {
return true;
}
StatisticsUnit unit = StatisticsUnit.fromValue(value);
if (ObjectUtil.isNotNull(unit)) {
return true;
} else {
return false;
}
}
}
@@ -1,6 +1,7 @@
package com.cf.imes.framework.id.config;
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
import com.cf.imes.framework.id.core.util.SnowflakeSerialNoWorker3rd;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
@@ -16,4 +17,9 @@ public class ChenfengIDAutoConfiguration {
public SnowflakeIdWorker3rd idWorker() {
return new SnowflakeIdWorker3rd();
}
@Bean
public SnowflakeSerialNoWorker3rd serialNoWorker3rd() {
return new SnowflakeSerialNoWorker3rd();
}
}
@@ -0,0 +1,25 @@
package com.cf.imes.framework.id.core.util;
import java.util.concurrent.atomic.AtomicLong;
public class SerialNoMinuteCounter {
private static final long MASK = 0x7FFFFFFFFFFFFFFFL;
private final AtomicLong atom;
public SerialNoMinuteCounter() {
atom = new AtomicLong(0);
}
public final long incrementAndGet() {
return atom.incrementAndGet() & MASK;
}
public long get() {
return atom.get() & MASK;
}
public void set(long newValue) {
atom.set(newValue & MASK);
}
}
@@ -4,9 +4,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicReference;
/**
* @ClassName: SnowflakeIdWorker3rd
@@ -39,10 +36,6 @@ public class SnowflakeIdWorker3rd {
private final MinuteCounter counter = new MinuteCounter();
/** 预支时间标志 */
boolean isAdvance = false;
/** 时间格式 */
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
/** 上次时间格式 */
private final AtomicReference<String> lastTimestampStr = new AtomicReference<>("");
// ==============================Constructors=====================================
@@ -133,37 +126,4 @@ public class SnowflakeIdWorker3rd {
// String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
return Integer.valueOf(timestamp);
}
/**
* 获取下一个流水号
*
* @return SerialNo
*/
public String nextSerialNo() {
String now = LocalDateTime.now().format(FORMATTER);
// 跨秒重置序列号
String last = lastTimestampStr.get();
if (!now.equals(last)) {
// 仅在跨秒时重置序列号
if (lastTimestampStr.compareAndSet(last, now)) {
counter.set(0);
}
}
// 原子递增序列号
int seq = counter.incrementAndGet();
// 序列号1000005位)以内
if (seq > 9999) {
if (counter.compareAndSet(seq, 1)) {
seq = 1;
} else {
seq = counter.incrementAndGet();
}
}
// 拼接时间 + 序列号
return String.format("%s%05d", now, seq);
}
}
@@ -0,0 +1,124 @@
package com.cf.imes.framework.id.core.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @ClassName: SnowflakeSerialNoWorker3rd
* @Description:snowflake算法改进
* @author: yonnie
* @date: 2025/09/29 16:00
* @version V1.1
*
* 将产生的Id类型更改为Integer 64bit <br>
* 把时间戳的单位改为秒,使用48bit的时间戳
* 16bit作为自增值即 2^16 = 65535
*/
@Slf4j
@Component
public class SnowflakeSerialNoWorker3rd {
/** 初始时间 (2025-01-01 00:00:00: 1735660800) */
// private final long twepoch = 28927680;// 1735660800000L/1000/60;
private final long twepoch = 1735660800;
/** 序列在id中占位数 */
private final long sequenceBits = 16L;
/** 时间截向左移16bit */
private final long timestampLeftShift = sequenceBits;
/** 生成序列的MASK (0xFFFF) */
private final long sequenceMask = -1 ^ (-1 << sequenceBits);
/** 分钟内序 (0~65535) */
private long sequence = 0;
private long laterSequence = 0;
/** 上次生成ID的时间戳 */
private long lastTimestamp = -1;
private final SerialNoMinuteCounter counter = new SerialNoMinuteCounter();
/** 预支时间标志 */
boolean isAdvance = false;
/** 时间格式 */
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
// ==============================Constructors=====================================
public SnowflakeSerialNoWorker3rd() {
// constructor
}
// ==============================Test=============================================
/** 测试 */
public static void main(String[] args) {
SnowflakeSerialNoWorker3rd idWorker = new SnowflakeSerialNoWorker3rd();
for (long i = 0; i < 1000; i++) {
System.out.println(i + ": " + idWorker.nextSerialNo());
}
}
// ==============================Methods==========================================
/**
* 获得下一个ID (该方法是线程安全)
*
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
// System.out.println("timeGen: " + Long.toString(timestamp));
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟修改过
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (timestamp > counter.get()) {
counter.set(timestamp);
isAdvance = false;
}
// 如果是同时间生成的,则进行秒内序列
if (lastTimestamp == timestamp || isAdvance) {
if (!isAdvance) {
sequence = (sequence + 1) & sequenceMask;
}
// 秒内自增列溢出
if (sequence == 0) {
// 预支下一秒获得新的时间戳
isAdvance = true;
long laterTimestamp = counter.get();
if (laterSequence == 0) {
laterTimestamp = counter.incrementAndGet();
}
long nextId = ((laterTimestamp - twepoch) << timestampLeftShift) | laterSequence;
laterSequence = (laterSequence + 1) & sequenceMask;
return nextId;
}
} else { // 时间戳改变,秒内序列置0
sequence = 0;
laterSequence = 0;
}
// 上次生成ID的时间截
lastTimestamp = timestamp;
// 移位并或运算拼成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) | sequence;
}
public String nextSerialNo() {
return LocalDateTime.now().format(FORMATTER) + String.valueOf(nextId()).substring(8);
}
/**
* 返回以秒为单位的当前时间
*
* @return 当前时间(秒)
*/
protected long timeGen() {
// String timestamp = String.valueOf(System.currentTimeMillis() / 1000 / 60);
// String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
// return Long.valueOf(timestamp);
return System.currentTimeMillis() / 1000;
}
}