Compare commits

...

25 Commits

Author SHA1 Message Date
huangqizhen 207d3cc970 6.26 查询接口修复 6 days ago
huangqizhen 208079fd1d 6.26 查询接口修复 6 days ago
sunjiabei e8921ddca0 新增消耗金币校验 6 days ago
sunjiabei 339410fc7c 新增消耗 6 days ago
sunjiabei 2ed53a5326 消耗更正以及用户卡片信息 7 days ago
sunjiabei c61f9f6eaf 用户信息 7 days ago
huangqizhen 58f24b11fd Merge remote-tracking branch 'origin/milestone-20250702-金币重构一期' into milestone-20250702-金币重构一期 1 week ago
huangqizhen ceb65f8110 6.24 合并冲突部分修复 1 week ago
jianlin 67508049dc Merge remote-tracking branch 'origin/milestone-20250702-金币重构一期' into milestone-20250702-金币重构一期 1 week ago
huangqizhen ed6ef8996e Merge remote-tracking branch 'origin/milestone-20250702-金币重构一期' into milestone-20250702-金币重构一期 1 week ago
huangqizhen cdd1c51dbd Merge remote-tracking branch 'refs/remotes/origin/huangqizheng/feature-20250623110001-客户金币明细' into milestone-20250702-金币重构一期 1 week ago
jianlin a4c8cb6875 Merge branch 'refs/heads/lijianlin/feature-20250623120104-工作台与审核' into milestone-20250702-金币重构一期 1 week ago
huangqizhen 3dcdb9f7b5 6.24 客户金币余额,异步部分 1 week ago
jianlin 5496460df7 6-24更新统计数据part2(余量外属性) 1 week ago
sunjiabei 9ad7f3af69 消费模块,筛选查询详情 1 week ago
sunjiabei 99a0b0f800 消费模块,消费详情分页,商品查询 1 week ago
sunjiabei 0341bc2ab3 Merge remote-tracking branch 'origin/milestone-20250702-金币重构一期' into milestone-20250702-金币重构一期 1 week ago
huangqizhen f827e86e7a Merge branch 'refs/heads/huangqizheng/feature-20250623110001-客户金币明细' into milestone-20250702-金币重构一期 1 week ago
huangqizhen e885ab526a 6.23 客户金币明细页面查询与合计 1 week ago
sunjiabei be8c77e80e 消费模块,消费金币统计接口 1 week ago
sunjiabei b8a58b038a 消费模块,消费金币统计接口 1 week ago
sunjiabei 9cffd95b79 消费模块,消息详情接口 1 week ago
sunjiabei d4c77f990d 消费模块,消息详情接口 1 week ago
sunjiabei 4fddb8ad5f 消费模块,消息详情接口 1 week ago
sunjiabei e9464c8998 测试 1 week ago
  1. 5
      pom.xml
  2. 31
      src/main/java/com/example/demo/Util/BusinessException.java
  3. 175
      src/main/java/com/example/demo/Util/RedisUtil.java
  4. 77
      src/main/java/com/example/demo/controller/ConsumeController.java
  5. 6
      src/main/java/com/example/demo/controller/GeneralController.java
  6. 60
      src/main/java/com/example/demo/controller/GoldDetailController.java
  7. 18
      src/main/java/com/example/demo/controller/StatisticsController.java
  8. 37
      src/main/java/com/example/demo/controller/UserController.java
  9. 33
      src/main/java/com/example/demo/domain/entity/Export.java
  10. 3
      src/main/java/com/example/demo/domain/entity/User.java
  11. 46
      src/main/java/com/example/demo/domain/vo/ConsumeUser.java
  12. 26
      src/main/java/com/example/demo/domain/vo/Gold.java
  13. 44
      src/main/java/com/example/demo/domain/vo/GoldDetail.java
  14. 41
      src/main/java/com/example/demo/domain/vo/GoldUser.java
  15. 26
      src/main/java/com/example/demo/domain/vo/Page.java
  16. 64
      src/main/java/com/example/demo/domain/vo/Result.java
  17. 25
      src/main/java/com/example/demo/domain/vo/Total.java
  18. 26
      src/main/java/com/example/demo/mapper/ConsumeMapper.java
  19. 1
      src/main/java/com/example/demo/mapper/GeneralMapper.java
  20. 25
      src/main/java/com/example/demo/mapper/GoldDetailMapper.java
  21. 53
      src/main/java/com/example/demo/mapper/StatisticsMapper.java
  22. 25
      src/main/java/com/example/demo/mapper/UserMapper.java
  23. 6
      src/main/java/com/example/demo/security/TokenFilter.java
  24. 28
      src/main/java/com/example/demo/service/ConsumeService.java
  25. 15
      src/main/java/com/example/demo/service/GeneralService.java
  26. 22
      src/main/java/com/example/demo/service/GoldDetailService.java
  27. 18
      src/main/java/com/example/demo/service/StatisticsService.java
  28. 19
      src/main/java/com/example/demo/service/UserService.java
  29. 163
      src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java
  30. 61
      src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java
  31. 52
      src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java
  32. 222
      src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java
  33. 38
      src/main/java/com/example/demo/serviceImpl/UserServiceImpl.java
  34. 10
      src/main/resources/application.yml
  35. 99
      src/main/resources/mapper/ConsumeMapper.xml
  36. 3
      src/main/resources/mapper/GeneralMapper.xml
  37. 94
      src/main/resources/mapper/GoldDetailMapper.xml
  38. 102
      src/main/resources/mapper/StatisticsMapper.xml
  39. 51
      src/main/resources/mapper/UserMapper.xml

5
pom.xml

@ -84,6 +84,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
</dependencies>
<build>

31
src/main/java/com/example/demo/Util/BusinessException.java

@ -0,0 +1,31 @@
package com.example.demo.Util;
/**
* @program: GOLD
* @ClassName BusinessException
* @description:
* @author: huangqizhen
* @create: 202506-23 14:58
* @Version 1.0
**/
import lombok.Getter;
/**
* 业务异常可抛出到前端
*/
@Getter
public class BusinessException extends RuntimeException {
private int code; // 业务状态码
// 使用默认状态码0的构造方法
public BusinessException(String message) {
this(400, message); // 默认状态码400
}
// 指定状态码的构造方法
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
}

175
src/main/java/com/example/demo/Util/RedisUtil.java

