19 Commits
5496460df7
...
98bb1296e1
44 changed files with 1649 additions and 130 deletions
-
5pom.xml
-
2src/main/java/com/example/demo/DemoApplication.java
-
31src/main/java/com/example/demo/Util/BusinessException.java
-
190src/main/java/com/example/demo/Util/RedisUtil.java
-
2src/main/java/com/example/demo/config/RedisConfig.java
-
70src/main/java/com/example/demo/controller/ConsumeController.java
-
6src/main/java/com/example/demo/controller/GeneralController.java
-
60src/main/java/com/example/demo/controller/GoldDetailController.java
-
13src/main/java/com/example/demo/controller/StatisticsController.java
-
49src/main/java/com/example/demo/controller/WorkbenchController.java
-
33src/main/java/com/example/demo/domain/entity/Export.java
-
8src/main/java/com/example/demo/domain/entity/Statistics.java
-
3src/main/java/com/example/demo/domain/entity/User.java
-
45src/main/java/com/example/demo/domain/vo/Consume.java
-
26src/main/java/com/example/demo/domain/vo/Gold.java
-
42src/main/java/com/example/demo/domain/vo/GoldDetail.java
-
26src/main/java/com/example/demo/domain/vo/Page.java
-
64src/main/java/com/example/demo/domain/vo/Result.java
-
17src/main/java/com/example/demo/domain/vo/TestRequest.java
-
25src/main/java/com/example/demo/domain/vo/Total.java
-
45src/main/java/com/example/demo/domain/vo/WorkbenchCard.java
-
65src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java
-
23src/main/java/com/example/demo/mapper/ConsumeMapper.java
-
1src/main/java/com/example/demo/mapper/GeneralMapper.java
-
25src/main/java/com/example/demo/mapper/GoldDetailMapper.java
-
15src/main/java/com/example/demo/mapper/StatisticsMapper.java
-
23src/main/java/com/example/demo/mapper/WorkBenchMapper.java
-
6src/main/java/com/example/demo/security/TokenFilter.java
-
26src/main/java/com/example/demo/service/ConsumeService.java
-
2src/main/java/com/example/demo/service/GeneralService.java
-
22src/main/java/com/example/demo/service/GoldDetailService.java
-
16src/main/java/com/example/demo/service/StatisticsService.java
-
19src/main/java/com/example/demo/service/WorkbenchService.java
-
79src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java
-
9src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java
-
52src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java
-
103src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java
-
212src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java
-
6src/main/resources/application.yml
-
62src/main/resources/mapper/ConsumeMapper.xml
-
3src/main/resources/mapper/GeneralMapper.xml
-
94src/main/resources/mapper/GoldDetailMapper.xml
-
68src/main/resources/mapper/StatisticsMapper.xml
-
86src/main/resources/mapper/WorkBenchMapper.xml
@ -0,0 +1,31 @@ |
|||
package com.example.demo.Util; |
|||
|
|||
/** |
|||
* @program: GOLD |
|||
* @ClassName BusinessException |
|||
* @description: |
|||
* @author: huangqizhen |
|||
* @create: 2025−06-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; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,190 @@ |
|||
/* |
|||
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; |
|||
} |
|||
}*/ |
@ -0,0 +1,70 @@ |
|||
package com.example.demo.controller; |
|||
|
|||
import com.example.demo.domain.vo.Consume; |
|||
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.*; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @program: gold-java |
|||
* @ClassName ConsumeController |
|||
* @description:消费模块 |
|||
* @author: Double |
|||
* @create: 2025−06-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.getConsume())); |
|||
} |
|||
|
|||
} |
|||
|
|||
//消耗金币统计 |
|||
@PostMapping("/statsGold") |
|||
public Result statsGold() { |
|||
Gold gold = consumeService.statsGold(); |
|||
return Result.success(gold); |
|||
} |
|||
|
|||
} |
@ -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: 2025−06-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())); |
|||
} |
|||
} |
@ -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: 2025−06-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; |
|||
} |
@ -0,0 +1,45 @@ |
|||
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: 2025−06-23 11:53 |
|||
* @Version 1.0 |
|||
**/ |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@AllArgsConstructor |
|||
public class Consume 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 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; // 结束时间 |
|||
} |
@ -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: 2025−06-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; // 任务金币总数 |
|||
} |
@ -0,0 +1,42 @@ |
|||
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: 2025−06-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 permentGold; //永久金币 |
|||
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; // 结束时间 |
|||
private String sortField; //排序字段 |
|||
private String sortOrder; //排序顺序 |
|||
|
|||
} |
@ -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: 2025−06-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 Consume consume; |
|||
private User user; |
|||
|
|||
} |
@ -0,0 +1,17 @@ |
|||
package com.example.demo.domain.vo; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.util.Date; |
|||
@Data |
|||
@NoArgsConstructor |
|||
public class TestRequest { |
|||
private String market; |
|||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private Date date; |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.example.demo.domain.vo; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
/** |
|||
* @program: GOLD |
|||
* @ClassName Total |
|||
* @description: |
|||
* @author: huangqizhen |
|||
* @create: 2025−06-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; |
|||
|
|||
} |
@ -0,0 +1,65 @@ |
|||
package com.example.demo.domain.vo; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @program: gold-java |
|||
* @ClassName WorkbenchMarketCard |
|||
* @description: |
|||
* @author: Ethan |
|||
* @create: 2025−06-25 16:20 |
|||
* @Version 1.0 |
|||
**/ |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@AllArgsConstructor |
|||
public class WorkbenchMarketCard implements Serializable { |
|||
|
|||
private String market;//地区 |
|||
// 卡片一:当前金币相关 |
|||
private Integer currentGold; // 当前金币余量 |
|||
private Integer dailyChange; // 余量较前一天的变化 |
|||
private Integer currentPermanent; // 永久金币余量 |
|||
private Integer currentFreeJune; // 六月到期免费金币余量 |
|||
private Integer currentFreeDecember; // 十二月到期免费金币余量 |
|||
private Integer currentTask; // 任务金币余量 |
|||
private Integer currentFree; // 免费金币余量(currentFreeJune + currentFreeDecember) |
|||
|
|||
// 卡片二:充值相关 |
|||
private Integer recharge; // 当日充值金币数 |
|||
private Integer money; // 当日金额(永久金币) |
|||
private Integer yearlyRecharge; // 全年累计充值金币数 |
|||
private Integer yearlyMoney; // 全年累计金额 |
|||
|
|||
// 卡片三:当日消费/退款/消耗相关 |
|||
private Integer consumePermanent; // 当日新增消费(永久) |
|||
private Integer consumeFreeJune; // 当日新增消费(六月免费) |
|||
private Integer consumeFreeDecember; // 当日新增消费(十二月免费) |
|||
private Integer consumeTask; // 当日新增消费(任务) |
|||
private Integer refundPermanent; // 当日新增退款(永久) |
|||
private Integer refundFreeJune; // 当日新增退款(六月免费) |
|||
private Integer refundFreeDecember; // 当日新增退款(十二月免费) |
|||
private Integer refundTask; // 当日新增退款(任务) |
|||
private Integer dailyConsume; // 当日总消耗 = consumePermanent + consumeFreeJune + consumeFreeDecember + consumeTask - (refundPermanent + refundFreeJune + refundFreeDecember + refundTask) |
|||
private Integer yearlyConsume; // 全年累计消费 |
|||
private Integer yearlyRefund; // 全年累计退款金币数 |
|||
private Integer yearlyReduce; // 全年累计消耗金币数 = yearlyConsume - yearlyRefund |
|||
|
|||
// 卡片四:人头数相关 |
|||
private Integer rechargeNum; // 当日充值人数 |
|||
private Integer firstRecharge; // 当日首充人数 |
|||
private Integer wow; // 周同比(%) |
|||
private Integer daily; // 日环比(%) |
|||
private Integer yearlyRechargeNum; // 全年累计充值人头数 |
|||
//图表 |
|||
private Integer SumRechargePermanent; //合计充值永久金币 |
|||
private Integer SumRechargeFree; //合计充值免费金币 |
|||
private Integer SumConsumePermanent; //合计消费永久金币 |
|||
private Integer SumConsumeFree; //合计消费免费金币 |
|||
private Integer SumConsumeTask; //合计消费任务金币 |
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.example.demo.mapper; |
|||
|
|||
import com.example.demo.domain.vo.Consume; |
|||
import org.apache.ibatis.annotations.Mapper; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @program: gold-java |
|||
* @ClassName ConsumeMapper |
|||
* @description: |
|||
* @author: Double |
|||
* @create: 2025−06-23 13:45 |
|||
* @Version 1.0 |
|||
**/ |
|||
|
|||
@Mapper |
|||
public interface ConsumeMapper { |
|||
|
|||
List<Consume> selectAll(); |
|||
|
|||
List<Consume> selectBy(Consume consume); |
|||
} |
@ -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: 2025−06-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); |
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.example.demo.service; |
|||
|
|||
|
|||
import com.example.demo.domain.vo.Consume; |
|||
import com.example.demo.domain.vo.Gold; |
|||
import com.example.demo.domain.vo.GoldDetail; |
|||
import com.github.pagehelper.PageInfo; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @program: gold-java |
|||
* @ClassName ConsumeService |
|||
* @description: 消费模块 |
|||
* @author: Double |
|||
* @create: 2025−06-23 13:58 |
|||
* @Version 1.0 |
|||
**/ |
|||
public interface ConsumeService { |
|||
|
|||
PageInfo<Consume> selectAll(Integer pageNum, Integer pageSize); |
|||
|
|||
Gold statsGold(); |
|||
|
|||
PageInfo<Consume> selectBy(Integer pageNum, Integer pageSize, Consume consume); |
|||
} |
@ -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: 2025−06-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); |
|||
} |
@ -0,0 +1,79 @@ |
|||
package com.example.demo.serviceImpl; |
|||
|
|||
import com.example.demo.domain.vo.Consume; |
|||
import com.example.demo.domain.vo.Gold; |
|||
import com.example.demo.mapper.ConsumeMapper; |
|||
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.util.List; |
|||
|
|||
/** |
|||
* @program: gold-java |
|||
* @ClassName ConsumeServiceImpl |
|||
* @description: 消费模块 |
|||
* @author: Double |
|||
* @create: 2025−06-23 13:58 |
|||
* @Version 1.0 |
|||
**/ |
|||
|
|||
@Service |
|||
public class ConsumeServiceImpl implements ConsumeService { |
|||
|
|||
@Autowired |
|||
private ConsumeMapper consumeMapper; |
|||
|
|||
//消耗明细 |
|||
@Override |
|||
public PageInfo<Consume> selectAll(Integer pageNum, Integer pageSize) { |
|||
PageHelper.startPage(pageNum, pageSize); |
|||
List<Consume> consumes = consumeMapper.selectAll(); |
|||
return new PageInfo<>(consumes); |
|||
} |
|||
|
|||
//消耗金币统计 |
|||
@Override |
|||
public Gold statsGold() { |
|||
Gold gold = new Gold(); |
|||
List<Consume> consumes = consumeMapper.selectAll(); |
|||
|
|||
// 初始化累加器 |
|||
int permanentGoldSum = 0; |
|||
int freeGoldSum = 0; |
|||
int taskGoldSum = 0; |
|||
|
|||
// 遍历消费记录并累加金币 |
|||
for (Consume consume : consumes) { |
|||
// 累加永久金币 |
|||
if (consume.getPermanentGold() != null) { |
|||
permanentGoldSum += consume.getPermanentGold(); |
|||
} |
|||
// 累加免费金币 |
|||
if (consume.getFreeGold() != null) { |
|||
freeGoldSum += consume.getFreeGold(); |
|||
} |
|||
// 累加任务金币 |
|||
if (consume.getTaskGold() != null) { |
|||
taskGoldSum += consume.getTaskGold(); |
|||
} |
|||
} |
|||
|
|||
// 将累加结果设置到Gold对象 |
|||
gold.setPermanentGolds(permanentGoldSum); |
|||
gold.setFreeGolds(freeGoldSum); |
|||
gold.setTaskGolds(taskGoldSum); |
|||
|
|||
return gold; |
|||
} |
|||
|
|||
//消耗明细筛选 |
|||
@Override |
|||
public PageInfo<Consume> selectBy(Integer pageNum, Integer pageSize, Consume consume) { |
|||
PageHelper.startPage(pageNum, pageSize); |
|||
List<Consume> consumes = consumeMapper.selectBy(consume); |
|||
return new PageInfo<>(consumes); |
|||
} |
|||
} |
@ -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: 2025−06-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); |
|||
} |
|||
} |
@ -0,0 +1,62 @@ |
|||
<?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.Consume"> |
|||
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.Consume"> |
|||
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> |
|||
</mapper> |
@ -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 jwcode.length > 0"> |
|||
and `ugr`.jwcode = #{jwcode} |
|||
</if> |
|||
<if test="payPlatform != null and payPlatform.length > 0"> |
|||
and `ugr`.pay_platform = #{payPlatform} |
|||
</if> |
|||
<if test="type != null and type.length > 0"> |
|||
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 jwcode.length > 0"> |
|||
and `ugr`.jwcode = #{jwcode} |
|||
</if> |
|||
<if test="payPlatform != null and payPlatform.length > 0"> |
|||
and `ugr`.pay_platform = #{payPlatform} |
|||
</if> |
|||
<if test="type != null and type.length > 0"> |
|||
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.length > 0"> |
|||
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.length > 0"> |
|||
and jwcode = #{jwcode} |
|||
</if> |
|||
<if test="market != null and market.length > 0"> |
|||
and market = #{market} |
|||
</if> |
|||
</where> |
|||
</select> |
|||
</mapper> |
@ -1,5 +1,91 @@ |
|||
<?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.WorkBenchMapper"> |
|||
<!--起止时间内的该地区充值金币数(永久+免费)若为空则默认0--> |
|||
<select id="sumRecharge" resultType="java.lang.Integer"> |
|||
select sum( |
|||
|
|||
COALESCE(recharge, 0) |
|||
) |
|||
from statistics |
|||
where market = #{market} |
|||
and current_datetime |
|||
between #{startDate} and #{endDate} |
|||
</select> |
|||
<!--起止时间内的该地区充值金额(永久金币数)--> |
|||
<select id="sumMoney" resultType="java.lang.Integer"> |
|||
SELECT SUM(money) |
|||
FROM statistics |
|||
WHERE market = #{market} |
|||
AND current_datetime BETWEEN #{startDate} and #{endDate} |
|||
</select> |
|||
<!-- 起止时间内该地区消费金币数(永久+免费+任务)--> |
|||
<select id="sumConsume" resultType="java.lang.Integer"> |
|||
SELECT SUM( |
|||
COALESCE(consume_permanent, 0) + |
|||
COALESCE(consume_free_june, 0) + |
|||
COALESCE(consume_free_december, 0) + |
|||
COALESCE(consume_task, 0) |
|||
) |
|||
FROM statistics |
|||
WHERE market = #{market} |
|||
AND current_datetime BETWEEN |
|||
#{startDate} and #{endDate} |
|||
</select> |
|||
<!--起止时间内的该地区退款金币数(永久+免费+任务)--> |
|||
<select id="sumRefund" resultType="java.lang.Integer"> |
|||
SELECT SUM( |
|||
COALESCE(refund_permanent, 0) + |
|||
COALESCE(refund_free_june, 0) + |
|||
COALESCE(refund_free_december, 0) + |
|||
COALESCE(refund_task, 0) |
|||
) |
|||
FROM statistics |
|||
WHERE market = #{market} |
|||
AND current_datetime BETWEEN |
|||
#{startDate} and #{endDate} |
|||
</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.pay_time BETWEEN |
|||
#{startDate} and #{endDate} |
|||
AND ugr.audit_status IN (1,3) |
|||
|
|||
</select> |
|||
<!--给定时间范围内的该地区消费永久金币数--> |
|||
<select id="sumCPermanent" resultType="java.lang.Integer"> |
|||
SELECT SUM( |
|||
COALESCE(consume_permanent, 0) |
|||
) |
|||
FROM statistics |
|||
WHERE market = #{market} |
|||
AND current_datetime BETWEEN |
|||
#{startDate} and #{endDate} |
|||
</select> |
|||
<!--给定时间范围内的该地区消费免费金币数--> |
|||
<select id="sumCFree" resultType="java.lang.Integer"> |
|||
SELECT SUM( |
|||
COALESCE(refund_free_june, 0) + |
|||
COALESCE(refund_free_december, 0) |
|||
) |
|||
FROM statistics |
|||
WHERE market = #{market} |
|||
AND current_datetime BETWEEN |
|||
#{startDate} and #{endDate} |
|||
</select> |
|||
<!--给定时间范围内的该地区消费任务金币数--> |
|||
<select id="sumCTask" resultType="java.lang.Integer"> |
|||
SELECT SUM( |
|||
COALESCE(refund_task, 0) |
|||
) |
|||
FROM statistics |
|||
WHERE market = #{market} |
|||
AND current_datetime BETWEEN |
|||
#{startDate} and #{endDate} |
|||
</select> |
|||
|
|||
</mapper> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue