对景区摄像头进行统计

This commit is contained in:
2025-05-27 14:42:07 +08:00
parent 0292b754fe
commit 06a07514cc
11 changed files with 296 additions and 0 deletions

View File

@ -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<ScenicDeviceStatsListResp> queryByScenic(@PathVariable("scenicId") Long scenicId, @RequestBody DeviceStatsReq req) {
return ApiResponse.success(service.queryByScenicId(scenicId, req.getStartTime(), req.getEndTime()));
}
}

View File

@ -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<ScenicDeviceStatsEntity> countDeviceStats(Date start, Date end);
List<ScenicDeviceStatsResp> countCachedStatsByScenicId(Long scenicId, Date start, Date end);
List<ScenicDeviceStatsResp> countRealtimeStatsByScenicId(Long scenicId, Date start, Date end);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<ScenicDeviceStatsResp> data;
private boolean realtime;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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<ScenicDeviceStatsResp> data = mapper.countRealtimeStatsByScenicId(scenicId, start, end);
resp.setData(data);
} else {
resp.setRealtime(false);
List<ScenicDeviceStatsResp> 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;
}
}

View File

@ -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<ScenicDeviceStatsEntity> 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);
});
}
}
}

View File

@ -0,0 +1,73 @@
<?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.ycwl.basic.mapper.ScenicDeviceStatsMapper">
<!-- 插入景区设备统计记录 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="stats.id">
REPLACE scenic_device_stats (
scenic_id,
device_id,
date,
count
) VALUES (
#{stats.scenicId},
#{stats.deviceId},
#{stats.date},
#{stats.count}
)
</insert>
<select id="countDeviceStats"
resultType="com.ycwl.basic.model.pc.scenicDeviceStats.entity.ScenicDeviceStatsEntity">
select scenic_id, device_id, count(1) as count
from (
select s.scenic_id, s.device_id
from member_source ms
left join source s on ms.source_id = s.id
where ms.type = 1
and s.create_time >= #{start}
and s.create_time &lt;= #{end}
group by s.scenic_id, s.device_id, ms.face_id
)a
group by scenic_id, device_id
</select>
<select id="countCachedStatsByScenicId"
resultType="com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsResp">
select
ds.scenic_id as scenicId,
s.name as scenicName,
ds.device_id as deviceId,
d.name as deviceName,
IFNULL(sum(ds.count), 0) as count
from scenic_device_stats ds
left join scenic s on ds.scenic_id = s.id
left join device d on ds.device_id = d.id
where s.id = #{scenicId}
and ds.date >= #{start}
and ds.date &lt;= #{end}
group by ds.scenic_id, ds.device_id
</select>
<select id="countRealtimeStatsByScenicId"
resultType="com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsResp">
select
ds.scenic_id as scenicId,
s.name as scenicName,
ds.device_id as deviceId,
d.name as deviceName,
ds.count
from (
select scenic_id, device_id, count(1) as count
from (
select s.scenic_id, s.device_id
from member_source ms
left join source s on ms.source_id = s.id
where ms.type = 1
and s.create_time >= #{start}
and s.create_time &lt;= #{end}
group by s.scenic_id, s.device_id, ms.face_id
)a
group by scenic_id, device_id
) ds
left join scenic s on ds.scenic_id = s.id
left join device d on ds.device_id = d.id
where s.id = #{scenicId}
</select>
</mapper>

View File

@ -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();
}
}