@ -0,0 +1,175 @@
package com.example.demo.Util;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Set;
import java.util.concurrent.*;
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> redisTemplate;
// 线程池用于处理延迟消息
private ExecutorService delayMessageExecutor;
// 延迟消息处理线程数
private static final int DELAY_THREAD_POOL_SIZE = 4;
// 延迟队列轮询间隔(毫秒)
private static final long DELAY_QUEUE_POLL_INTERVAL = 1000L;
@PostConstruct
public void init() {
// 初始化线程池
delayMessageExecutor = Executors.newFixedThreadPool(DELAY_THREAD_POOL_SIZE);
}
/**
* 发送消息到队列
* @param queueName 队列名称
* @param message 消息内容
*/
public void sendMessage(String queueName, Object message) {
redisTemplate.opsForList().rightPush(queueName, message);
}
/**
* 阻塞获取消息(优化版增加重试机制)
* @param queueName 队列名称
* @param timeout 超时时间()
* @return 消息内容
*/
public Object blockingGetMessage(String queueName, long timeout) {
// 分段获取避免长时间阻塞
long endTime = System.currentTimeMillis() + timeout * 1000;
while (System.currentTimeMillis() < endTime) {
Object message = redisTemplate.opsForList().leftPop(queueName, 1, TimeUnit.SECONDS);
if (message != null) {
return message;
}
}
return null;
}
/**
* 非阻塞获取消息
* @param queueName 队列名称
* @return 消息内容
*/
public Object getMessage(String queueName) {
return redisTemplate.opsForList().leftPop(queueName);
}
/**
* 获取队列长度
* @param queueName 队列名称
* @return 队列长度
*/
public Long getQueueSize(String queueName) {
return redisTemplate.opsForList().size(queueName);
}
/**
* 发送延迟消息(优化版)
* @param queueName 队列名称
* @param message 消息内容
* @param delay 延迟时间()
*/
public void sendDelayMessage(String queueName, Object message, long delay) {
String delayQueueKey = getDelayQueueKey(queueName);
String messageId = generateMessageId();
redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) {
connection.openPipeline();
// 直接存储消息内容到ZSet的value中
connection.zAdd(
delayQueueKey.getBytes(),
System.currentTimeMillis() + delay * 1000,
serializeMessage(messageId, message)
);
connection.closePipeline();
return null;
}
});
}
/**
* 启动延迟消息处理任务
*/
@Scheduled(fixedRate = DELAY_QUEUE_POLL_INTERVAL)
public void processDelayMessages() {
Set<String> delayQueues = redisTemplate.keys("delay:*");
if (delayQueues != null) {
for (String delayQueue : delayQueues) {
delayMessageExecutor.execute(() -> {
String queueName = delayQueue.substring(6); // 去掉"delay:"前缀
processSingleDelayQueue(queueName);
});
}
}
}
/**
* 处理单个延迟队列
*/
private void processSingleDelayQueue(String queueName) {
String delayQueueKey = getDelayQueueKey(queueName);
long now = System.currentTimeMillis();
// 获取所有已到期的消息
Set<ZSetOperations.TypedTuple<Object>> messages = redisTemplate.opsForZSet()
.rangeByScoreWithScores(delayQueueKey, 0, now);
if (messages != null && !messages.isEmpty()) {
for (ZSetOperations.TypedTuple<Object> tuple : messages) {
Object messageWithId = tuple.getValue();
if (messageWithId != null) {
// 反序列化消息
Object message = deserializeMessage(messageWithId.toString());
// 发送到实际队列
sendMessage(queueName, message);
// 从延迟队列中移除
redisTemplate.opsForZSet().remove(delayQueueKey, messageWithId);
}
}
}
}
// 生成消息ID
private String generateMessageId() {
return java.util.UUID.randomUUID().toString();
}
// 获取延迟队列key
private String getDelayQueueKey(String queueName) {
return "delay:" + queueName;
}
// 序列化消息(可根据实际需求实现)
private byte[] serializeMessage(String messageId, Object message) {
// 这里简单实现实际项目中可以使用JSON序列化等
return (messageId + ":" + message.toString()).getBytes();
}
// 反序列化消息(可根据实际需求实现)
private Object deserializeMessage(String serialized) {
// 简单实现根据实际序列化方式调整
int separatorIndex = serialized.indexOf(':');
if (separatorIndex > 0) {
return serialized.substring(separatorIndex + 1);
}
return serialized;
}
}

77
src/main/java/com/example/demo/controller/ConsumeController.java

@ -0,0 +1,77 @@
package com.example.demo.controller;
import com.example.demo.domain.entity.UserGoldRecord;
import com.example.demo.domain.vo.ConsumeUser;
import com.example.demo.domain.vo.Gold;
import com.example.demo.domain.vo.Page;
import com.example.demo.domain.vo.Result;
import com.example.demo.service.ConsumeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
/**
* @program: gold-java
* @ClassName ConsumeController
* @description:消费模块
* @author: Double
* @create: 202506-23 13:06
* @Version 1.0
**/
@RestController
@RequestMapping("/consume")
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
public class ConsumeController {
@Autowired
private ConsumeService consumeService;
//消耗明细
@PostMapping("/selectAll")
public Result selcetAll(@RequestBody Page page) {
if (ObjectUtils.isEmpty(page.getPageNum())) {
return Result.error("页码数为空!");
}
if (ObjectUtils.isEmpty(page.getPageSize())) {
return Result.error("页大小为空!");
} else {
return Result.success(consumeService.selectAll(page.getPageNum(), page.getPageSize()));
}
}
//消耗明细筛选
@PostMapping("/selectBy")
public Result selcetBy(@RequestBody Page page) {
if (ObjectUtils.isEmpty(page.getPageNum())) {
return Result.error("页码数为空!");
}
if (ObjectUtils.isEmpty(page.getPageSize())) {
return Result.error("页大小为空!");
} else {
return Result.success(consumeService.selectBy(page.getPageNum(), page.getPageSize(), page.getConsumeUser()));
}
}
//消耗金币统计
@PostMapping("/statsGold")
public Result statsGold() {
Gold gold = consumeService.statsGold();
return Result.success(gold);
}
//消耗金币增加
@PostMapping("/add")
public Result add(@RequestBody ConsumeUser consumeUser) {
return consumeService.add(consumeUser);
}
}

6
src/main/java/com/example/demo/controller/GeneralController.java

@ -41,4 +41,10 @@ public class GeneralController {
List<String> list = generalService.getPlatform();
return Result.success(list);
}
@PostMapping("/goods")
public Result getGoods()
{
List<String> list = generalService.getGoods();
return Result.success(list);
}
}

60
src/main/java/com/example/demo/controller/GoldDetailController.java

@ -0,0 +1,60 @@
package com.example.demo.controller;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.GoldDetail;
import com.example.demo.domain.vo.Page;
import com.example.demo.domain.vo.Result;
import com.example.demo.service.GoldDetailService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
/**
* @program: GOLD
* @ClassName GoldDetailController
* @description:
* @author: huangqizhen
* @create: 202506-23 14:41
* @Version 1.0
**/
@RestController
@RequestMapping("/goldDetail")
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
public class GoldDetailController {
private final GoldDetailService goldDetailService;
@PostMapping("/getGoldDetail")
public Result getGoldDetail(@RequestBody Page page){
if(ObjectUtils.isEmpty(page.getPageNum())){
return Result.error("页码数为空!");
}
if(ObjectUtils.isEmpty(page.getPageSize())){
return Result.error("页大小为空!");
}
else{
return Result.success(goldDetailService.getGoldDetail(page.getPageNum(), page.getPageSize(), page.getGoldDetail()));
}
}
@PostMapping("/getTotal")
public Result getTotal(@RequestBody GoldDetail goldDetail) {
return Result.success(goldDetailService.getTotal(goldDetail));
}
@PostMapping("/goldTotal")
public Result GoldTotal(@RequestBody User user) {
return Result.success(goldDetailService.GoldTotal(user));
}
@PostMapping("/getGold")
public Result getGold(@RequestBody Page page) {
if(ObjectUtils.isEmpty(page.getPageNum())){
return Result.error("页码数为空!");
}
if(ObjectUtils.isEmpty(page.getPageSize())){
return Result.error("页大小为空!");
}
return Result.success(goldDetailService.getGold(page.getPageNum(), page.getPageSize(), page.getUser()));
}
}

18
src/main/java/com/example/demo/controller/StatisticsController.java

@ -1,13 +1,20 @@
package com.example.demo.controller;
import com.example.demo.domain.entity.Statistics;
import com.example.demo.domain.vo.Result;
import com.example.demo.service.GeneralService;
import com.example.demo.service.StatisticsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List;
/**
* @program: gold-java
* @ClassName StatisticsController
@ -25,4 +32,15 @@ import org.springframework.web.bind.annotation.RestController;
public class StatisticsController {
@Autowired
private StatisticsService statisticsService;
@Autowired
private GeneralService generalService;
//测试定时任务1
@PostMapping("/Hourly")
public void HourlyTask() {
statisticsService.runHourlyTask();
}
}

37
src/main/java/com/example/demo/controller/UserController.java

@ -0,0 +1,37 @@
package com.example.demo.controller;
import com.example.demo.domain.vo.Gold;
import com.example.demo.domain.vo.GoldUser;
import com.example.demo.domain.vo.Result;
import com.example.demo.service.ConsumeService;
import com.example.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @program: gold-java
* @ClassName UserController
* @description:
* @author: Double
* @create: 202506-25 10:25
* @Version 1.0
**/
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
@Slf4j
@CrossOrigin
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/selectUser")
public Result selectUser(@RequestBody GoldUser user) {
user = userService.selectUser(user.getJwcode().toString());
return Result.success(user);
}
}

33
src/main/java/com/example/demo/domain/entity/Export.java

@ -0,0 +1,33 @@
package com.example.demo.domain.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* @program: GOLD
* @ClassName Export
* @description:
* @author: huangqizhen
* @create: 202506-24 16:17
* @Version 1.0
**/
@Data
@NoArgsConstructor
public class Export {
private String token;
private Integer account;
private String url;
private String fileName;
private Byte type;
private Byte state;
private Integer dataNum;
private String reason;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date updateTime;
}

3
src/main/java/com/example/demo/domain/entity/User.java

@ -27,6 +27,7 @@ public class User implements Serializable {
private Integer currentFreeDecember; // 当前十二月免费金币
private Integer currentTaskGold; // 当前任务金币
private Integer rechargeNum; // 充值次数
private Integer sumConsume; // 消费总额
private Integer consumeNum; // 消费次数
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai")
@ -37,4 +38,6 @@ public class User implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date updateTime; // 更新时间
private String sortField; //排序字段
private String sortOrder; //排序顺序
}

46
src/main/java/com/example/demo/domain/vo/ConsumeUser.java

@ -0,0 +1,46 @@
package com.example.demo.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* @program: gold-java
* @ClassName Consume
* @description: 消费明细
* @author: Double
* @create: 202506-23 11:53
* @Version 1.0
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ConsumeUser implements Serializable {
private static final long serialVersionUID = 1L;
private String name; // 客户姓名
private Integer jwcode; // 精网号
private String market; // 所属地区
private String goodsName; // 商品名称
private String payPlatform; // 消费平台
private Integer sumGold; // 金币总数
private Integer permanentGold; // 永久金币
private Integer freeGold; // 免费金币
private Integer taskGold; // 任务金币
private String remark; // 备注
private Integer adminId; //提交人Id
private String adminName; //提交人姓名
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date payTime; // 消费时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date startTime; // 开始时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date endTime; // 结束时间
}

26
src/main/java/com/example/demo/domain/vo/Gold.java

@ -0,0 +1,26 @@
package com.example.demo.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @program: gold-java
* @ClassName Gold
* @description: 金币信息
* @author: Double
* @create: 202506-23 15:53
* @Version 1.0
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Gold implements Serializable {
private static final long serialVersionUID = 1L;
private Integer permanentGolds; // 永久金币总数
private Integer freeGolds; // 免费金币总数
private Integer taskGolds; // 任务金币总数
}

44
src/main/java/com/example/demo/domain/vo/GoldDetail.java

@ -0,0 +1,44 @@
package com.example.demo.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* @program: GOLD
* @ClassName GoldDetail
* @description:
* @author: huangqizhen
* @create: 202506-23 13:03
* @Version 1.0
**/
@Data
@NoArgsConstructor
public class GoldDetail {
private static final long serialVersionUID = 1L;
private String token;
private String name; // 名称
private Integer jwcode; // 精网号
private String market; // 所属地区
private String payPlatform; // 支付平台
private Integer type; // 类型
private Integer sumGold; // 总金币
private Integer permanentGold; //永久金币
private Integer freeJune; // 免费金币六月到期
private Integer freeDecember; // 免费金币七月到期
private Integer taskGold; // 任务金币
private String adminName; //提交人
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date startTime; // 开始时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date endTime; // 结束时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date auditTime; // 更新时间
private String sortField; //排序字段
private String sortOrder; //排序顺序
}

41
src/main/java/com/example/demo/domain/vo/GoldUser.java

@ -0,0 +1,41 @@
package com.example.demo.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @program: gold-java
* @ClassName ConsumeUser
* @description:
* @author: Double
* @create: 202506-24 18:30
* @Version 1.0
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GoldUser {
private String name; // 客户姓名
private Integer jwcode; // 精网号
private String market; // 所属地区
private Integer NowSumGold; // 当前金币总数
private Integer NowPermanentGold; // 当前永久金币
private Integer NowFreeGold; // 当前免费金币
private Integer NowFreeJune; // 免费金币6月
private Integer NowFreeDecember; // 免费金币12月
private Integer NowTaskGold; // 当前任务金币
private Integer historySumGold; // 历史金币总数
private Integer historyPermanentGold; // 历史永久金币
private Integer historyFreeGold; // 历史免费金币
private Integer historyTaskGold; // 历史任务金币
private Integer rechargeNum; // 充值次数
private Integer consumeNum; // 消费次数
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai")
private Date firstRecharge; // 首充日期
}

26
src/main/java/com/example/demo/domain/vo/Page.java

@ -0,0 +1,26 @@
package com.example.demo.domain.vo;
import com.example.demo.domain.entity.User;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: GOLD
* @ClassName Page
* @description:
* @author: huangqizhen
* @create: 202506-23 16:23
* @Version 1.0
**/
@Data
@NoArgsConstructor
public class Page {
private static final long serialVersionUID = 1L;
private Integer pageNum;
private Integer pageSize;
private GoldDetail goldDetail;
private ConsumeUser consumeUser;
private User user;
}

64
src/main/java/com/example/demo/domain/vo/Result.java

