From 06a07514cc352900219fa0449967f7d594938db9 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Tue, 27 May 2025 14:42:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=99=AF=E5=8C=BA=E6=91=84=E5=83=8F?= =?UTF-8?q?=E5=A4=B4=E8=BF=9B=E8=A1=8C=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/pc/DeviceStatsController.java | 23 ++++++ .../basic/mapper/ScenicDeviceStatsMapper.java | 25 +++++++ .../entity/ScenicDeviceStatsEntity.java | 16 ++++ .../scenicDeviceStats/req/DeviceStatsReq.java | 11 +++ .../resp/ScenicDeviceStatsListResp.java | 11 +++ .../resp/ScenicDeviceStatsResp.java | 17 +++++ .../basic/service/pc/DeviceStatsService.java | 9 +++ .../pc/impl/DeviceStatsServiceImpl.java | 46 ++++++++++++ .../basic/task/ScenicDeviceStatsTask.java | 41 +++++++++++ .../mapper/ScenicDeviceStatsMapper.xml | 73 +++++++++++++++++++ .../basic/task/ScenicDeviceStatsTaskTest.java | 24 ++++++ 11 files changed, 296 insertions(+) create mode 100644 src/main/java/com/ycwl/basic/controller/pc/DeviceStatsController.java create mode 100644 src/main/java/com/ycwl/basic/mapper/ScenicDeviceStatsMapper.java create mode 100644 src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/entity/ScenicDeviceStatsEntity.java create mode 100644 src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/req/DeviceStatsReq.java create mode 100644 src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsListResp.java create mode 100644 src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsResp.java create mode 100644 src/main/java/com/ycwl/basic/service/pc/DeviceStatsService.java create mode 100644 src/main/java/com/ycwl/basic/service/pc/impl/DeviceStatsServiceImpl.java create mode 100644 src/main/java/com/ycwl/basic/task/ScenicDeviceStatsTask.java create mode 100644 src/main/resources/mapper/ScenicDeviceStatsMapper.xml create mode 100644 src/test/java/com/ycwl/basic/task/ScenicDeviceStatsTaskTest.java diff --git a/src/main/java/com/ycwl/basic/controller/pc/DeviceStatsController.java b/src/main/java/com/ycwl/basic/controller/pc/DeviceStatsController.java new file mode 100644 index 0000000..eeadda4 --- /dev/null +++ b/src/main/java/com/ycwl/basic/controller/pc/DeviceStatsController.java @@ -0,0 +1,23 @@ +package com.ycwl.basic.controller.pc; + +import com.ycwl.basic.model.pc.scenicDeviceStats.req.DeviceStatsReq; +import com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsListResp; +import com.ycwl.basic.utils.ApiResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/deviceStats/v1") +public class DeviceStatsController { + @Autowired + private com.ycwl.basic.service.pc.DeviceStatsService service; + + @PostMapping("/{scenicId}") + public ApiResponse queryByScenic(@PathVariable("scenicId") Long scenicId, @RequestBody DeviceStatsReq req) { + return ApiResponse.success(service.queryByScenicId(scenicId, req.getStartTime(), req.getEndTime())); + } +} diff --git a/src/main/java/com/ycwl/basic/mapper/ScenicDeviceStatsMapper.java b/src/main/java/com/ycwl/basic/mapper/ScenicDeviceStatsMapper.java new file mode 100644 index 0000000..c1e95e1 --- /dev/null +++ b/src/main/java/com/ycwl/basic/mapper/ScenicDeviceStatsMapper.java @@ -0,0 +1,25 @@ +package com.ycwl.basic.mapper; + +import com.ycwl.basic.model.pc.scenicDeviceStats.entity.ScenicDeviceStatsEntity; +import com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsResp; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; + +/** + * 景区设备统计Mapper接口 + */ +public interface ScenicDeviceStatsMapper { + /** + * 插入景区设备统计记录 + * @param stats 景区设备统计对象 + * @return 影响行数 + */ + int insert(@Param("stats") ScenicDeviceStatsEntity stats); + + List countDeviceStats(Date start, Date end); + + List countCachedStatsByScenicId(Long scenicId, Date start, Date end); + List countRealtimeStatsByScenicId(Long scenicId, Date start, Date end); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/entity/ScenicDeviceStatsEntity.java b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/entity/ScenicDeviceStatsEntity.java new file mode 100644 index 0000000..80b5cbf --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/entity/ScenicDeviceStatsEntity.java @@ -0,0 +1,16 @@ +package com.ycwl.basic.model.pc.scenicDeviceStats.entity; + +import lombok.Data; + +import java.util.Date; + +/** + * 景区设备统计实体类 + */ +@Data +public class ScenicDeviceStatsEntity { + private Long scenicId; + private Long deviceId; + private Date date; + private Integer count; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/req/DeviceStatsReq.java b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/req/DeviceStatsReq.java new file mode 100644 index 0000000..1f65f96 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/req/DeviceStatsReq.java @@ -0,0 +1,11 @@ +package com.ycwl.basic.model.pc.scenicDeviceStats.req; + +import lombok.Data; + +import java.util.Date; + +@Data +public class DeviceStatsReq { + private Date startTime; + private Date endTime; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsListResp.java b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsListResp.java new file mode 100644 index 0000000..8120811 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsListResp.java @@ -0,0 +1,11 @@ +package com.ycwl.basic.model.pc.scenicDeviceStats.resp; + +import lombok.Data; + +import java.util.List; + +@Data +public class ScenicDeviceStatsListResp { + private List data; + private boolean realtime; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsResp.java b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsResp.java new file mode 100644 index 0000000..90fa49a --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/scenicDeviceStats/resp/ScenicDeviceStatsResp.java @@ -0,0 +1,17 @@ +package com.ycwl.basic.model.pc.scenicDeviceStats.resp; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +public class ScenicDeviceStatsResp { + private Long scenicId; + private String scenicName; + private Long deviceId; + private String deviceName; + private Integer count; + private BigDecimal rate; +} diff --git a/src/main/java/com/ycwl/basic/service/pc/DeviceStatsService.java b/src/main/java/com/ycwl/basic/service/pc/DeviceStatsService.java new file mode 100644 index 0000000..8dd0f76 --- /dev/null +++ b/src/main/java/com/ycwl/basic/service/pc/DeviceStatsService.java @@ -0,0 +1,9 @@ +package com.ycwl.basic.service.pc; + +import com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsListResp; + +import java.util.Date; + +public interface DeviceStatsService { + ScenicDeviceStatsListResp queryByScenicId(Long scenicId, Date start, Date end); +} diff --git a/src/main/java/com/ycwl/basic/service/pc/impl/DeviceStatsServiceImpl.java b/src/main/java/com/ycwl/basic/service/pc/impl/DeviceStatsServiceImpl.java new file mode 100644 index 0000000..9a0617b --- /dev/null +++ b/src/main/java/com/ycwl/basic/service/pc/impl/DeviceStatsServiceImpl.java @@ -0,0 +1,46 @@ +package com.ycwl.basic.service.pc.impl; + +import cn.hutool.core.date.DateUtil; +import com.ycwl.basic.mapper.ScenicDeviceStatsMapper; +import com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsListResp; +import com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsResp; +import com.ycwl.basic.service.pc.DeviceStatsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Date; +import java.util.List; + +@Service +public class DeviceStatsServiceImpl implements DeviceStatsService { + @Autowired + private ScenicDeviceStatsMapper mapper; + + @Override + public ScenicDeviceStatsListResp queryByScenicId(Long scenicId, Date start, Date end) { + if (start == null) { + start = DateUtil.beginOfDay(new Date()); + } + if (end == null) { + end = DateUtil.endOfDay(new Date()); + } + ScenicDeviceStatsListResp resp = new ScenicDeviceStatsListResp(); + if (DateUtil.isIn(start, DateUtil.tomorrow(), DateUtil.yesterday()) && DateUtil.isIn(start, DateUtil.tomorrow(), DateUtil.yesterday())) { + resp.setRealtime(true); + List data = mapper.countRealtimeStatsByScenicId(scenicId, start, end); + resp.setData(data); + } else { + resp.setRealtime(false); + List data = mapper.countCachedStatsByScenicId(scenicId, start, end); + resp.setData(data); + } + resp.getData().stream().mapToInt(ScenicDeviceStatsResp::getCount).max().ifPresent((max) -> { + resp.getData().forEach(item -> { + item.setRate(BigDecimal.valueOf(item.getCount()).divide(BigDecimal.valueOf(max), 6, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100))); + }); + }); + return resp; + } +} diff --git a/src/main/java/com/ycwl/basic/task/ScenicDeviceStatsTask.java b/src/main/java/com/ycwl/basic/task/ScenicDeviceStatsTask.java new file mode 100644 index 0000000..219f5ea --- /dev/null +++ b/src/main/java/com/ycwl/basic/task/ScenicDeviceStatsTask.java @@ -0,0 +1,41 @@ +package com.ycwl.basic.task; + +import cn.hutool.core.date.DateUtil; +import com.ycwl.basic.mapper.ScenicDeviceStatsMapper; +import com.ycwl.basic.model.pc.scenicDeviceStats.entity.ScenicDeviceStatsEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +@Component +@EnableScheduling +public class ScenicDeviceStatsTask { + @Autowired + private ScenicDeviceStatsMapper mapper; + @Scheduled(cron = "0 10 0 * * *") + public void countDeviceStats() { + Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday()); + Date yesterdayEnd = DateUtil.endOfDay(yesterdayStart); + Date twoDaysBeforeStart = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.yesterday(), -1)); + Date twoDaysBeforeEnd = DateUtil.endOfDay(twoDaysBeforeStart); + // 前天的数据 + List list = mapper.countDeviceStats(twoDaysBeforeStart, twoDaysBeforeEnd); + if (!list.isEmpty()) { + list.forEach(stats -> { + stats.setDate(twoDaysBeforeStart); + mapper.insert(stats); + }); + } + list = mapper.countDeviceStats(yesterdayStart, yesterdayEnd); + if (!list.isEmpty()) { + list.forEach(stats -> { + stats.setDate(yesterdayStart); + mapper.insert(stats); + }); + } + } +} diff --git a/src/main/resources/mapper/ScenicDeviceStatsMapper.xml b/src/main/resources/mapper/ScenicDeviceStatsMapper.xml new file mode 100644 index 0000000..1cc7605 --- /dev/null +++ b/src/main/resources/mapper/ScenicDeviceStatsMapper.xml @@ -0,0 +1,73 @@ + + + + + + REPLACE scenic_device_stats ( + scenic_id, + device_id, + date, + count + ) VALUES ( + #{stats.scenicId}, + #{stats.deviceId}, + #{stats.date}, + #{stats.count} + ) + + + + + \ No newline at end of file diff --git a/src/test/java/com/ycwl/basic/task/ScenicDeviceStatsTaskTest.java b/src/test/java/com/ycwl/basic/task/ScenicDeviceStatsTaskTest.java new file mode 100644 index 0000000..6ff31a6 --- /dev/null +++ b/src/test/java/com/ycwl/basic/task/ScenicDeviceStatsTaskTest.java @@ -0,0 +1,24 @@ +package com.ycwl.basic.task; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.jupiter.api.Assertions.*; + + +@Slf4j +@SpringBootTest +@RunWith(SpringRunner.class) +public class ScenicDeviceStatsTaskTest { + @Autowired + private ScenicDeviceStatsTask task; + + @Test + public void testA() { + task.countDeviceStats(); + } +} \ No newline at end of file