diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java index 094d95b..b5f983a 100644 --- a/src/main/java/com/example/demo/DemoApplication.java +++ b/src/main/java/com/example/demo/DemoApplication.java @@ -2,8 +2,10 @@ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling // 启用调度功能 public class DemoApplication { public static void main(String[] args) { diff --git a/src/main/java/com/example/demo/Util/RedisUtil.java b/src/main/java/com/example/demo/Util/RedisUtil.java index 1bc95af..5431742 100644 --- a/src/main/java/com/example/demo/Util/RedisUtil.java +++ b/src/main/java/com/example/demo/Util/RedisUtil.java @@ -1,3 +1,4 @@ +/* package com.example.demo.Util; import jakarta.annotation.PostConstruct; @@ -34,21 +35,25 @@ public class RedisUtil { 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; @@ -61,30 +66,36 @@ public class RedisUtil { 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(); @@ -105,9 +116,11 @@ public class RedisUtil { }); } - /** + */ +/** * 启动延迟消息处理任务 - */ + *//* + @Scheduled(fixedRate = DELAY_QUEUE_POLL_INTERVAL) public void processDelayMessages() { Set delayQueues = redisTemplate.keys("delay:*"); @@ -121,9 +134,11 @@ public class RedisUtil { } } - /** + */ +/** * 处理单个延迟队列 - */ + *//* + private void processSingleDelayQueue(String queueName) { String delayQueueKey = getDelayQueueKey(queueName); long now = System.currentTimeMillis(); @@ -172,4 +187,4 @@ public class RedisUtil { } return serialized; } -} \ No newline at end of file +}*/ diff --git a/src/main/java/com/example/demo/config/RedisConfig.java b/src/main/java/com/example/demo/config/RedisConfig.java index e99407c..dfd5115 100644 --- a/src/main/java/com/example/demo/config/RedisConfig.java +++ b/src/main/java/com/example/demo/config/RedisConfig.java @@ -1,3 +1,4 @@ +/* package com.example.demo.config; import org.springframework.beans.factory.annotation.Autowired; @@ -44,3 +45,4 @@ public class RedisConfig { } +*/ diff --git a/src/main/java/com/example/demo/controller/StatisticsController.java b/src/main/java/com/example/demo/controller/StatisticsController.java index b8bab1a..d18fee3 100644 --- a/src/main/java/com/example/demo/controller/StatisticsController.java +++ b/src/main/java/com/example/demo/controller/StatisticsController.java @@ -34,10 +34,15 @@ public class StatisticsController { private StatisticsService statisticsService; @Autowired private GeneralService generalService; - //测试定时任务1 - @PostMapping("/Hourly") - public void HourlyTask() { - statisticsService.runHourlyTask(); + //测试定时任务part1 + @PostMapping("/Hourly1") + public void HourlyTask1() { + statisticsService.runHourlyTaskPart1(); + } + //测试定时任务part2 + @PostMapping("/Hourly2") + public void HourlyTask2() { + statisticsService.runHourlyTaskPart2(); } diff --git a/src/main/java/com/example/demo/controller/WorkbenchController.java b/src/main/java/com/example/demo/controller/WorkbenchController.java index 3e28a33..3e73097 100644 --- a/src/main/java/com/example/demo/controller/WorkbenchController.java +++ b/src/main/java/com/example/demo/controller/WorkbenchController.java @@ -1,12 +1,20 @@ package com.example.demo.controller; +import com.example.demo.domain.entity.Statistics; +import com.example.demo.domain.vo.TestRequest; import com.example.demo.domain.vo.WorkbenchCard; +import com.example.demo.mapper.StatisticsMapper; +import com.example.demo.service.StatisticsService; import com.example.demo.service.WorkbenchService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.Date; +import java.util.Map; + /** * @program: gold-java * @ClassName WorkbenchController @@ -24,27 +32,40 @@ import org.springframework.web.bind.annotation.*; public class WorkbenchController { @Autowired - private WorkbenchService WorkbenchService; + private WorkbenchService workbenchService; + @Autowired + private StatisticsService statisticsService; + @Autowired + private StatisticsMapper statisticsMapper; /* - 获取工作台卡片一的数据 + 获取各地区工作台卡片的数据 */ - @PostMapping("card1") - public WorkbenchCard card1(@RequestBody WorkbenchCard workbench){ - return WorkbenchService.getCard1(workbench.getToken(),workbench.getMarket()); + @PostMapping("getCard") + public ResponseEntity card1(@RequestBody WorkbenchCard workbench){ + WorkbenchCard result =workbenchService.getCard(workbench.getToken(),workbench.getMarkets()); + return ResponseEntity.ok(result); } /* - 获取工作台卡片二的数据 + 获取各地区工作台图表的数据 */ - @PostMapping("card2") - public WorkbenchCard card2(@RequestBody WorkbenchCard workbench){ - return WorkbenchService.getCard2(workbench.getToken(),workbench.getMarket()); + @PostMapping("getGraph") + public ResponseEntity graph1(@RequestBody WorkbenchCard workbench){ + WorkbenchCard result =workbenchService.getGraph(workbench.getToken(),workbench.getStartDate(),workbench.getEndDate(),workbench.getMarkets()); + return ResponseEntity.ok(result); } /* - 获取工作台卡片三的数据 + 测试一段时间内的统计数据 */ - @PostMapping("card3") - public WorkbenchCard card3(@RequestBody WorkbenchCard workbench){ - return WorkbenchService.getCard3(workbench.getToken(),workbench.getMarket()); - } + /* @PostMapping("testSum") + public Statistics testSum( @RequestBody TestRequest request){ + String market = request.getMarket(); + Date date = request.getDate(); + + + //获取传入日期所在周的周一 + Date thisWeekStart = workbenchService.getStartOfWeek(date); + + return statisticsMapper.selectSumByMarketAndDate(market, thisWeekStart, date); + }*/ } diff --git a/src/main/java/com/example/demo/domain/entity/Statistics.java b/src/main/java/com/example/demo/domain/entity/Statistics.java index 2597e9a..5bb64e3 100644 --- a/src/main/java/com/example/demo/domain/entity/Statistics.java +++ b/src/main/java/com/example/demo/domain/entity/Statistics.java @@ -2,10 +2,13 @@ package com.example.demo.domain.entity; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; +import java.time.LocalDate; import java.util.Date; /** @@ -45,8 +48,9 @@ public class Statistics implements Serializable { private Integer rechargeNum; // 当日充值人数 private Integer firstRecharge; // 当日首充人数 // 数据日期 - @JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai") - private Date currentDatetime; + @JsonFormat(pattern = "yyyy-MM-dd") + @JsonDeserialize(using = LocalDateDeserializer.class) + private LocalDate currentDatetime; // 创建时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date createTime; diff --git a/src/main/java/com/example/demo/domain/vo/TestRequest.java b/src/main/java/com/example/demo/domain/vo/TestRequest.java new file mode 100644 index 0000000..51cb98a --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/TestRequest.java @@ -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; + + + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/domain/vo/WorkbenchCard.java b/src/main/java/com/example/demo/domain/vo/WorkbenchCard.java index bd2d397..8453b45 100644 --- a/src/main/java/com/example/demo/domain/vo/WorkbenchCard.java +++ b/src/main/java/com/example/demo/domain/vo/WorkbenchCard.java @@ -1,16 +1,18 @@ 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; import java.util.List; /** * @program: gold-java * @ClassName Workbench - * @description: 工作台请求参数 + * @description: 工作台顶层容器 * @author: Ethan * @create: 2025−06-17 17:43 * @Version 1.0 @@ -21,41 +23,12 @@ import java.util.List; @AllArgsConstructor public class WorkbenchCard implements Serializable { private String token; //用户token - private List 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 List marketCards; // 地区卡片数据 + private List markets; // 地区列表 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date startDate; // 起始时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date endDate; // 结束时间 - // 卡片二:充值相关 - 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; // 全年累计充值人头数 } diff --git a/src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java b/src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java new file mode 100644 index 0000000..747c0bc --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java @@ -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; //合计消费任务金币 +} diff --git a/src/main/java/com/example/demo/mapper/StatisticsMapper.java b/src/main/java/com/example/demo/mapper/StatisticsMapper.java index a88b42d..d54f350 100644 --- a/src/main/java/com/example/demo/mapper/StatisticsMapper.java +++ b/src/main/java/com/example/demo/mapper/StatisticsMapper.java @@ -5,6 +5,7 @@ import com.example.demo.domain.entity.UserGoldRecord; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.time.LocalDate; import java.util.Date; import java.util.List; @@ -33,21 +34,29 @@ public interface StatisticsMapper { //获取某地区当前永久金币余量 Integer sumCurrentTaskGold(@Param("market") String market); //计算该天充值人数 - int countRechargeNum( + Integer countRechargeNum( @Param("market") String market, @Param("startTime") Date startTime, @Param("endTime") Date endTime); //计算该天首充人数 - int countFirstRecharge( + Integer countFirstRecharge( @Param("market") String market, @Param("startTime") Date startTime, @Param("endTime") Date endTime); + //新增part1统计数据 + void insertPart1(Statistics statistics); + //更新part1统计数据 + void updatePart1(Statistics statistics); //新增part2统计数据 void insertPart2(Statistics statistics); //更新part2统计数据 void updatePart2(Statistics statistics); - //获取某地区某天的数据 + //获取某地区某时间所在日期的数据(仅一条) Statistics selectByMarketAndDate(@Param("market") String market, @Param("startDate") Date startDate, @Param("endDate") Date endDate); + //获取某地区某时间段的统计数据(仅一条) + Statistics selectSumByMarketAndDate(@Param("market") String market, + @Param("startDate") Date startDate, + @Param("endDate") Date endDate); } diff --git a/src/main/java/com/example/demo/mapper/WorkBenchMapper.java b/src/main/java/com/example/demo/mapper/WorkBenchMapper.java index ac94011..6dd220a 100644 --- a/src/main/java/com/example/demo/mapper/WorkBenchMapper.java +++ b/src/main/java/com/example/demo/mapper/WorkBenchMapper.java @@ -3,6 +3,7 @@ package com.example.demo.mapper; import com.example.demo.domain.vo.WorkbenchCard; import org.apache.ibatis.annotations.Mapper; +import java.util.Date; import java.util.List; /** @@ -16,10 +17,20 @@ import java.util.List; @Mapper public interface WorkBenchMapper { - //工作台卡片一 - public WorkbenchCard getCard1(List areas); - //工作台卡片二 - public WorkbenchCard getCard2(List areas); - //工作台卡片三 - public WorkbenchCard getCard3(List areas); + //给定时间范围内的该地区充值金币数(永久+免费) + Integer sumRecharge(String market, Date startDate, Date endDate); + //给定时间范围内的该地区充值金额(永久金币数) + Integer sumMoney(String market, Date startDate, Date endDate); + //给定时间范围内的该地区消费金币数(永久+免费+任务) + Integer sumConsume(String market, Date startDate, Date endDate); + //给定时间范围内的该地区消费永久金币数 + Integer sumCPermanent(String market, Date startDate, Date endDate); + //给定时间范围内的该地区消费免费金币数 + Integer sumCFree(String market, Date startDate, Date endDate); + //给定时间范围内的该地区消费任务金币数 + Integer sumCTask(String market, Date startDate, Date endDate); + //给定时间范围内的该地区退款金币数(永久+免费+任务) + Integer sumRefund(String market,Date startDate, Date endDate); + //给定时间范围内的该地区充值人头数(根据精网号去重,老数据有多人共用一个精网号的问题) + Integer countRechargeNum(String market, Date startDate, Date endDate); } diff --git a/src/main/java/com/example/demo/service/GeneralService.java b/src/main/java/com/example/demo/service/GeneralService.java index 1e9128b..e19c4b9 100644 --- a/src/main/java/com/example/demo/service/GeneralService.java +++ b/src/main/java/com/example/demo/service/GeneralService.java @@ -29,4 +29,5 @@ public interface GeneralService { String formatDate(Date date) ; //获取时间段内的所有日期(包含起始和结束日) List getAllDatesBetween(Date start, Date end); + } diff --git a/src/main/java/com/example/demo/service/StatisticsService.java b/src/main/java/com/example/demo/service/StatisticsService.java index bfdc214..30dcd01 100644 --- a/src/main/java/com/example/demo/service/StatisticsService.java +++ b/src/main/java/com/example/demo/service/StatisticsService.java @@ -15,15 +15,19 @@ import java.util.Date; public interface StatisticsService { - //12点,18点执行定时任务更新当天数据 - public void runHourlyTask(); - //0点执行定时任务更新近一周数据 - public void runDailyTask(); + //12点,18点,23点30分执行定时任务更新当天part2数据 + public void runHourlyTaskPart1(); + //12点,18点执行定时任务更新当天part2数据 + public void runHourlyTaskPart2(); + //0点执行定时任务更新近一周part2数据 + public void runDailyTaskPart2(); //查询某地区某天是否已存在统计数据 public Statistics getExistStatistics(String market,Date date); - //新增或更新或不修改某地区某天统计数据 - public void saveStatistics(String market, Date date); + //新增或更新或不修改某地区某天part1统计数据 + public void saveStatisticsPart1(String market, Date date); + //新增或更新或不修改某地区某天part2统计数据 + public void saveStatisticsPart2(String market, Date date); //根据地区与日期获取part1(余量属性)统计数据 public Statistics getStatisticsPart1(String market, Date date); //根据地区与日期获取part2(余量外属性)统计数据 diff --git a/src/main/java/com/example/demo/service/WorkbenchService.java b/src/main/java/com/example/demo/service/WorkbenchService.java index cdc0aaa..30fad16 100644 --- a/src/main/java/com/example/demo/service/WorkbenchService.java +++ b/src/main/java/com/example/demo/service/WorkbenchService.java @@ -1,7 +1,9 @@ package com.example.demo.service; import com.example.demo.domain.vo.WorkbenchCard; +import com.example.demo.domain.vo.WorkbenchMarketCard; +import java.util.Date; import java.util.List; /** @@ -15,7 +17,18 @@ import java.util.List; public interface WorkbenchService { - WorkbenchCard getCard1(String token, Listareas); - WorkbenchCard getCard2(String token, Listareas); - WorkbenchCard getCard3(String token, Listareas); + //获取不同地区的工作台统计卡片 + WorkbenchCard getCard(String token, List markets); + //获取不同地区的工作台柱状图数据(根据类型,起止时间,地区查询) + WorkbenchCard getGraph(String token, Date startDate, Date endDate, List markets); + //根据类型获取年初至今的统计数据 + Integer calculateSum(String market, String type, Date startDate,Date endDate); + //获取该日期该市场的日同比 + Integer calculateDayOverDay(String market,Date date); + //获取该日期该市场的周环比 + Integer calculateWeekOverWeek(String market, Date date); + //获取与传入的日期相差XX天的日期 + Date addDays(Date date, int days); + //获取传入时间所在周的第一天(周一) + Date getStartOfWeek(Date date); } diff --git a/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java index eb458e3..6e55273 100644 --- a/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java @@ -93,4 +93,7 @@ public class GeneralServiceImpl implements GeneralService { return dates; } + + + } diff --git a/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java index b870f8f..b311ed8 100644 --- a/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java @@ -11,9 +11,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.*; /** @@ -32,23 +34,37 @@ public class StatisticsServiceImpl implements StatisticsService { private StatisticsMapper statisticsMapper; @Autowired private GeneralService generalService; + /* - 12点,18点执行定时任务更新当天数据 - */ + 12点,18点,23点30分执行定时任务更新当天part1数据 + */ + @Override + @Scheduled(cron = "0 0 12,18 * * ?") // 分别在 12:00 和 18:00 执行 + @Scheduled(cron = "0 30 23 * * ?") // 在 23:30 执行 + public void runHourlyTaskPart1() { + Date today = new Date(); //取当天日期 + for(String market : generalService.getMarket()){ + saveStatisticsPart1(market,today); + } + } + + /* + 12点,18点执行定时任务更新当天part2数据 + */ @Override @Scheduled(cron = "0 0 12,18 * * ?") - public void runHourlyTask() { + public void runHourlyTaskPart2() { Date today = new Date(); //取当天日期 for(String market : generalService.getMarket()){ - saveStatistics(market,today); + saveStatisticsPart2(market,today); } } /* - 0点执行定时任务更新近一周数据 + 0点执行定时任务更新近一周part2数据 */ @Override @Scheduled(cron = "0 0 0 * * ?") - public void runDailyTask() { + public void runDailyTaskPart2() { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_YEAR, -7); // 一周前 Date startDate = cal.getTime(); @@ -58,7 +74,7 @@ public class StatisticsServiceImpl implements StatisticsService { for (Date date : dateList) { for (String market : generalService.getMarket()) { - saveStatistics(market, date); + saveStatisticsPart2(market, date); } } } @@ -74,11 +90,35 @@ public class StatisticsServiceImpl implements StatisticsService { Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()), Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant())); } + + /* + 新增或更新或不修改某地区某天part1统计数据 + */ + @Override + public void saveStatisticsPart1(String market, Date date) { + //获取该地区该日期part1(余量属性)统计数据 + Statistics newStats=getStatisticsPart1(market,date); + //获取该地区该日期已存在的数据 + Statistics existStats = getExistStatistics(market, date); + //判断是否存在已存在的数据 + if(existStats==null){ + //没有记录,新增 + statisticsMapper.insertPart1(newStats ); + }else { + //判断新旧数据part1部分(余量属性)是否一致 + if (!isSameStatisticsPart1(existStats,newStats)){ + statisticsMapper.updatePart1(newStats); + }else{ + System.out.println("数据未发生改变"); + } + } + } + /* - 新增或更新或不修改某地区某天统计数据 + 新增或更新或不修改某地区某天part2统计数据 */ @Override - public void saveStatistics(String market, Date date){ + public void saveStatisticsPart2(String market, Date date){ //获取该地区该日期part2(余量外属性)统计数据 Statistics newStats=getStatisticsPart2(market,date); //获取该地区该日期已存在的数据 @@ -92,7 +132,7 @@ public class StatisticsServiceImpl implements StatisticsService { if (!isSameStatisticsPart2(existStats,newStats)){ statisticsMapper.updatePart2(newStats); }else{ - log.atInfo().log("数据未发生改变"); + System.out.println("数据未发生改变"); } } } @@ -100,9 +140,14 @@ public class StatisticsServiceImpl implements StatisticsService { //根据地区与日期获取part1(余量属性)统计数据 @Override public Statistics getStatisticsPart1(String market, Date date) { + //获取日期 + LocalDate localDate=date.toInstant() + .atZone(ZoneId.of("Asia/Shanghai")) // 使用系统默认时区 + .toLocalDate(); //初始化Statistics对象 Statistics statistics = new Statistics(); statistics.setMarket(market); + statistics.setCurrentDatetime(localDate); //计算属性 //当前金币余量 Integer currentGold = statisticsMapper.sumCurrentPermanentGold(market)+ @@ -110,6 +155,25 @@ public class StatisticsServiceImpl implements StatisticsService { statisticsMapper.sumCurrentFreeDecember(market)+ statisticsMapper.sumCurrentTaskGold( market); statistics.setCurrentGold(currentGold); + //较前一日变化 + Date yesterday =generalService.getYesterday(); + //把yesterday改为昨天的开始时间和结束时间 + LocalDateTime startTime = yesterday.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN); + LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1); + + //昨天金币余量 + Statistics ydayStats = statisticsMapper.selectByMarketAndDate(market, Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()), + Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant())); + Integer yesterdayGold=0; + if (ydayStats != null) { + yesterdayGold = ydayStats.getCurrentGold(); + + } + Integer dailyChange = currentGold - yesterdayGold; + statistics.setDailyChange(dailyChange); + + + //当前永久金币 Integer currentPermanent = statisticsMapper.sumCurrentPermanentGold(market); statistics.setCurrentPermanent(currentPermanent); @@ -130,6 +194,10 @@ public class StatisticsServiceImpl implements StatisticsService { */ @Override public Statistics getStatisticsPart2(String market, Date date) { + //获取日期 + LocalDate localDate=date.toInstant() + .atZone(ZoneId.of("Asia/Shanghai")) // 使用系统默认时区 + .toLocalDate(); //把date改为当天的开始时间和结束时间 LocalDateTime startTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN); LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1); @@ -143,7 +211,8 @@ public class StatisticsServiceImpl implements StatisticsService { //初始化Statistics对象 Statistics statistics = new Statistics(); statistics.setMarket(market); - statistics.setCurrentDatetime(date); + statistics.setCurrentDatetime(localDate); + //计算属性 //充值相关-当日充值(永久+免费) Integer recharge = records.stream() @@ -213,6 +282,18 @@ public class StatisticsServiceImpl implements StatisticsService { statistics.setFirstRecharge(firstRecharge); return statistics; } + +/* + * 判断两个统计对象part1(余量属性)是否相同 + */ +private boolean isSameStatisticsPart1(Statistics oldStats, Statistics newStats) { + return Objects.equals(oldStats.getCurrentGold(), newStats.getCurrentGold()) && + Objects.equals(oldStats.getCurrentPermanent(), newStats.getCurrentPermanent()) && + Objects.equals(oldStats.getCurrentFreeJune(), newStats.getCurrentFreeJune()) && + Objects.equals(oldStats.getCurrentFreeDecember(), newStats.getCurrentFreeDecember()) && + Objects.equals(oldStats.getCurrentTask(), newStats.getCurrentTask()) && + Objects.equals(oldStats.getDailyChange(), newStats.getDailyChange()) ; +} /* * 判断两个统计对象part2(余量外属性)是否相同 */ diff --git a/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java index 72e539f..669e4ee 100644 --- a/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java @@ -1,11 +1,24 @@ package com.example.demo.serviceImpl; +import com.example.demo.domain.entity.Statistics; import com.example.demo.domain.vo.WorkbenchCard; +import com.example.demo.domain.vo.WorkbenchMarketCard; +import com.example.demo.mapper.StatisticsMapper; import com.example.demo.mapper.WorkBenchMapper; +import com.example.demo.service.GeneralService; +import com.example.demo.service.StatisticsService; import com.example.demo.service.WorkbenchService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.DayOfWeek; +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; /** @@ -19,23 +32,206 @@ import java.util.List; @Service public class WorkbenchServiceImpl implements WorkbenchService { - @Autowired - private WorkBenchMapper workbenchMapper; + private WorkBenchMapper workBenchMapper; + @Autowired + private GeneralService generalService; + @Autowired + private StatisticsMapper statisticsMapper; + @Override + public WorkbenchCard getCard(String token, List markets) { + Date date=new Date(); + // 获取开始时间和结束时间(当天) + LocalDateTime startOfDay = date.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime() + .with(LocalTime.MIN); + + LocalDateTime endOfDay = startOfDay.plusDays(1).minusSeconds(1); + // 获取当前日期 + LocalDate today = LocalDate.now(); + // 获取当前年份的第一天 + LocalDate firstDayOfYear = today.withDayOfYear(1); + Date yearlyStartDate=Date.from(firstDayOfYear.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + List marketCards = new ArrayList<>(); + // 遍历每个 marketCard 并填充数据 + for (String market : markets) { + if (market == null || market.trim().isEmpty()) continue; + + // 查询该地区当天的数据 + Statistics statistics = statisticsMapper.selectByMarketAndDate( + market, + Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()), + Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()) + ); + WorkbenchMarketCard card = new WorkbenchMarketCard(); + card.setMarket(market); + if (statistics != null){ + + // 卡片一:当前金币相关 + card.setCurrentPermanent(statistics.getCurrentPermanent());//余量-永久金币 + card.setCurrentFreeJune(statistics.getCurrentFreeJune()); //余量-免费六月金币 + card.setCurrentFreeDecember(statistics.getCurrentFreeDecember()); //余量-免费十二月金币 + card.setCurrentTask(statistics.getCurrentTask()); //余量-任务金币 + card.setCurrentFree(card.getCurrentFreeJune() + card.getCurrentFreeDecember()); //余量-免费金币 + card.setCurrentGold(card.getCurrentPermanent() + card.getCurrentFree() + card.getCurrentTask()); //余量-总金币 + card.setDailyChange(statistics.getDailyChange()); //较前一日变化 + // 卡片二:充值相关 + card.setRecharge(statistics.getRecharge()); //充值-当日充值 + card.setMoney(statistics.getMoney()); //充值-当日金额(永久) + card.setYearlyRecharge(calculateSum(market, "recharge",yearlyStartDate ,date));//充值-全年累计充值 + card.setYearlyMoney(calculateSum(market, "money",yearlyStartDate ,date)); //充值-全年累计金额(永久) + // 卡片三:消费与退款 + card.setConsumePermanent(statistics.getConsumePermanent());//消费-永久金币 + card.setConsumeFreeJune(statistics.getConsumeFreeJune());//消费-免费六月金币 + card.setConsumeFreeDecember(statistics.getConsumeFreeDecember());//消费-免费十二月金币 + card.setConsumeTask(statistics.getConsumeTask());//消费-任务金币 + card.setRefundPermanent(statistics.getRefundPermanent());//退款-永久金币 + card.setRefundFreeJune(statistics.getRefundFreeJune());//退款-免费六月金币 + card.setRefundFreeDecember(statistics.getRefundFreeDecember());//退款-免费十二月金币 + card.setRefundTask(statistics.getRefundTask());//退款-任务金币 + //当日总消费 + int totalConsume = card.getConsumePermanent() + card.getConsumeFreeJune() + card.getConsumeFreeDecember() + card.getConsumeTask(); + //当日总退款 + int totalRefund = card.getRefundPermanent() + card.getRefundFreeJune() + card.getRefundFreeDecember() + card.getRefundTask(); + card.setDailyConsume(totalConsume - totalRefund);//当日总消耗 + card.setYearlyConsume(calculateSum(market, "consume", yearlyStartDate,date));//年累计消费 + card.setYearlyRefund(calculateSum(market, "refund",yearlyStartDate ,date));//年累计退款 + card.setYearlyReduce(card.getYearlyConsume() - card.getYearlyRefund());//年累计消耗 + // 卡片四:人头数相关 + card.setRechargeNum(statistics.getRechargeNum()); + card.setFirstRecharge(statistics.getFirstRecharge()); + card.setYearlyRechargeNum(calculateSum(market,"rechargeNum",yearlyStartDate,date)); + + // 周环比、日同比 + card.setWow(calculateWeekOverWeek(market, date)); + card.setDaily(calculateDayOverDay(market, date)); + + marketCards.add(card); + } + + } + return new WorkbenchCard(token, marketCards,markets,date,date); + } + @Override - public WorkbenchCard getCard1(String token, List areas) { - return workbenchMapper.getCard1(areas); + public WorkbenchCard getGraph(String token, Date startDate, Date endDate, List markets) { + List marketCards = new ArrayList<>(); + + for (String market : markets) { + WorkbenchMarketCard cards = new WorkbenchMarketCard(); + cards.setMarket(market); + cards.setSumRechargePermanent(calculateSum(market, "money",startDate,endDate)); + cards.setSumRechargeFree(calculateSum(market, "rFree",startDate,endDate)); + cards.setSumConsumePermanent(calculateSum(market, "cPermanent",startDate,endDate)); + cards.setSumConsumeFree(calculateSum(market, "cFree",startDate,endDate)); + cards.setSumConsumeTask(calculateSum(market, "cTask",startDate,endDate)); + marketCards.add( cards); + } + return new WorkbenchCard(token, marketCards,markets,startDate,endDate); } + /* + 根据类型获取统计数据 + */ + @Override + public Integer calculateSum(String market, String type, Date startDate,Date endDate) { + + //判断类型 + switch + (type) { + case "recharge": //获取累计充值 + return workBenchMapper.sumRecharge(market, startDate,endDate); + case "money": //获取累计金额(永久) + return workBenchMapper.sumMoney(market,startDate,endDate); + case "rFree": //获取累计充值(免费) + return workBenchMapper.sumRecharge(market,startDate,endDate)- + workBenchMapper.sumMoney(market,startDate,endDate); + case "consume": //获取累计消费 + return workBenchMapper.sumConsume(market,startDate,endDate); + case "cPermanent": //获取累计消费-永久 + return workBenchMapper.sumCPermanent(market,startDate,endDate); + case "cFree": //获取累计消费- 免费 + return workBenchMapper.sumCFree(market,startDate,endDate); + case "cTask": //获取累计消费- 任务 + return workBenchMapper.sumCTask(market,startDate,endDate); + case "refund": //获取累计退款 + return workBenchMapper.sumRefund(market,startDate,endDate); + case "rechargeNum": //获取累计充值人数 + return workBenchMapper.countRechargeNum(market,startDate,endDate); + default: + return 0; + } + + } + /* + 获取该日期该市场的日同比 + */ @Override - public WorkbenchCard getCard2(String token, List areas) { + public Integer calculateDayOverDay(String market, Date date) { + //传入日期的数据 + LocalDateTime startTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN); + LocalDateTime endTime= startTime.plusDays(1).minusSeconds(1); + Statistics currentStatistics = statisticsMapper.selectByMarketAndDate(market, + Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()), + Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant())); + //空数据或数量为零,为避免0除数错误,返回增长率为0 + if (currentStatistics == null || currentStatistics.getRechargeNum() == null) { + return 0; + } + Date yesterday = addDays(date, -1); //传入日期减一,昨天 + Statistics yesterdayStatistics = statisticsMapper.selectByMarketAndDate(market, + Date.from(yesterday.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant()), + Date.from(yesterday.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().with(LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant())); + //空数据或数量为零,为避免0除数错误,返回增长率为0 + if (yesterdayStatistics == null || yesterdayStatistics.getRechargeNum() == null || yesterdayStatistics.getRechargeNum() == 0) { + return 0; + } + //计算增长率 + double rate = ((double) (currentStatistics.getRechargeNum() - yesterdayStatistics.getRechargeNum()) / yesterdayStatistics.getRechargeNum()) * 100; + return (int) Math.round(rate); + } + /* + 获取该日期该市场的周环比 + */ + @Override + public Integer calculateWeekOverWeek(String market, Date date) { + //获取传入日期所在周的周一 + Date thisWeekStart = getStartOfWeek(date); + //获取传入日期上一周的周一 + Date lastWeekStart = addDays(thisWeekStart, -7); + // 获取本周周一至今天的充值人数总和 + int thisWeekTotal = statisticsMapper.countRechargeNum(market, thisWeekStart, date); + // 获取上周同一时间段的充值人数总和 + int lastWeekTotal = statisticsMapper.countRechargeNum(market, lastWeekStart, addDays(date, -7)); + if (lastWeekTotal == 0) { + return 0; // 避免除以零的情况 + } + double rate = ((double) (thisWeekTotal - lastWeekTotal) / lastWeekTotal) * 100; + return (int) Math.round(rate); + } - return workbenchMapper.getCard2(areas); + @Override + public Date addDays(Date date, int days) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); //设置日期为传入的日期 + cal.add(Calendar.DATE, days); //传入日期加上多少天 + return cal.getTime(); //返回处理后的日期 } @Override - public WorkbenchCard getCard3(String token, List areas) { + public Date getStartOfWeek(Date date) { + // 将 Date 转换为 LocalDate + LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + // 获取周一作为一周的第一天 + DayOfWeek firstDayOfWeek = DayOfWeek.MONDAY; - return workbenchMapper.getCard3(areas); + // 返回所在周的第一天,转换回Date格式 + return Date.from(localDate.with(firstDayOfWeek) + .atStartOfDay(ZoneId.systemDefault()) + .toInstant()); } + + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4ddfebc..cbbfb21 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -62,7 +62,7 @@ spring: data: redis: database: 0 - host: 192.168.8.220 + host: 192.168.8.94 port: 6379 password: timeout: 1000 diff --git a/src/main/resources/mapper/StatisticsMapper.xml b/src/main/resources/mapper/StatisticsMapper.xml index 4e77423..76dda9d 100644 --- a/src/main/resources/mapper/StatisticsMapper.xml +++ b/src/main/resources/mapper/StatisticsMapper.xml @@ -21,8 +21,24 @@ #{rechargeNum}, #{firstRecharge} ) + + + INSERT INTO statistics ( + market, current_datetime, + current_gold, daily_change, + current_permanent, current_free_june, + current_free_december, current_task, + + ) VALUES ( + #{market}, #{currentDatetime}, + #{currentGold}, #{dailyChange}, + #{currentPermanent}, #{currentFreeJune}, + #{currentFreeDecember}, #{currentTask}, + + ) + - + UPDATE statistics SET recharge = #{recharge}, @@ -36,8 +52,20 @@ refund_free_december = #{refundFreeDecember}, refund_task = #{refundTask}, recharge_num = #{rechargeNum}, - first_recharge = #{firstRecharge}, - WHERE id = #{id} + first_recharge = #{firstRecharge} + WHERE market = #{market} and current_datetime = #{currentDatetime} + + + + update statistics + SET + current_gold = #{currentGold}, + daily_change = #{dailyChange}, + current_permanent = #{currentPermanent}, + current_free_june = #{currentFreeJune}, + current_free_december = #{currentFreeDecember}, + current_task = #{currentTask} + WHERE market = #{market} and current_datetime = #{currentDatetime} + + diff --git a/src/main/resources/mapper/WorkBenchMapper.xml b/src/main/resources/mapper/WorkBenchMapper.xml index d816489..a0df89c 100644 --- a/src/main/resources/mapper/WorkBenchMapper.xml +++ b/src/main/resources/mapper/WorkBenchMapper.xml @@ -1,5 +1,91 @@ + + + + + + + + + + + + + + + +