@ -1,5 +1,6 @@
package com.example.demo.domain.vo;
import com.example.demo.Util.BusinessException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
@ -8,40 +9,67 @@ import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.HashMap;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result implements Serializable {
private static final long serialVersionUID = 1L;
private Integer code;
private String msg;
private Object data;
private Integer code; // 响应码200 代表成功401 代表未授权
private String msg; // 响应消息
private Object data; // 返回的数据
public static Result success(Integer code, String msg, Object data) {
return new Result(code, msg, data);
// 成功响应不需要给前端返回数据
public static Result success() {
return new Result(200, "success", new HashMap<>());
}
public static Result success(Integer code, Object data) {
return success(code, "操作成功", data);
// 查询成功响应把查询结果作为返回数据响应给前端
public static Result success(Object data) {
return new Result(200, "success", data);
}
public static Result success(String msg, Object data) {return success(200, msg, data);}
public static Result success(Object data){
return success(200, data);
// 失败响应
public static Result error(String msg) {
return new Result(0, msg, new HashMap<>());
}
public static Result success(){
return success(null);
// 失败响应可以自定义错误码
public static Result error(int code, String msg) {
return new Result(code, msg, new HashMap<>());
}
public static Result error(Integer code, String msg, Object data){
return new Result(code, msg, data);
// 成功响应可以自定义消息和数据
public static Result success(String msg, HashMap<String, Object> resultData) {
return new Result(200, msg, resultData); // 返回成功响应状态码为 200
}
public static Result error(Integer code, String msg){
return error(code, msg, null);
// 未授权响应可以自定义错误码
public static Result unauthorized(int code, String msg) {
return new Result(code, msg, new HashMap<>());
}
public static Result error(String msg){
return error(0, msg);
// 错误响应状态码为200code为401
public static Result unauthorized(String msg) {
return new Result(401, msg, new HashMap<>());
}
//失败响应 自定义状态码 默认为500
public static Result error(BusinessException e) {
Result response = new Result();
// 定义默认错误码映射
final int defaultErrorCode = 400;
// 检查 getCode() 是否为 null如果是 Integer
Integer code = e.getCode();
if (code == null || code == 0) {
response.setCode(defaultErrorCode); // 默认错误码
} else {
response.setCode(code);
}
response.setMsg(e.getMessage());
return response;
}
public String toJson() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(this);

25
src/main/java/com/example/demo/domain/vo/Total.java

@ -0,0 +1,25 @@
package com.example.demo.domain.vo;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: GOLD
* @ClassName Total
* @description:
* @author: huangqizhen
* @create: 202506-23 16:53
* @Version 1.0
**/
@Data
@NoArgsConstructor
public class Total {
private static final long serialVersionUID = 1L;
private String token;
private Integer Goldtotal;
private Integer permanentGold;
private Integer freeGold;
private Integer taskGold;
}

26
src/main/java/com/example/demo/mapper/ConsumeMapper.java

@ -0,0 +1,26 @@
package com.example.demo.mapper;
import com.example.demo.domain.entity.UserGoldRecord;
import com.example.demo.domain.vo.ConsumeUser;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @program: gold-java
* @ClassName ConsumeMapper
* @description:
* @author: Double
* @create: 202506-23 13:45
* @Version 1.0
**/
@Mapper
public interface ConsumeMapper {
List<ConsumeUser> selectAll();
List<ConsumeUser> selectBy(ConsumeUser consumeUser);
void add(UserGoldRecord userGoldRecord);
}

1
src/main/java/com/example/demo/mapper/GeneralMapper.java

@ -16,4 +16,5 @@ import java.util.List;
public interface GeneralMapper {
List<String> getMarket();
List<String> getPlatform();
List<String> getGoods();
}

25
src/main/java/com/example/demo/mapper/GoldDetailMapper.java

@ -0,0 +1,25 @@
package com.example.demo.mapper;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.GoldDetail;
import com.example.demo.domain.vo.Total;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @program: GOLD
* @ClassName GoldDetailMapper
* @description:
* @author: huangqizhen
* @create: 202506-23 13:47
* @Version 1.0
**/
@Mapper
public interface GoldDetailMapper {
List<GoldDetail> getGoldDetail(GoldDetail goldDetail);
Total getTotal(GoldDetail goldDetail);
List<User> getGold(User user);
Total GoldTotal(User user);
}

53
src/main/java/com/example/demo/mapper/StatisticsMapper.java

@ -0,0 +1,53 @@
package com.example.demo.mapper;
import com.example.demo.domain.entity.Statistics;
import com.example.demo.domain.entity.UserGoldRecord;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
* @program: gold-java
* @ClassName StatisticsMapper
* @description:
* @author: Ethan
* @create: 202506-23 14:08
* @Version 1.0
**/
@Mapper
public interface StatisticsMapper {
//根据地区审核状态起止时间查询订单表数据
List<UserGoldRecord> findByMarketAndAuditStatus(@Param("market") String market,
@Param("auditStatusList") List<Integer> auditStatusList,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime);
//获取某地区当前永久金币余量
Integer sumCurrentPermanentGold(@Param("market") String market);
//获取某地区当前六月免费金币余量
Integer sumCurrentFreeJune(@Param("market") String market);
//获取某地区当前永久金币余量
Integer sumCurrentFreeDecember(@Param("market") String market);
//获取某地区当前永久金币余量
Integer sumCurrentTaskGold(@Param("market") String market);
//计算该天充值人数
int countRechargeNum(
@Param("market") String market,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime);
//计算该天首充人数
int countFirstRecharge(
@Param("market") String market,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime);
//新增part2统计数据
void insertPart2(Statistics statistics);
//更新part2统计数据
void updatePart2(Statistics statistics);
//获取某地区某天的数据
Statistics selectByMarketAndDate(@Param("market") String market,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate);
}

25
src/main/java/com/example/demo/mapper/UserMapper.java

@ -0,0 +1,25 @@
package com.example.demo.mapper;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.Gold;
import com.example.demo.domain.vo.GoldUser;
import org.apache.ibatis.annotations.Mapper;
/**
* @program: gold-java
* @ClassName UserMapper
* @description:
* @author: Double
* @create: 202506-25 10:40
* @Version 1.0
**/
@Mapper
public interface UserMapper {
GoldUser selectUser(String jwcode);
GoldUser selectGold(String jwcode);
void updateGold(User user);
}

6
src/main/java/com/example/demo/security/TokenFilter.java

@ -228,8 +228,8 @@ public class TokenFilter extends OncePerRequestFilter {
// 检查是否是上传请求
boolean isErpRequest = request.getRequestURI().startsWith("/ERP") || request.getRequestURI().contains("ERP");
boolean isUploadRequest = request.getRequestURI().startsWith("/upload");
System.out.println(request.getRequestURI());
System.out.println(isUploadRequest);
// System.out.println(request.getRequestURI());
// System.out.println(isUploadRequest);
if (isUploadRequest ) {
// 如果是上传请求直接将请求传递给下一个过滤器或目标资源
filterChain.doFilter(request, response);
@ -237,7 +237,7 @@ public class TokenFilter extends OncePerRequestFilter {
} else {
// 使用RequestWrapper包装原始的HttpServletRequest使其输入流可以被重复读取
RequestWrapper requestWrapper = new RequestWrapper(request);
System.out.println(request);
// System.out.println(request);
// 确保请求体只被读取一次
boolean hasRequestBody = "POST".equals(requestWrapper.getMethod());

28
src/main/java/com/example/demo/service/ConsumeService.java

@ -0,0 +1,28 @@
package com.example.demo.service;
import com.example.demo.domain.entity.UserGoldRecord;
import com.example.demo.domain.vo.ConsumeUser;
import com.example.demo.domain.vo.Gold;
import com.example.demo.domain.vo.Result;
import com.github.pagehelper.PageInfo;
/**
* @program: gold-java
* @ClassName ConsumeService
* @description: 消费模块
* @author: Double
* @create: 202506-23 13:58
* @Version 1.0
**/
public interface ConsumeService {
PageInfo<ConsumeUser> selectAll(Integer pageNum, Integer pageSize);
Gold statsGold();
PageInfo<ConsumeUser> selectBy(Integer pageNum, Integer pageSize, ConsumeUser consumeUser);
Result add(ConsumeUser consumeUser);
}

15
src/main/java/com/example/demo/service/GeneralService.java

@ -1,5 +1,9 @@
package com.example.demo.service;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
/**
@ -12,6 +16,17 @@ import java.util.List;
**/
public interface GeneralService {
//获取所有市场地区
List<String> getMarket();
//获取平台
List<String> getPlatform();
List<String> getGoods();
//获取昨天的日期
Date getYesterday();
//获取某天的开始时间(00:00:00)
Date getStartOfDay(Date date);
//转换日期格式为yyyy-MM-dd
String formatDate(Date date) ;
//获取时间段内的所有日期包含起始和结束日
List<Date> getAllDatesBetween(Date start, Date end);
}

22
src/main/java/com/example/demo/service/GoldDetailService.java

@ -0,0 +1,22 @@
package com.example.demo.service;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.GoldDetail;
import com.example.demo.domain.vo.Total;
import com.github.pagehelper.PageInfo;
/**
* @program: GOLD
* @ClassName GoldDetailService
* @description:
* @author: huangqizhen
* @create: 202506-23 11:59
* @Version 1.0
**/
public interface GoldDetailService {
PageInfo<GoldDetail> getGoldDetail(Integer pageNum, Integer pageSize, GoldDetail goldDetail);
Total getTotal(GoldDetail goldDetail);
PageInfo<User> getGold(Integer pageNum, Integer pageSize, User user);
Total GoldTotal(User user);
}

18
src/main/java/com/example/demo/service/StatisticsService.java

@ -1,5 +1,9 @@
package com.example.demo.service;
import com.example.demo.domain.entity.Statistics;
import java.util.Date;
/**
* @program: gold-java
* @ClassName StatisticsService
@ -11,4 +15,18 @@ package com.example.demo.service;
public interface StatisticsService {
//12点18点执行定时任务更新当天数据
public void runHourlyTask();
//0点执行定时任务更新近一周数据
public void runDailyTask();
//查询某地区某天是否已存在统计数据
public Statistics getExistStatistics(String market,Date date);
//新增或更新或不修改某地区某天统计数据
public void saveStatistics(String market, Date date);
//根据地区与日期获取part1(余量属性)统计数据
public Statistics getStatisticsPart1(String market, Date date);
//根据地区与日期获取part2(余量外属性)统计数据
public Statistics getStatisticsPart2(String market, Date date);
}

19
src/main/java/com/example/demo/service/UserService.java

@ -0,0 +1,19 @@
package com.example.demo.service;
import com.example.demo.domain.vo.Gold;
import com.example.demo.domain.vo.GoldUser;
/**
* @program: gold-java
* @ClassName UserService
* @description:
* @author: Double
* @create: 202506-25 10:30
* @Version 1.0
**/
public interface UserService {
GoldUser selectUser(String jwcode);
GoldUser selectgold(String jwcode);
}

163
src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java

@ -0,0 +1,163 @@
package com.example.demo.serviceImpl;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.entity.UserGoldRecord;
import com.example.demo.domain.vo.ConsumeUser;
import com.example.demo.domain.vo.Gold;
import com.example.demo.domain.vo.GoldUser;
import com.example.demo.domain.vo.Result;
import com.example.demo.mapper.ConsumeMapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.ConsumeService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @program: gold-java
* @ClassName ConsumeServiceImpl
* @description: 消费模块
* @author: Double
* @create: 202506-23 13:58
* @Version 1.0
**/
@Service
public class ConsumeServiceImpl implements ConsumeService {
@Autowired
private ConsumeMapper consumeMapper;
@Autowired
private UserMapper userMapper;
//消耗明细
@Override
public PageInfo<ConsumeUser> selectAll(Integer pageNum, Integer pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<ConsumeUser> consumeUsers = consumeMapper.selectAll();
return new PageInfo<>(consumeUsers);
}
//消耗金币统计
@Override
public Gold statsGold() {
Gold gold = new Gold();
List<ConsumeUser> consumeUsers = consumeMapper.selectAll();
// 初始化累加器
int permanentGoldSum = 0;
int freeGoldSum = 0;
int taskGoldSum = 0;
// 遍历消费记录并累加金币
for (ConsumeUser consumeUser : consumeUsers) {
// 累加永久金币
if (consumeUser.getPermanentGold() != null) {
permanentGoldSum += consumeUser.getPermanentGold();
}
// 累加免费金币
if (consumeUser.getFreeGold() != null) {
freeGoldSum += consumeUser.getFreeGold();
}
// 累加任务金币
if (consumeUser.getTaskGold() != null) {
taskGoldSum += consumeUser.getTaskGold();
}
}
// 将累加结果设置到Gold对象
gold.setPermanentGolds(permanentGoldSum);
gold.setFreeGolds(freeGoldSum);
gold.setTaskGolds(taskGoldSum);
return gold;
}
//消耗明细筛选
@Override
public PageInfo<ConsumeUser> selectBy(Integer pageNum, Integer pageSize, ConsumeUser consumeUser) {
PageHelper.startPage(pageNum, pageSize);
List<ConsumeUser> consumeUsers = consumeMapper.selectBy(consumeUser);
return new PageInfo<>(consumeUsers);
}
//新增消耗
@Override
public Result add(ConsumeUser consumeUser) {
UserGoldRecord userGoldRecord = new UserGoldRecord();
// 获取当前时间戳部分
String timestampPart = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
// 获取自增计数器部分三位数不足补零
AtomicInteger atomicInteger = new AtomicInteger(0);
int count = atomicInteger.getAndUpdate(c -> (c >= 999) ? 0 : c + 1);
String counterPart = String.format("%03d", count);
// 生成随机数部分四位数
Random RANDOM = new Random();
int randomNum = RANDOM.nextInt(9000) + 1000;
//订单号生成
userGoldRecord.setOrderCode(timestampPart + counterPart + randomNum);
userGoldRecord.setJwcode(consumeUser.getJwcode());
userGoldRecord.setGoodsName(consumeUser.getGoodsName());
userGoldRecord.setSumGold(consumeUser.getSumGold());
userGoldRecord.setPermanentGold(consumeUser.getPermanentGold());
// 获取当前月份1-12
int currentMonth = LocalDate.now().getMonthValue();
GoldUser gold = userMapper.selectGold(consumeUser.getJwcode().toString());
if(consumeUser.getFreeGold()>(gold.getNowFreeDecember()+ gold.getNowFreeJune())||consumeUser.getPermanentGold()>gold.getNowPermanentGold()
||consumeUser.getTaskGold()>gold.getNowTaskGold()){
return Result.error("金币数量不足");
}
// 根据当前月份设置对应字段
if (currentMonth >= 1 && currentMonth <= 6) {
// 1-6月设置6月额度12月保持默认值
if(consumeUser.getFreeGold()>gold.getNowFreeJune()) {
userGoldRecord.setFreeJune(gold.getNowFreeJune());
userGoldRecord.setFreeDecember(consumeUser.getFreeGold()-gold.getNowFreeJune());
}else {
userGoldRecord.setFreeJune(consumeUser.getFreeGold());
userGoldRecord.setFreeDecember(0);
}
} else {
// 7-12月设置12月额度6月保持默认值
if(consumeUser.getFreeGold()>gold.getNowFreeDecember()) {
userGoldRecord.setFreeDecember(gold.getNowFreeDecember());
userGoldRecord.setFreeJune(consumeUser.getFreeGold()-gold.getNowFreeDecember());
}else {
userGoldRecord.setFreeDecember(consumeUser.getFreeGold());
userGoldRecord.setFreeJune(0);
}
}
userGoldRecord.setTaskGold(consumeUser.getTaskGold());
userGoldRecord.setRemark(consumeUser.getRemark());
userGoldRecord.setType((byte) 1);
userGoldRecord.setIsRefund((byte) 0);
userGoldRecord.setAdminId(consumeUser.getAdminId());
userGoldRecord.setCreateTime(new Date());
userGoldRecord.setPayTime(new Date());
consumeMapper.add(userGoldRecord);
User user = new User();
user.setJwcode(userGoldRecord.getJwcode());
user.setCurrentPermanentGold(gold.getNowPermanentGold()-consumeUser.getPermanentGold());
user.setCurrentFreeJune(gold.getNowFreeJune()-userGoldRecord.getFreeJune());
user.setCurrentFreeDecember(gold.getNowFreeDecember()-userGoldRecord.getFreeDecember());
user.setCurrentTaskGold(gold.getNowTaskGold()-consumeUser.getTaskGold());
user.setConsumeNum(gold.getConsumeNum()-1);
userMapper.updateGold(user);
return Result.success();
}
}

61
src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java

@ -5,6 +5,12 @@ import com.example.demo.service.GeneralService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
@ -32,4 +38,59 @@ public class GeneralServiceImpl implements GeneralService {
List<String> list = generalMapper.getPlatform();
return list;
}
@Override
public List<String> getGoods() {
List<String> list = generalMapper.getGoods();
return list;
}
/*
获取昨天的日期
*/
@Override
public Date getYesterday() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -1); //当前天数-1
return getStartOfDay(cal.getTime()); //昨天的00:00:00
}
/*
获取某天的开始时间(00:00:00)
*/
@Override
public Date getStartOfDay(Date date) {
LocalDateTime localDate = date.toInstant()
.atZone(ZoneId.systemDefault()) // 转换为本地时区
.toLocalDateTime()
.with(LocalTime.MIN); // 设置时间为当天 00:00:00
return Date.from(localDate.atZone(ZoneId.systemDefault()).toInstant());
}
/*
转换日期格式为yyyy-MM-dd
*/
@Override
public String formatDate(Date date) {
return date.toInstant()
.atZone(ZoneId.systemDefault())
.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE); // 输出格式如 "2025-10-01"
}
/*
获取时间段内的所有日期包含起始和结束日
*/
@Override
public List<Date> getAllDatesBetween(Date start, Date end) {
List<Date> dates = new ArrayList<>();
//初始化日历对象
Calendar tempStart = Calendar.getInstance();
tempStart.setTime(start);
Calendar tempEnd = Calendar.getInstance();
tempEnd.setTime(end);
while (!tempStart.after(tempEnd)) {
dates.add(tempStart.getTime()); // 将当前日期添加到列表中
tempStart.add(Calendar.DAY_OF_YEAR, 1); // 每次增加一天
}
return dates;
}
}

52
src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java

@ -0,0 +1,52 @@
package com.example.demo.serviceImpl;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.GoldDetail;
import com.example.demo.domain.vo.Total;
import com.example.demo.mapper.GoldDetailMapper;
import com.example.demo.service.GoldDetailService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @program: GOLD
* @ClassName GoldDetailServiceImpl
* @description:
* @author: huangqizhen
* @create: 202506-23 13:44
* @Version 1.0
**/
@Service
public class GoldDetailServiceImpl implements GoldDetailService {
@Autowired
private GoldDetailMapper goldDetailMapper;
@Override
public PageInfo<GoldDetail> getGoldDetail(Integer pageNum, Integer pageSize, GoldDetail goldDetail) {
PageHelper.startPage(pageNum, pageSize);
List<GoldDetail> list= goldDetailMapper.getGoldDetail(goldDetail);
return new PageInfo<>(list);
}
@Override
public Total getTotal(GoldDetail goldDetail) {
return goldDetailMapper.getTotal(goldDetail);
}
@Override
public PageInfo<User> getGold(Integer pageNum, Integer pageSize, User user) {
PageHelper.startPage(pageNum, pageSize);
List<User> list= goldDetailMapper.getGold(user);
return new PageInfo<>(list);
}
@Override
public Total GoldTotal(User user) {
return goldDetailMapper.GoldTotal(user);
}
}

222
src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java

@ -1,8 +1,21 @@
package com.example.demo.serviceImpl;
import com.example.demo.domain.entity.Statistics;
import com.example.demo.domain.entity.UserGoldRecord;
import com.example.demo.mapper.StatisticsMapper;
import com.example.demo.service.GeneralService;
import com.example.demo.service.StatisticsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
/**
* @program: gold-java
* @ClassName StatisticsServiceImpl
@ -14,4 +27,213 @@ import org.springframework.stereotype.Service;
@Service
public class StatisticsServiceImpl implements StatisticsService {
private static final Logger log = LoggerFactory.getLogger(StatisticsServiceImpl.class);
@Autowired
private StatisticsMapper statisticsMapper;
@Autowired
private GeneralService generalService;
/*
12点18点执行定时任务更新当天数据
*/
@Override
@Scheduled(cron = "0 0 12,18 * * ?")
public void runHourlyTask() {
Date today = new Date(); //取当天日期
for(String market : generalService.getMarket()){
saveStatistics(market,today);
}
}
/*
0点执行定时任务更新近一周数据
*/
@Override
@Scheduled(cron = "0 0 0 * * ?")
public void runDailyTask() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -7); // 一周前
Date startDate = cal.getTime();
Date endDate = generalService.getYesterday(); // 昨天
//近一周的日期列表
List<Date> dateList =generalService.getAllDatesBetween(startDate, endDate);
for (Date date : dateList) {
for (String market : generalService.getMarket()) {
saveStatistics(market, date);
}
}
}
/*
查询某地区某天已存在的统计数据
*/
@Override
public Statistics getExistStatistics(String market, Date date) {
LocalDateTime startTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN);
LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1);
return statisticsMapper.selectByMarketAndDate(market,
Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),
Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
}
/*
新增或更新或不修改某地区某天统计数据
*/
@Override
public void saveStatistics(String market, Date date){
//获取该地区该日期part2(余量外属性)统计数据
Statistics newStats=getStatisticsPart2(market,date);
//获取该地区该日期已存在的数据
Statistics existStats = getExistStatistics(market, date);
//判断是否存在已存在的数据
if(existStats==null){
//没有记录新增
statisticsMapper.insertPart2(newStats );
}else {
//判断新旧数据part2部分(余量外属性)是否一致
if (!isSameStatisticsPart2(existStats,newStats)){
statisticsMapper.updatePart2(newStats);
}else{
log.atInfo().log("数据未发生改变");
}
}
}
//根据地区与日期获取part1(余量属性)统计数据
@Override
public Statistics getStatisticsPart1(String market, Date date) {
//初始化Statistics对象
Statistics statistics = new Statistics();
statistics.setMarket(market);
//计算属性
//当前金币余量
Integer currentGold = statisticsMapper.sumCurrentPermanentGold(market)+
statisticsMapper.sumCurrentFreeJune( market)+
statisticsMapper.sumCurrentFreeDecember(market)+
statisticsMapper.sumCurrentTaskGold( market);
statistics.setCurrentGold(currentGold);
//当前永久金币
Integer currentPermanent = statisticsMapper.sumCurrentPermanentGold(market);
statistics.setCurrentPermanent(currentPermanent);
//当前免费六月金币
Integer currentFreeJune = statisticsMapper.sumCurrentFreeJune(market);
statistics.setCurrentFreeJune(currentFreeJune);
//当前免费十二月金币
Integer currentFreeDecember = statisticsMapper.sumCurrentFreeDecember(market);
statistics.setCurrentFreeDecember(currentFreeDecember);
//当前任务金币
Integer currentTask = statisticsMapper.sumCurrentTaskGold(market);
statistics.setCurrentTask(currentTask);
return statistics;
}
/*
根据地区与日期获取part2(余量外属性)统计数据
*/
@Override
public Statistics getStatisticsPart2(String market, Date date) {
//把date改为当天的开始时间和结束时间
LocalDateTime startTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN);
LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1);
//定义审核状态列表
List<Integer> auditStatusList = new ArrayList<>();
auditStatusList.add(1); // 审核通过
auditStatusList.add(3); // 外部传入默认通过
//查询当天该地区审核通过的所有数据
List<UserGoldRecord> records = statisticsMapper.findByMarketAndAuditStatus(market, auditStatusList,
Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
//初始化Statistics对象
Statistics statistics = new Statistics();
statistics.setMarket(market);
statistics.setCurrentDatetime(date);
//计算属性
//充值相关-当日充值永久+免费
Integer recharge = records.stream()
.filter(record -> record.getType() == 0) // 类型为充值
.mapToInt(record -> record.getPermanentGold() + record.getFreeJune() + record.getFreeDecember() + record.getTaskGold())
.sum();
statistics.setRecharge(recharge);
//充值相关-当日金额永久
Integer money = records.stream()
.filter(record -> record.getType() == 0) // 类型为充值
.mapToInt(UserGoldRecord::getPermanentGold)
.sum();
statistics.setMoney(money);
//消费相关-当日新增消费永久
Integer consumePermanent = records.stream()
.filter(record -> record.getType() == 1) // 类型为消费
.mapToInt(UserGoldRecord::getPermanentGold)
.sum();
statistics.setConsumePermanent(consumePermanent);
//消费相关-当日新增消费六月免费
Integer consumeFreeJune = records.stream()
.filter(record -> record.getType() == 1) // 类型为消费
.mapToInt(UserGoldRecord::getFreeJune)
.sum();
statistics.setConsumeFreeJune(consumeFreeJune);
//消费相关-当日新增消费十二月免费
Integer consumeFreeDecember = records.stream()
.filter(record -> record.getType() == 1) // 类型为消费
.mapToInt(UserGoldRecord::getFreeDecember)
.sum();
statistics.setConsumeFreeDecember(consumeFreeDecember);
//消费相关-当日新增消费任务
Integer consumeTask = records.stream()
.filter(record -> record.getType() == 1) // 类型为消费
.mapToInt(UserGoldRecord::getTaskGold)
.sum();
statistics.setConsumeTask(consumeTask);
//退款相关-当日退款永久
Integer refundPermanent = records.stream()
.filter(record -> record.getType() == 2) // 类型为退款
.mapToInt(UserGoldRecord::getPermanentGold)
.sum();
statistics.setRefundPermanent(refundPermanent);
//退款相关-当日退款六月免费
Integer refundFreeJune = records.stream()
.filter(record -> record.getType() == 2) // 类型为退款
.mapToInt(UserGoldRecord::getFreeJune)
.sum();
statistics.setRefundFreeJune(refundFreeJune);
//退款相关-当日退款十二月免费
Integer refundFreeDecember = records.stream()
.filter(record -> record.getType() == 2) // 类型为退款
.mapToInt(UserGoldRecord::getFreeDecember)
.sum();
statistics.setRefundFreeDecember(refundFreeDecember);
//退款相关-当日退款任务
Integer refundTask = records.stream()
.filter(record -> record.getType() == 2) // 类型为退款
.mapToInt(UserGoldRecord::getTaskGold)
.sum();
statistics.setRefundTask(refundTask);
//充值人数
int rechargeNum= statisticsMapper.countRechargeNum(market,Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
statistics.setRechargeNum(rechargeNum);
//首充人数
int firstRecharge= statisticsMapper.countFirstRecharge(market,Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()),Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()));
statistics.setFirstRecharge(firstRecharge);
return statistics;
}
/*
* 判断两个统计对象part2(余量外属性)是否相同
*/
private boolean isSameStatisticsPart2(Statistics oldStats, Statistics newStats) {
return Objects.equals(oldStats.getRecharge(), newStats.getRecharge()) &&
Objects.equals(oldStats.getMoney(), newStats.getMoney()) &&
Objects.equals(oldStats.getConsumePermanent(), newStats.getConsumePermanent()) &&
Objects.equals(oldStats.getConsumeFreeJune(), newStats.getConsumeFreeJune()) &&
Objects.equals(oldStats.getConsumeFreeDecember(), newStats.getConsumeFreeDecember()) &&
Objects.equals(oldStats.getConsumeTask(), newStats.getConsumeTask()) &&
Objects.equals(oldStats.getRefundPermanent(), newStats.getRefundPermanent()) &&
Objects.equals(oldStats.getRefundFreeJune(), newStats.getRefundFreeJune()) &&
Objects.equals(oldStats.getRefundFreeDecember(), newStats.getRefundFreeDecember()) &&
Objects.equals(oldStats.getRefundTask(), newStats.getRefundTask()) &&
Objects.equals(oldStats.getRechargeNum(), newStats.getRechargeNum()) &&
Objects.equals(oldStats.getFirstRecharge(), newStats.getFirstRecharge()) &&
Objects.equals(oldStats.getCurrentGold(), newStats.getCurrentGold()) &&
Objects.equals(oldStats.getDailyChange(), newStats.getDailyChange()) &&
Objects.equals(oldStats.getCurrentPermanent(), newStats.getCurrentPermanent()) &&
Objects.equals(oldStats.getCurrentFreeJune(), newStats.getCurrentFreeJune()) &&
Objects.equals(oldStats.getCurrentFreeDecember(), newStats.getCurrentFreeDecember()) &&
Objects.equals(oldStats.getCurrentTask(), newStats.getCurrentTask());
}
}

38
src/main/java/com/example/demo/serviceImpl/UserServiceImpl.java

@ -0,0 +1,38 @@
package com.example.demo.serviceImpl;
import com.example.demo.domain.vo.Gold;
import com.example.demo.domain.vo.GoldUser;
import com.example.demo.mapper.ConsumeMapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @program: gold-java
* @ClassName UserServiceImpl
* @description:
* @author: Double
* @create: 202506-25 10:32
* @Version 1.0
**/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public GoldUser selectUser(String jwcode) {
GoldUser user = userMapper.selectUser(jwcode);
return user;
}
@Override
public GoldUser selectgold(String jwcode) {
GoldUser gold = userMapper.selectGold(jwcode);
return gold;
}
}

10
src/main/resources/application.yml

@ -4,7 +4,7 @@ spring:
fail-on-unknown-properties: false
datasource:
mysql1:
jdbc-url: jdbc:mysql://localhost:3306/hwgold?serverTimezone=Asia/Shanghai
jdbc-url: jdbc:mysql://192.168.8.220:3306/hwgold?serverTimezone=Asia/Shanghai
username: hwgold
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
@ -62,9 +62,9 @@ spring:
data:
redis:
database: 0
host: 54.251.137.151
port: 10703
password: 8912h12jhhajsd
host: 192.168.8.220
port: 6379
password:
timeout: 1000
lettuce:
pool:
@ -91,7 +91,7 @@ upload:
server:
port: 8080
port: 8081
logging:
level:

99
src/main/resources/mapper/ConsumeMapper.xml

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ConsumeMapper">
<!-- 查询所有消费记录 -->
<select id="selectAll" resultType="com.example.demo.domain.vo.ConsumeUser">
SELECT u.name AS name,
u.jwcode AS jwcode,
u.market AS market,
ugr.goods_name AS goodsName,
ugr.pay_platform AS payPlatform,
ugr.sum_gold AS sumGold,
ugr.permanent_gold AS permanentGold,
(COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) AS freeGold,
ugr.task_gold AS taskGold,
ugr.remark AS remark,
a.admin_name AS adminName,
ugr.pay_time AS payTime
FROM user u
JOIN
user_gold_record ugr ON u.jwcode = ugr.jwcode
JOIN
admin a ON ugr.admin_id = a.id
WHERE ugr.type = 1
</select>
<!-- 查询筛选后消费记录 -->
<select id="selectBy" resultType="com.example.demo.domain.vo.ConsumeUser">
SELECT u.name AS name,
u.jwcode AS jwcode,
u.market AS market,
ugr.goods_name AS goodsName,
ugr.pay_platform AS payPlatform,
ugr.sum_gold AS sumGold,
ugr.permanent_gold AS permanentGold,
(COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) AS freeGold,
ugr.task_gold AS taskGold,
ugr.remark AS remark,
a.admin_name AS adminName,
ugr.pay_time AS payTime
FROM user u
JOIN
user_gold_record ugr ON u.jwcode = ugr.jwcode
JOIN
admin a ON ugr.admin_id = a.id
<where>
ugr.type = 1
<if test="goodsName != null and goodsName != ''">
AND ugr.goods_name = #{goodsName}
</if>
<if test="market != null and market != ''">
AND u.market = #{market}
</if>
<if test="payPlatform != null and payPlatform != ''">
AND ugr.pay_platform = #{payPlatform}
</if>
<if test="startTime != null and endTime != null">
AND ugr.pay_time BETWEEN #{startTime} AND #{endTime}
</if>
</where>
</select>
<insert id="add" parameterType="com.example.demo.domain.entity.UserGoldRecord" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user_gold_record
<trim prefix="(" suffix=")" suffixOverrides=",">
order_code,
jwcode,
sum_gold,
permanent_gold,
free_june,
free_december,
task_gold,
goods_name,
remark,
type,
is_refund,
admin_id,
create_time,
pay_time
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
#{orderCode},
#{jwcode},
#{sumGold},
#{permanentGold},
#{freeJune},
#{freeDecember},
#{taskGold},
#{goodsName},
#{remark},
#{type},
#{isRefund},
#{adminId},
#{createTime},
#{payTime}
</trim>
</insert>
</mapper>

3
src/main/resources/mapper/GeneralMapper.xml

@ -8,4 +8,7 @@
<select id="getPlatform" resultType="java.lang.String">
select DISTINCT pay_platform from user_gold_record
</select>
<select id="getGoods" resultType="java.lang.String">
select DISTINCT goods_name from user_gold_record
</select>
</mapper>

94
src/main/resources/mapper/GoldDetailMapper.xml

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.GoldDetailMapper">
<select id="getGoldDetail" resultType="com.example.demo.domain.vo.GoldDetail">
select `user`.name, `user`.jwcode, `user`.market, `ugr`.pay_platform, `ugr`.type, `ugr`.sum_gold, `ugr`.permanent_gold, `ugr`.free_june, `ugr`.free_december, `ugr`.task_gold, `admin`.admin_name, `ugr`.audit_time
from user_gold_record ugr
left join `user` on `user`.jwcode = `ugr`.jwcode
left join `admin` on `admin`.id = `ugr`.admin_id
<where>
<if test="jwcode != null">
and `ugr`.jwcode = #{jwcode}
</if>
<if test="payPlatform != null and payPlatform.length > 0">
and `ugr`.pay_platform = #{payPlatform}
</if>
<if test="type != null">
and `ugr`.type = #{type}
</if>
<if test="market != null and market.length > 0">
and `user`.market = #{market}
</if>
<if test="startTime != null and endTime != null">
and ugr.`audit_time` BETWEEN #{startTime} AND #{endTime}
</if>
</where>
<choose>
<when test="sortField != null and sortField.length > 0 or sortOrder != null and sortOrder.length > 0">
ORDER BY ${sortField} ${sortOrder}
</when>
<otherwise>
ORDER BY audit_time DESC
</otherwise>
</choose>
</select>
<select id="getTotal" resultType="com.example.demo.domain.vo.Total">
select sum(sum_gold) as Goldtotal, sum(permanent_gold) as permanentGold, sum(free_june+free_december) as freeGold, sum(task_gold) as taskGold
from user_gold_record
<where>
<if test="jwcode != null">
and `ugr`.jwcode = #{jwcode}
</if>
<if test="payPlatform != null and payPlatform.length > 0">
and `ugr`.pay_platform = #{payPlatform}
</if>
<if test="type != null">
and `ugr`.type = #{type}
</if>
<if test="market != null and market.length > 0">
and `user`.market = #{market}
</if>
<if test="startTime != null and endTime != null">
and ugr.`audit_time` BETWEEN #{startTime} AND #{endTime}
</if>
</where>
</select>
<select id="getGold" resultType="com.example.demo.domain.entity.User">
select * from user
<where>
<if test="jwcode != null">
and jwcode = #{jwcode}
</if>
<if test="market != null and market.length > 0">
and market = #{market}
</if>
</where>
<choose>
<when test="sortField != null and sortField.length > 0 or sortOrder != null and sortOrder.length > 0">
ORDER BY ${sortField} ${sortOrder}
</when>
<otherwise>
ORDER BY create_time DESC
</otherwise>
</choose>
</select>
<select id="GoldTotal" resultType="com.example.demo.domain.vo.Total">
select
sum(current_permanent_gold) as permanentGold,
sum(current_free_june + current_free_december) as freeGold,
sum(current_task_gold) as taskGold,
sum(current_permanent_gold) + sum(current_free_june + current_free_december) + sum(current_task_gold) as Goldtotal
from `user`
<where>
<if test="jwcode != null">
and jwcode = #{jwcode}
</if>
<if test="market != null and market.length > 0">
and market = #{market}
</if>
</where>
</select>
</mapper>

102
src/main/resources/mapper/StatisticsMapper.xml

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.StatisticsMapper">
<!--新增part2统计数据-->
<insert id="insertPart2">
INSERT INTO statistics (
market, current_datetime,
recharge, money,
consume_permanent, consume_free_june,
consume_free_december, consume_task,
refund_permanent, refund_free_june,
refund_free_december,refund_task,
recharge_num, first_recharge
) VALUES (
#{market}, #{currentDatetime},
#{recharge}, #{money},
#{consumePermanent}, #{consumeFreeJune},
#{consumeFreeDecember}, #{consumeTask},
#{refundPermanent}, #{refundFreeJune},
#{refundFreeDecember}, #{refundTask},
#{rechargeNum}, #{firstRecharge}
)
</insert>
<!--更新part2统计数据-->
<update id="updatePart2">
UPDATE statistics
SET
recharge = #{recharge},
money = #{money},
consume_permanent = #{consumePermanent},
consume_free_june = #{consumeFreeJune},
consume_free_december = #{consumeFreeDecember},
consume_task = #{consumeTask},
refund_permanent = #{refundPermanent},
refund_free_june = #{refundFreeJune},
refund_free_december = #{refundFreeDecember},
refund_task = #{refundTask},
recharge_num = #{rechargeNum},
first_recharge = #{firstRecharge},
WHERE id = #{id}
</update>
<!--根据地区、审核状态、起止时间查询订单表数据-->
<select id="findByMarketAndAuditStatus"
resultType="com.example.demo.domain.entity.UserGoldRecord">
SELECT u.market, ugr.*
FROM user_gold_record ugr
INNER JOIN user u ON ugr.jwcode = u.jwcode
WHERE u.market = #{market}
AND ugr.audit_status IN
<foreach item="status" collection="auditStatusList" open="(" separator="," close=")">
#{status}
</foreach>
AND ugr.pay_time BETWEEN #{startTime} AND #{endTime}
</select>
<!-- 计算该天充值人数-->
<select id="countRechargeNum" resultType="java.lang.Integer">
SELECT COUNT(DISTINCT ugr.jwcode)
FROM user_gold_record ugr
INNER JOIN user u ON ugr.jwcode = u.jwcode
WHERE u.market = #{market}
AND ugr.audit_status = 1
AND ugr.pay_time BETWEEN #{startTime} AND #{endTime}
</select>
<!--计算该天首充人数-->
<select id="countFirstRecharge" resultType="java.lang.Integer">
SELECT COUNT(DISTINCT ugr.jwcode)
FROM user_gold_record ugr
INNER JOIN user u ON ugr.jwcode = u.jwcode
WHERE u.market = #{market}
AND ugr.audit_status = 1
AND ugr.pay_time BETWEEN #{startTime} AND #{endTime}
AND u.first_recharge = #{startTime}
</select>
<select id="selectByMarketAndDate" resultType="com.example.demo.domain.entity.Statistics">
SELECT *
FROM statistics
WHERE market = #{market}
AND current_datetime >= #{startDate}
AND current_datetime &lt;= #{endDate}
LIMIT 1
</select>
<select id="sumCurrentPermanentGold" resultType="java.lang.Integer">
SELECT SUM(u.currentPermanentGold)
FROM user u
WHERE u.market = #{market}
</select>
<select id="sumCurrentFreeJune" resultType="java.lang.Integer">
SELECT SUM(u.currentFreeJune)
FROM user u
WHERE u.market = #{market}
</select>
<select id="sumCurrentFreeDecember" resultType="java.lang.Integer">
SELECT SUM(u.currentFreeDecember)
FROM user u
WHERE u.market = #{market}
</select>
<select id="sumCurrentTaskGold" resultType="java.lang.Integer">
SELECT SUM(u.currentTaskGold)
FROM user u
WHERE u.market = #{market}
</select>
</mapper>

51
src/main/resources/mapper/UserMapper.xml

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<!-- 根据精网号查询用户信息 -->
<select id="selectUser" resultType="com.example.demo.domain.vo.GoldUser">
SELECT
name AS "name",
jwcode AS "jwcode",
market AS "market",
(COALESCE(current_permanent_gold, 0) + COALESCE(current_free_june, 0) + COALESCE(current_free_december, 0) + COALESCE(current_task_gold, 0)) AS "nowSumGold",
current_permanent_gold AS "nowPermanentGold",
(COALESCE(current_free_june, 0) + COALESCE(current_free_december, 0)) AS "nowFreeGold",
current_task_gold AS "nowTaskGold",
(COALESCE(sum_permanent_gold, 0) + COALESCE(sum_free_june, 0) + COALESCE(sum_free_december, 0) + COALESCE(sum_task_gold, 0)) AS "historySumGold",
sum_permanent_gold AS "historyPermanentGold",
(COALESCE(sum_free_june, 0) + COALESCE(sum_free_december, 0)) AS "historyFreeGold",
sum_task_gold AS "historyTaskGold",
recharge_num AS "rechargeNum",
consume_num AS "consumeNum",
first_recharge AS "firstRecharge"
FROM user
WHERE jwcode = #{jwcode}
</select>
<!-- 根据精网号查询金币余额 -->
<select id="selectGold" resultType="com.example.demo.domain.vo.GoldUser">
SELECT
current_permanent_gold AS "NowPermanentGold",
(COALESCE(current_free_june, 0) + COALESCE(current_free_december, 0)) AS "NowFreeGold",
current_free_june AS "NowFreeJune",
current_free_december AS "NowFreeDecember",
current_task_gold AS "NowTaskGold",
consume_num AS "consumeNum"
FROM user
WHERE jwcode = #{jwcode}
</select>
<!-- 根据精网号更新数据 -->
<update id="updateGold" parameterType="com.example.demo.domain.entity.User">
UPDATE user
SET
current_permanent_gold = #{currentPermanentGold},
current_free_june = #{currentFreeJune},
current_free_december = #{currentFreeDecember},
current_task_gold = #{currentTaskGold},
consume_num = #{consumeNum},
update_time = NOW()
WHERE jwcode = #{jwcode}
</update>
</mapper>
Loading…
Cancel
Save