diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java new file mode 100644 index 0000000..7490a27 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java @@ -0,0 +1,92 @@ +package com.casic.missiles.modular.job; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.StatisticNumberMapper; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.model.StatisticNumber; +import com.casic.missiles.modular.service.CockpitService; +import lombok.extern.slf4j.Slf4j; +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.HashMap; +import java.util.List; + +/** + * @Description: 驾驶舱驻留页面-定时推送任务 + * @Author: wangpeng + * @Date: 2022/8/2 16:11 + */ +@Slf4j +@Component +@EnableScheduling +public class CockpitJob { + + @Autowired + private AccessGroupConfig accessGroupConfig; + + @Autowired + private CockpitService cockpitService; + + @Autowired + private StatisticNumberMapper statisticNumberMapper; + + @Autowired + private AbstractDictService dictService; + + /** + * 统计一期二期楼栋,每小时存储各楼栋人数 + */ + @Scheduled(cron = "0 0 0/1 * * ?") + public void buildingPeopleNumber() { + log.info("定时任务执行,每小时存储各楼栋人数"); + //每小时人数存储 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + //将当前时间的人数置为0 + configMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(0); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败1"); + } + }); + }else{ + resultMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(resultMap.get(key)); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败2"); + } + }); + } + + } + + /** + * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 + */ +// @Scheduled(cron = "0 0/1 * * * ?") + public void BeOnDutyRatio() { + + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java new file mode 100644 index 0000000..7490a27 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java @@ -0,0 +1,92 @@ +package com.casic.missiles.modular.job; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.StatisticNumberMapper; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.model.StatisticNumber; +import com.casic.missiles.modular.service.CockpitService; +import lombok.extern.slf4j.Slf4j; +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.HashMap; +import java.util.List; + +/** + * @Description: 驾驶舱驻留页面-定时推送任务 + * @Author: wangpeng + * @Date: 2022/8/2 16:11 + */ +@Slf4j +@Component +@EnableScheduling +public class CockpitJob { + + @Autowired + private AccessGroupConfig accessGroupConfig; + + @Autowired + private CockpitService cockpitService; + + @Autowired + private StatisticNumberMapper statisticNumberMapper; + + @Autowired + private AbstractDictService dictService; + + /** + * 统计一期二期楼栋,每小时存储各楼栋人数 + */ + @Scheduled(cron = "0 0 0/1 * * ?") + public void buildingPeopleNumber() { + log.info("定时任务执行,每小时存储各楼栋人数"); + //每小时人数存储 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + //将当前时间的人数置为0 + configMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(0); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败1"); + } + }); + }else{ + resultMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(resultMap.get(key)); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败2"); + } + }); + } + + } + + /** + * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 + */ +// @Scheduled(cron = "0 0/1 * * * ?") + public void BeOnDutyRatio() { + + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java new file mode 100644 index 0000000..d2ae04e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java @@ -0,0 +1,24 @@ +package com.casic.missiles.modular.model; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** + * @Description: 统计楼栋人数实体类 + * @Author: wangpeng + * @Date: 2022/8/9 13:42 + */ +@Data +@TableName("bus_statistic_number") +public class StatisticNumber extends Model { + @TableId + private Long id; + private String statisticTime; + private Integer statisticQuantity; + private String statisticPosition; + private String statisticPositionName; + private String createTime; + private String updateTime; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java new file mode 100644 index 0000000..7490a27 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java @@ -0,0 +1,92 @@ +package com.casic.missiles.modular.job; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.StatisticNumberMapper; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.model.StatisticNumber; +import com.casic.missiles.modular.service.CockpitService; +import lombok.extern.slf4j.Slf4j; +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.HashMap; +import java.util.List; + +/** + * @Description: 驾驶舱驻留页面-定时推送任务 + * @Author: wangpeng + * @Date: 2022/8/2 16:11 + */ +@Slf4j +@Component +@EnableScheduling +public class CockpitJob { + + @Autowired + private AccessGroupConfig accessGroupConfig; + + @Autowired + private CockpitService cockpitService; + + @Autowired + private StatisticNumberMapper statisticNumberMapper; + + @Autowired + private AbstractDictService dictService; + + /** + * 统计一期二期楼栋,每小时存储各楼栋人数 + */ + @Scheduled(cron = "0 0 0/1 * * ?") + public void buildingPeopleNumber() { + log.info("定时任务执行,每小时存储各楼栋人数"); + //每小时人数存储 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + //将当前时间的人数置为0 + configMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(0); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败1"); + } + }); + }else{ + resultMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(resultMap.get(key)); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败2"); + } + }); + } + + } + + /** + * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 + */ +// @Scheduled(cron = "0 0/1 * * * ?") + public void BeOnDutyRatio() { + + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java new file mode 100644 index 0000000..d2ae04e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java @@ -0,0 +1,24 @@ +package com.casic.missiles.modular.model; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** + * @Description: 统计楼栋人数实体类 + * @Author: wangpeng + * @Date: 2022/8/9 13:42 + */ +@Data +@TableName("bus_statistic_number") +public class StatisticNumber extends Model { + @TableId + private Long id; + private String statisticTime; + private Integer statisticQuantity; + private String statisticPosition; + private String statisticPositionName; + private String createTime; + private String updateTime; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java new file mode 100644 index 0000000..b3d1968 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.service; + +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; + +import java.util.HashMap; +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +public interface CockpitService { + HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java new file mode 100644 index 0000000..7490a27 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java @@ -0,0 +1,92 @@ +package com.casic.missiles.modular.job; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.StatisticNumberMapper; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.model.StatisticNumber; +import com.casic.missiles.modular.service.CockpitService; +import lombok.extern.slf4j.Slf4j; +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.HashMap; +import java.util.List; + +/** + * @Description: 驾驶舱驻留页面-定时推送任务 + * @Author: wangpeng + * @Date: 2022/8/2 16:11 + */ +@Slf4j +@Component +@EnableScheduling +public class CockpitJob { + + @Autowired + private AccessGroupConfig accessGroupConfig; + + @Autowired + private CockpitService cockpitService; + + @Autowired + private StatisticNumberMapper statisticNumberMapper; + + @Autowired + private AbstractDictService dictService; + + /** + * 统计一期二期楼栋,每小时存储各楼栋人数 + */ + @Scheduled(cron = "0 0 0/1 * * ?") + public void buildingPeopleNumber() { + log.info("定时任务执行,每小时存储各楼栋人数"); + //每小时人数存储 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + //将当前时间的人数置为0 + configMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(0); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败1"); + } + }); + }else{ + resultMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(resultMap.get(key)); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败2"); + } + }); + } + + } + + /** + * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 + */ +// @Scheduled(cron = "0 0/1 * * * ?") + public void BeOnDutyRatio() { + + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java new file mode 100644 index 0000000..d2ae04e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java @@ -0,0 +1,24 @@ +package com.casic.missiles.modular.model; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** + * @Description: 统计楼栋人数实体类 + * @Author: wangpeng + * @Date: 2022/8/9 13:42 + */ +@Data +@TableName("bus_statistic_number") +public class StatisticNumber extends Model { + @TableId + private Long id; + private String statisticTime; + private Integer statisticQuantity; + private String statisticPosition; + private String statisticPositionName; + private String createTime; + private String updateTime; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java new file mode 100644 index 0000000..b3d1968 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.service; + +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; + +import java.util.HashMap; +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +public interface CockpitService { + HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java new file mode 100644 index 0000000..6e6076e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java @@ -0,0 +1,113 @@ +package com.casic.missiles.modular.service.impl; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.HikUri; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.service.CockpitService; +import com.casic.missiles.modular.util.HikUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +@Slf4j +@Service +public class CockpitServiceImpl implements CockpitService { + @Autowired + private AbstractDictService dictService; + + @Override + public HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap) { + List eventTypes = new ArrayList<>(); + eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); + eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); + Date date = new Date(); + DateTime startTimeDate = DateUtil.beginOfDay(date); + DateTime endTimeDate = DateUtil.endOfDay(date); + String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + configMap.keySet().stream().forEach(key -> { + List doorIndexCodes = configMap.get(key); + doorEventsRequest.setPageNo(1); + doorEventsRequest.setPageSize(1000); + doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 + doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 + doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 + doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 + String body = JSONObject.toJSONString(doorEventsRequest); + String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); + JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); + if (Objects.isNull(resultJson) || !"0".equals(resultJson.get("code"))) { + log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); + return; + } + JSONObject dataJson = (JSONObject)resultJson.get("data"); + if(Objects.isNull(dataJson)){ + return; + } + JSONArray dataArray = (JSONArray)dataJson.get("list"); + if(Objects.isNull(dataArray)){ + return; + } + + //海康分页限制,需循环请求数据 + if((Integer)dataJson.get("totalPage") > 1){ + for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { + doorEventsRequest.setPageNo(i); + String body1 = JSONObject.toJSONString(doorEventsRequest); + String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); + JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); + if (!"0".equals(resultJson1.get("code"))) { + log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); + return; + } + JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); + if(Objects.isNull(dataJson1)){ + return; + } + JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); + if(Objects.isNull(dataArray1)){ + return; + } + dataArray.addAll(dataArray1); + } + } + jsonMap.put(key, dataArray); + }); + + //构造结构 + jsonMap.keySet().forEach(key -> { + JSONArray list = jsonMap.get(key); + if (Objects.isNull(list)) { + log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); + return; + } + Integer num = 0; + while (list.stream().iterator().hasNext()) { + JSONObject next = (JSONObject) list.stream().iterator().next(); + Integer inAndOutType = next.getInteger("inAndOutType"); + //进门 + if (1 == inAndOutType) { + ++num; + } else if (0 == inAndOutType) { + --num; + } + } + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + resultMap.put(dictName, num); + }); + return resultMap; + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java new file mode 100644 index 0000000..7490a27 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java @@ -0,0 +1,92 @@ +package com.casic.missiles.modular.job; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.StatisticNumberMapper; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.model.StatisticNumber; +import com.casic.missiles.modular.service.CockpitService; +import lombok.extern.slf4j.Slf4j; +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.HashMap; +import java.util.List; + +/** + * @Description: 驾驶舱驻留页面-定时推送任务 + * @Author: wangpeng + * @Date: 2022/8/2 16:11 + */ +@Slf4j +@Component +@EnableScheduling +public class CockpitJob { + + @Autowired + private AccessGroupConfig accessGroupConfig; + + @Autowired + private CockpitService cockpitService; + + @Autowired + private StatisticNumberMapper statisticNumberMapper; + + @Autowired + private AbstractDictService dictService; + + /** + * 统计一期二期楼栋,每小时存储各楼栋人数 + */ + @Scheduled(cron = "0 0 0/1 * * ?") + public void buildingPeopleNumber() { + log.info("定时任务执行,每小时存储各楼栋人数"); + //每小时人数存储 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + //将当前时间的人数置为0 + configMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(0); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败1"); + } + }); + }else{ + resultMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(resultMap.get(key)); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败2"); + } + }); + } + + } + + /** + * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 + */ +// @Scheduled(cron = "0 0/1 * * * ?") + public void BeOnDutyRatio() { + + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java new file mode 100644 index 0000000..d2ae04e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java @@ -0,0 +1,24 @@ +package com.casic.missiles.modular.model; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** + * @Description: 统计楼栋人数实体类 + * @Author: wangpeng + * @Date: 2022/8/9 13:42 + */ +@Data +@TableName("bus_statistic_number") +public class StatisticNumber extends Model { + @TableId + private Long id; + private String statisticTime; + private Integer statisticQuantity; + private String statisticPosition; + private String statisticPositionName; + private String createTime; + private String updateTime; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java new file mode 100644 index 0000000..b3d1968 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.service; + +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; + +import java.util.HashMap; +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +public interface CockpitService { + HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java new file mode 100644 index 0000000..6e6076e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java @@ -0,0 +1,113 @@ +package com.casic.missiles.modular.service.impl; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.HikUri; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.service.CockpitService; +import com.casic.missiles.modular.util.HikUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +@Slf4j +@Service +public class CockpitServiceImpl implements CockpitService { + @Autowired + private AbstractDictService dictService; + + @Override + public HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap) { + List eventTypes = new ArrayList<>(); + eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); + eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); + Date date = new Date(); + DateTime startTimeDate = DateUtil.beginOfDay(date); + DateTime endTimeDate = DateUtil.endOfDay(date); + String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + configMap.keySet().stream().forEach(key -> { + List doorIndexCodes = configMap.get(key); + doorEventsRequest.setPageNo(1); + doorEventsRequest.setPageSize(1000); + doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 + doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 + doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 + doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 + String body = JSONObject.toJSONString(doorEventsRequest); + String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); + JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); + if (Objects.isNull(resultJson) || !"0".equals(resultJson.get("code"))) { + log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); + return; + } + JSONObject dataJson = (JSONObject)resultJson.get("data"); + if(Objects.isNull(dataJson)){ + return; + } + JSONArray dataArray = (JSONArray)dataJson.get("list"); + if(Objects.isNull(dataArray)){ + return; + } + + //海康分页限制,需循环请求数据 + if((Integer)dataJson.get("totalPage") > 1){ + for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { + doorEventsRequest.setPageNo(i); + String body1 = JSONObject.toJSONString(doorEventsRequest); + String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); + JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); + if (!"0".equals(resultJson1.get("code"))) { + log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); + return; + } + JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); + if(Objects.isNull(dataJson1)){ + return; + } + JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); + if(Objects.isNull(dataArray1)){ + return; + } + dataArray.addAll(dataArray1); + } + } + jsonMap.put(key, dataArray); + }); + + //构造结构 + jsonMap.keySet().forEach(key -> { + JSONArray list = jsonMap.get(key); + if (Objects.isNull(list)) { + log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); + return; + } + Integer num = 0; + while (list.stream().iterator().hasNext()) { + JSONObject next = (JSONObject) list.stream().iterator().next(); + Integer inAndOutType = next.getInteger("inAndOutType"); + //进门 + if (1 == inAndOutType) { + ++num; + } else if (0 == inAndOutType) { + --num; + } + } + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + resultMap.put(dictName, num); + }); + return resultMap; + } +} diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml index 4712961..d95fb6f 100644 --- a/casic-web/src/main/resources/config/application-dev.yml +++ b/casic-web/src/main/resources/config/application-dev.yml @@ -12,19 +12,14 @@ port: 11412 password: ew5T4K3#203lwh database: 1 + serializer: org.springframework.data.redis.serializer.StringRedisSerializer redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer -jms: - pub-sub-domain: true + # session: # store-type: redis -# redis: -# host: 111.198.10.15 -# port: 11412 -# password: ew5T4K3#203lwh -# serializer: org.springframework.data.redis.serializer.StringRedisSerializer -# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer + casic: - #kaptcha-open: false #是否开启登录时验证码 (true/false) + kaptcha-open: false #是否开启登录时验证码 (true/false) no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken #flowable数据源和多数据源配置 db: @@ -40,10 +35,9 @@ level.org.springframework.web: info #所属楼栋及各楼栋内门禁点列表配置 -#1/2/3/4对应字典中4个楼栋 +#1/2/3对应字典中一期二期主楼和录制楼 accessgroup: configMap: 1: [1,2,3] 2: [2,3,4] - 3: [3,4,5] - 4: [4,5,6] \ No newline at end of file + 3: [3,4,5] \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java new file mode 100644 index 0000000..7490a27 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java @@ -0,0 +1,92 @@ +package com.casic.missiles.modular.job; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.StatisticNumberMapper; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.model.StatisticNumber; +import com.casic.missiles.modular.service.CockpitService; +import lombok.extern.slf4j.Slf4j; +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.HashMap; +import java.util.List; + +/** + * @Description: 驾驶舱驻留页面-定时推送任务 + * @Author: wangpeng + * @Date: 2022/8/2 16:11 + */ +@Slf4j +@Component +@EnableScheduling +public class CockpitJob { + + @Autowired + private AccessGroupConfig accessGroupConfig; + + @Autowired + private CockpitService cockpitService; + + @Autowired + private StatisticNumberMapper statisticNumberMapper; + + @Autowired + private AbstractDictService dictService; + + /** + * 统计一期二期楼栋,每小时存储各楼栋人数 + */ + @Scheduled(cron = "0 0 0/1 * * ?") + public void buildingPeopleNumber() { + log.info("定时任务执行,每小时存储各楼栋人数"); + //每小时人数存储 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + //将当前时间的人数置为0 + configMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(0); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败1"); + } + }); + }else{ + resultMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(resultMap.get(key)); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败2"); + } + }); + } + + } + + /** + * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 + */ +// @Scheduled(cron = "0 0/1 * * * ?") + public void BeOnDutyRatio() { + + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java new file mode 100644 index 0000000..d2ae04e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java @@ -0,0 +1,24 @@ +package com.casic.missiles.modular.model; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** + * @Description: 统计楼栋人数实体类 + * @Author: wangpeng + * @Date: 2022/8/9 13:42 + */ +@Data +@TableName("bus_statistic_number") +public class StatisticNumber extends Model { + @TableId + private Long id; + private String statisticTime; + private Integer statisticQuantity; + private String statisticPosition; + private String statisticPositionName; + private String createTime; + private String updateTime; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java new file mode 100644 index 0000000..b3d1968 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.service; + +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; + +import java.util.HashMap; +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +public interface CockpitService { + HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java new file mode 100644 index 0000000..6e6076e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java @@ -0,0 +1,113 @@ +package com.casic.missiles.modular.service.impl; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.HikUri; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.service.CockpitService; +import com.casic.missiles.modular.util.HikUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +@Slf4j +@Service +public class CockpitServiceImpl implements CockpitService { + @Autowired + private AbstractDictService dictService; + + @Override + public HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap) { + List eventTypes = new ArrayList<>(); + eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); + eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); + Date date = new Date(); + DateTime startTimeDate = DateUtil.beginOfDay(date); + DateTime endTimeDate = DateUtil.endOfDay(date); + String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + configMap.keySet().stream().forEach(key -> { + List doorIndexCodes = configMap.get(key); + doorEventsRequest.setPageNo(1); + doorEventsRequest.setPageSize(1000); + doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 + doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 + doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 + doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 + String body = JSONObject.toJSONString(doorEventsRequest); + String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); + JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); + if (Objects.isNull(resultJson) || !"0".equals(resultJson.get("code"))) { + log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); + return; + } + JSONObject dataJson = (JSONObject)resultJson.get("data"); + if(Objects.isNull(dataJson)){ + return; + } + JSONArray dataArray = (JSONArray)dataJson.get("list"); + if(Objects.isNull(dataArray)){ + return; + } + + //海康分页限制,需循环请求数据 + if((Integer)dataJson.get("totalPage") > 1){ + for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { + doorEventsRequest.setPageNo(i); + String body1 = JSONObject.toJSONString(doorEventsRequest); + String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); + JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); + if (!"0".equals(resultJson1.get("code"))) { + log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); + return; + } + JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); + if(Objects.isNull(dataJson1)){ + return; + } + JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); + if(Objects.isNull(dataArray1)){ + return; + } + dataArray.addAll(dataArray1); + } + } + jsonMap.put(key, dataArray); + }); + + //构造结构 + jsonMap.keySet().forEach(key -> { + JSONArray list = jsonMap.get(key); + if (Objects.isNull(list)) { + log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); + return; + } + Integer num = 0; + while (list.stream().iterator().hasNext()) { + JSONObject next = (JSONObject) list.stream().iterator().next(); + Integer inAndOutType = next.getInteger("inAndOutType"); + //进门 + if (1 == inAndOutType) { + ++num; + } else if (0 == inAndOutType) { + --num; + } + } + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + resultMap.put(dictName, num); + }); + return resultMap; + } +} diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml index 4712961..d95fb6f 100644 --- a/casic-web/src/main/resources/config/application-dev.yml +++ b/casic-web/src/main/resources/config/application-dev.yml @@ -12,19 +12,14 @@ port: 11412 password: ew5T4K3#203lwh database: 1 + serializer: org.springframework.data.redis.serializer.StringRedisSerializer redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer -jms: - pub-sub-domain: true + # session: # store-type: redis -# redis: -# host: 111.198.10.15 -# port: 11412 -# password: ew5T4K3#203lwh -# serializer: org.springframework.data.redis.serializer.StringRedisSerializer -# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer + casic: - #kaptcha-open: false #是否开启登录时验证码 (true/false) + kaptcha-open: false #是否开启登录时验证码 (true/false) no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken #flowable数据源和多数据源配置 db: @@ -40,10 +35,9 @@ level.org.springframework.web: info #所属楼栋及各楼栋内门禁点列表配置 -#1/2/3/4对应字典中4个楼栋 +#1/2/3对应字典中一期二期主楼和录制楼 accessgroup: configMap: 1: [1,2,3] 2: [2,3,4] - 3: [3,4,5] - 4: [4,5,6] \ No newline at end of file + 3: [3,4,5] \ No newline at end of file diff --git a/casic-web/src/main/resources/config/application.yml b/casic-web/src/main/resources/config/application.yml index 95b8eee..86971f8 100644 --- a/casic-web/src/main/resources/config/application.yml +++ b/casic-web/src/main/resources/config/application.yml @@ -26,8 +26,9 @@ spring-session-open: false #是否开启spring session,如果是多机环境需要开启(true/false) session-invalidate-time: 86400 #session失效时间(只在单机环境下生效,,多机环境在SpringSessionConfig类中配置) 单位:秒 session-validation-interval: 900 #多久检测一次失效的session(只在单机环境下生效) 单位:秒 - no-login-urls: /user/login,/kaptcha,/config/baseConfig - - config: - export-path: D:\java\boot\guns-web-1.0.0-SNAPSHOT\export\ - config-path: E:\Develop\IdeaProject\smartcity\casic-smartcity-dcms\casic-web\src\main\resources\config\ \ No newline at end of file + no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken + file: + uploadPath: D:\tmp\ #图片下载本地地址 +# config: +# export-path: D:\java\boot\guns-web-1.0.0-SNAPSHOT\export\ +# config-path: E:\Develop\IdeaProject\smartcity\casic-smartcity-dcms\casic-web\src\main\resources\config\ \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java index 4b92489..a5c7d10 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/cockpit/CockpitController.java @@ -2,18 +2,19 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.casic.missiles.core.application.service.AbstractDictService; import com.casic.missiles.model.response.ResponseData; -import com.casic.missiles.modular.dao.CaseInfoMapper; -import com.casic.missiles.modular.dao.CategoryLevelMapper; -import com.casic.missiles.modular.dao.DeviceInfoMapper; -import com.casic.missiles.modular.dao.FireEquipInfoMapper; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.*; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; import com.casic.missiles.modular.dto.statistics.*; import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.model.CaseCategoryLevel; -import com.casic.missiles.modular.model.CaseInfo; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.model.*; import com.casic.missiles.modular.redis.RedisUtil; import com.casic.missiles.modular.redis.key.CacheKeys; +import com.casic.missiles.modular.service.CockpitService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; @@ -41,6 +42,9 @@ private RedisUtil redisUtil; @Autowired + private CockpitService cockpitService; + + @Autowired private AbstractDictService dictService; @Autowired @@ -55,6 +59,141 @@ @Autowired private FireEquipInfoMapper fireEquipInfoMapper; + @Autowired + private VisitInfoMapper visitInfoMapper; + + @Autowired + private StaffInfoMapper staffInfoMapper; + + @Autowired + private VisitorApplyMapper applyMapper; + + @Autowired + private StatisticNumberMapper numberMapper; + + @Autowired + private AccessGroupConfig accessGroupConfig; + + /** + * 各楼栋人数计算 + */ + @GetMapping("/build/peopleNumber") + @ResponseBody + public Object buildingPeopleNumber(){ + //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + return ResponseData.error("无门禁点数据"); + } + + return ResponseData.success(resultMap); + } + + /** + * 每小时各楼栋人数 + */ + @GetMapping("/build/numberPerHour") + @ResponseBody + public Object buildingNumberPerHour(){ + //当天按小时分组的人数 + List list = numberMapper.selectListByTime(); + Map> collect = list.stream().collect(Collectors.groupingBy(BuildingNumberDTO::getStatisticPosition)); + return ResponseData.success(collect); + } + + /** + * 今日访客量计算 + */ + @GetMapping("/visitor/todayNumber") + @ResponseBody + public Object visitorTodayNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); + List visitInfos = visitInfoMapper.selectList(wrapper); + HashMap resultMap = new HashMap<>(); + resultMap.put("今日访客量", visitInfos.size()); + return ResponseData.success(resultMap); + } + + /** + * 计算设备总数及在线率 + */ + @GetMapping("/device/number") + @ResponseBody + public Object deviceNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + Integer total = deviceInfoMapper.selectCount(wrapper); + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 + Integer online = deviceInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) online / (float) total * 100); + HashMap resultMap = new HashMap<>(); + resultMap.put("设备总数", total); + resultMap.put("设备在线率", result+"%"); + return ResponseData.success(resultMap); + } + + /** + * 安保人员总数及安保人员离岗率 + */ + @GetMapping("/staff/securityNumber") + @ResponseBody + public Object securityNumber() { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("staff_type", 2); + Integer total = staffInfoMapper.selectCount(wrapper); + //当日离岗事件个数 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); + wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); + Integer leave = caseInfoMapper.selectCount(wrapper1); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + String result = numberFormat.format((float) leave / (float) total * 100); + HashMap resultMap = new HashMap<>(); + if(0 == total){ + resultMap.put("安保人员总数", 0); + resultMap.put("安保人员离岗率", "0%"); + }else{ + resultMap.put("安保人员总数", total); + resultMap.put("安保人员离岗率", result+"%"); + } + return ResponseData.success(resultMap); + } + + /** + * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 + */ + @GetMapping("/visitor/applyDetail") + @ResponseBody + public Object visitorApplyDetail() { + List reasonGroup = applyMapper.selectByVisitReason(); + HashMap resultMap = new HashMap<>(); + NumberFormat numberFormat = NumberFormat.getInstance(); + // 设置精确到小数点后2位 + numberFormat.setMaximumFractionDigits(2); + long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); + if(0 == sum){ + return ResponseData.success(); + } + reasonGroup.forEach(group -> { + String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); + String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); + resultMap.put(reasonName, result+"%"); + }); + return ResponseData.success(resultMap); + } + /** * 重点区域威胁事件历史统计,计算每个月的各级别事件的数量 */ diff --git a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java index 4cad1dd..2740a1e 100644 --- a/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java +++ b/casic-server/src/main/java/com/casic/missiles/modular/controller/hik/HikController.java @@ -111,14 +111,14 @@ ThreadPoolUtil.executorService.execute(new Thread(new Runnable() { @Override public void run() { - CaseHandle(hikRecvEvent, eventType, caseInfo); + caseHandle(hikRecvEvent, eventType, caseInfo); } })); return null; } - private void CaseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { + private void caseHandle(HikRecvEvent hikRecvEvent, Long eventType, CaseInfo caseInfo) { JSONArray eventArray = hikRecvEvent.getEventArray(); List caseInfos = new ArrayList<>(); while (eventArray.stream().iterator().hasNext()) { diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java new file mode 100644 index 0000000..d2377fe --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/StatisticNumberMapper.java @@ -0,0 +1,18 @@ +package com.casic.missiles.modular.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.casic.missiles.modular.dto.statistics.BuildingNumberDTO; +import com.casic.missiles.modular.model.StatisticNumber; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:45 + */ +@Mapper +public interface StatisticNumberMapper extends BaseMapper { + List selectListByTime(); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml new file mode 100644 index 0000000..6d00458 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dao/mapping/StatisticNumberMapper.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java new file mode 100644 index 0000000..0924009 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/dto/statistics/BuildingNumberDTO.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.dto.statistics; + +import lombok.Data; + +/** + * @Description: 每小时各楼栋人数DTO + * @Author: wangpeng + * @Date: 2022/8/9 14:34 + */ +@Data +public class BuildingNumberDTO { + private String statisticPosition; + private String statisticPositionName; + private String statisticTime; + private String statisticQuantity; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java deleted file mode 100644 index 0cfe24a..0000000 --- a/casic-server/src/main/java/com/casic/missiles/modular/job/BuildingPeopleNumberJob.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.casic.missiles.modular.job; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.casic.missiles.core.application.service.AbstractDictService; -import com.casic.missiles.modular.config.AccessGroupConfig; -import com.casic.missiles.modular.dao.*; -import com.casic.missiles.modular.dto.hik.DoorEventsRequest; -import com.casic.missiles.modular.dto.statistics.ApplyReasonGroupDTO; -import com.casic.missiles.modular.enums.HikUri; -import com.casic.missiles.modular.enums.SecurityEventDict; -import com.casic.missiles.modular.enums.SecurityEventType; -import com.casic.missiles.modular.model.CaseInfo; -import com.casic.missiles.modular.model.DeviceInfo; -import com.casic.missiles.modular.model.StaffInfo; -import com.casic.missiles.modular.model.VisitInfo; -import com.casic.missiles.modular.util.HikUtil; -import com.casic.missiles.modular.util.WebSocket; -import lombok.extern.slf4j.Slf4j; -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.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @Description: 驾驶舱驻留页面-定时推送任务 - * @Author: wangpeng - * @Date: 2022/8/2 16:11 - */ -@Slf4j -@Component -@EnableScheduling -public class BuildingPeopleNumberJob { - @Autowired - private AccessGroupConfig accessGroupConfig; - - @Autowired - private AbstractDictService dictService; - - @Autowired - private WebSocket webSocket; - - @Autowired - private DeviceInfoMapper deviceInfoMapper; - - @Autowired - private VisitInfoMapper visitInfoMapper; - - @Autowired - private StaffInfoMapper staffInfoMapper; - - @Autowired - private CaseInfoMapper caseInfoMapper; - - @Autowired - private VisitorApplyMapper applyMapper; - - /** - * 各楼栋人数计算定时任务 - */ - @Scheduled(initialDelay = 60000, fixedDelay = 60000) - public void buildingPeopleNumber() { - //统计各楼的,查询当天每小时段内人数 - //查询海康门禁点事件v2,只查询当天的,将返回的list中的所有进出类型进行计算,得到当天的人数 - DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); - List eventTypes = new ArrayList<>(); - eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); - eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); - - // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 - HashMap> configMap = accessGroupConfig.getConfigMap(); - HashMap jsonMap = new HashMap<>(); - HashMap resultMap = new HashMap<>(); - Date date = new Date(); - DateTime startTimeDate = DateUtil.beginOfDay(date); - DateTime endTimeDate = DateUtil.endOfDay(date); - String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); - configMap.keySet().stream().forEach(key -> { - List doorIndexCodes = configMap.get(key); - doorEventsRequest.setPageNo(1); - doorEventsRequest.setPageSize(1000); - doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 - doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 - doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 - doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 - String body = JSONObject.toJSONString(doorEventsRequest); - String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); - JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson.get("code"))) { - log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); - return; - } - JSONObject dataJson = (JSONObject)resultJson.get("data"); - if(Objects.isNull(dataJson)){ - return; - } - JSONArray dataArray = (JSONArray)dataJson.get("list"); - if(Objects.isNull(dataArray)){ - return; - } - - //海康分页限制,需循环请求数据 - if((Integer)dataJson.get("totalPage") > 1){ - for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { - doorEventsRequest.setPageNo(i); - String body1 = JSONObject.toJSONString(doorEventsRequest); - String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); - JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); - if (!"0".equals(resultJson1.get("code"))) { - log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); - return; - } - JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); - if(Objects.isNull(dataJson1)){ - return; - } - JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); - if(Objects.isNull(dataArray1)){ - return; - } - dataArray.addAll(dataArray1); - } - } - jsonMap.put(key, dataArray); - }); - if (jsonMap.size() != configMap.size()) { - return; - } - - //构造结构 - jsonMap.keySet().forEach(key -> { - JSONArray list = jsonMap.get(key); - if (Objects.isNull(list)) { - log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); - return; - } - Integer num = 0; - while (list.stream().iterator().hasNext()) { - JSONObject next = (JSONObject) list.stream().iterator().next(); - Integer inAndOutType = next.getInteger("inAndOutType"); - //进门 - if (1 == inAndOutType) { - ++num; - } else if (0 == inAndOutType) { - --num; - } - } - resultMap.put(key, num); - }); - - if (resultMap.size() != configMap.size()) { - return; - } - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - - // TODO: 2022/8/5 各时段人数统计 - //根据当前时间判断,每小时保存一次人数信息 - - return; - - } - - /** - * 今日访客量计算定时任务 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void visitorNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.apply("date_format(now(),'%Y-%m-%d') = date_format(in_time,'%Y-%m-%d')"); - List visitInfos = visitInfoMapper.selectList(wrapper); - HashMap resultMap = new HashMap<>(); - resultMap.put("今日访客量", visitInfos.size()); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 计算设备总数及在线率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void deviceNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - Integer total = deviceInfoMapper.selectCount(wrapper); - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("status", 1); //字典值:在线1、离线2、故障3 - Integer online = deviceInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) online / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("设备总数", total); - resultMap.put("设备在线率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 安保人员总数及安保人员离岗率 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void SecurityPersonNumber() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("staff_type", 2); - Integer total = staffInfoMapper.selectCount(wrapper); - //当日离岗事件个数 - QueryWrapper wrapper1 = new QueryWrapper<>(); - wrapper1.eq("hik_event_type", SecurityEventType.PERSONNEL_DEMOBILIZED_EVENT); - wrapper1.apply("date_format(now(),'%Y-%m-%d') = date_format(happen_time,'%Y-%m-%d')"); - Integer leave = caseInfoMapper.selectCount(wrapper1); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - String result = numberFormat.format((float) leave / (float) total * 100); - HashMap resultMap = new HashMap<>(); - resultMap.put("安保人员总数", total); - resultMap.put("安保人员离岗率", result+"%"); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 访客预约详情,按照访客访问目的字典进行分组,计算占总数的占比 - */ - @Scheduled(cron = "0 0/1 * * * ?") - public void VisitorApplyDetail() { - List reasonGroup = applyMapper.selectByVisitReason(); - HashMap resultMap = new HashMap<>(); - NumberFormat numberFormat = NumberFormat.getInstance(); - // 设置精确到小数点后2位 - numberFormat.setMaximumFractionDigits(2); - long sum = reasonGroup.stream().collect(Collectors.summarizingInt(ApplyReasonGroupDTO::getQuantity)).getSum(); - reasonGroup.forEach(group -> { - String reasonName = dictService.getDictNameByCode(SecurityEventDict.VISIT_REASON, group.getVisitReason()); - String result = numberFormat.format((float) group.getQuantity() / (float) sum * 100); - resultMap.put(reasonName, result+"%"); - }); - //websocket推送 - webSocket.sendAllMessage(JSONObject.toJSONString(resultMap)); - } - - /** - * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 - */ -// @Scheduled(cron = "0 0/1 * * * ?") - public void BeOnDutyRatio() { - - } - -} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java new file mode 100644 index 0000000..7490a27 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/job/CockpitJob.java @@ -0,0 +1,92 @@ +package com.casic.missiles.modular.job; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.config.AccessGroupConfig; +import com.casic.missiles.modular.dao.StatisticNumberMapper; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.model.StatisticNumber; +import com.casic.missiles.modular.service.CockpitService; +import lombok.extern.slf4j.Slf4j; +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.HashMap; +import java.util.List; + +/** + * @Description: 驾驶舱驻留页面-定时推送任务 + * @Author: wangpeng + * @Date: 2022/8/2 16:11 + */ +@Slf4j +@Component +@EnableScheduling +public class CockpitJob { + + @Autowired + private AccessGroupConfig accessGroupConfig; + + @Autowired + private CockpitService cockpitService; + + @Autowired + private StatisticNumberMapper statisticNumberMapper; + + @Autowired + private AbstractDictService dictService; + + /** + * 统计一期二期楼栋,每小时存储各楼栋人数 + */ + @Scheduled(cron = "0 0 0/1 * * ?") + public void buildingPeopleNumber() { + log.info("定时任务执行,每小时存储各楼栋人数"); + //每小时人数存储 + DoorEventsRequest doorEventsRequest = new DoorEventsRequest(); + // TODO: 2022/7/29 将所属楼栋及楼栋内的门禁点列表放到yml中 + HashMap> configMap = accessGroupConfig.getConfigMap(); + HashMap jsonMap = new HashMap<>(); + HashMap resultMap = new HashMap<>(); + cockpitService.dataHandle(doorEventsRequest, configMap, jsonMap, resultMap); + if(resultMap.size() == 0){ + //将当前时间的人数置为0 + configMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(0); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败1"); + } + }); + }else{ + resultMap.keySet().forEach(key -> { + StatisticNumber statisticNumber = new StatisticNumber(); + statisticNumber.setStatisticPosition(String.valueOf(key)); + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + statisticNumber.setStatisticPositionName(dictName); + statisticNumber.setStatisticTime(DateUtil.now()); + statisticNumber.setStatisticQuantity(resultMap.get(key)); + if(statisticNumberMapper.insert(statisticNumber) <= 0){ + log.info("定时任务,每小时存储各楼栋人数入库失败2"); + } + }); + } + + } + + /** + * 机动力量实时在岗率,在岗人数除以总应在岗人数,功能待定 + */ +// @Scheduled(cron = "0 0/1 * * * ?") + public void BeOnDutyRatio() { + + } +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java new file mode 100644 index 0000000..d2ae04e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/model/StatisticNumber.java @@ -0,0 +1,24 @@ +package com.casic.missiles.modular.model; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** + * @Description: 统计楼栋人数实体类 + * @Author: wangpeng + * @Date: 2022/8/9 13:42 + */ +@Data +@TableName("bus_statistic_number") +public class StatisticNumber extends Model { + @TableId + private Long id; + private String statisticTime; + private Integer statisticQuantity; + private String statisticPosition; + private String statisticPositionName; + private String createTime; + private String updateTime; +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java new file mode 100644 index 0000000..b3d1968 --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/CockpitService.java @@ -0,0 +1,16 @@ +package com.casic.missiles.modular.service; + +import com.alibaba.fastjson.JSONArray; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; + +import java.util.HashMap; +import java.util.List; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +public interface CockpitService { + HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap); +} diff --git a/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java new file mode 100644 index 0000000..6e6076e --- /dev/null +++ b/casic-server/src/main/java/com/casic/missiles/modular/service/impl/CockpitServiceImpl.java @@ -0,0 +1,113 @@ +package com.casic.missiles.modular.service.impl; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.casic.missiles.core.application.service.AbstractDictService; +import com.casic.missiles.modular.dto.hik.DoorEventsRequest; +import com.casic.missiles.modular.enums.HikUri; +import com.casic.missiles.modular.enums.SecurityEventDict; +import com.casic.missiles.modular.enums.SecurityEventType; +import com.casic.missiles.modular.service.CockpitService; +import com.casic.missiles.modular.util.HikUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * @Description: + * @Author: wangpeng + * @Date: 2022/8/9 13:49 + */ +@Slf4j +@Service +public class CockpitServiceImpl implements CockpitService { + @Autowired + private AbstractDictService dictService; + + @Override + public HashMap dataHandle(DoorEventsRequest doorEventsRequest, HashMap> configMap, HashMap jsonMap, HashMap resultMap) { + List eventTypes = new ArrayList<>(); + eventTypes.add(SecurityEventType.CARD_COMPARE_PASS); + eventTypes.add(SecurityEventType.FACE_COMPARE_PASS); + Date date = new Date(); + DateTime startTimeDate = DateUtil.beginOfDay(date); + DateTime endTimeDate = DateUtil.endOfDay(date); + String startTime = DateUtil.format(startTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + String endTime = DateUtil.format(endTimeDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + configMap.keySet().stream().forEach(key -> { + List doorIndexCodes = configMap.get(key); + doorEventsRequest.setPageNo(1); + doorEventsRequest.setPageSize(1000); + doorEventsRequest.setDoorIndexCodes(doorIndexCodes); //门禁点列表 + doorEventsRequest.setEventTypes(eventTypes); //事件类型列表 + doorEventsRequest.setStartTime(startTime); //开始时间,当日0点 + doorEventsRequest.setEndTime(endTime); //结束时间,当日23:59 + String body = JSONObject.toJSONString(doorEventsRequest); + String resultStr = HikUtil.hikApi(HikUri.DOOR_EVENTS, body); + JSONObject resultJson = (JSONObject) JSONObject.parse(resultStr); + if (Objects.isNull(resultJson) || !"0".equals(resultJson.get("code"))) { + log.error("请求海康,查询海康门禁点事件v2失败,海康response:{}", resultStr); + return; + } + JSONObject dataJson = (JSONObject)resultJson.get("data"); + if(Objects.isNull(dataJson)){ + return; + } + JSONArray dataArray = (JSONArray)dataJson.get("list"); + if(Objects.isNull(dataArray)){ + return; + } + + //海康分页限制,需循环请求数据 + if((Integer)dataJson.get("totalPage") > 1){ + for (int i = 2; i <=(Integer)dataJson.get("totalPage"); i++) { + doorEventsRequest.setPageNo(i); + String body1 = JSONObject.toJSONString(doorEventsRequest); + String resultStr1 = HikUtil.hikApi(HikUri.DOOR_EVENTS, body1); + JSONObject resultJson1 = (JSONObject) JSONObject.parse(resultStr); + if (!"0".equals(resultJson1.get("code"))) { + log.error("请求海康,循环查询海康门禁点事件v2失败,海康response:{}", resultStr1); + return; + } + JSONObject dataJson1 = (JSONObject)resultJson1.get("data"); + if(Objects.isNull(dataJson1)){ + return; + } + JSONArray dataArray1 = (JSONArray)dataJson1.get("list"); + if(Objects.isNull(dataArray1)){ + return; + } + dataArray.addAll(dataArray1); + } + } + jsonMap.put(key, dataArray); + }); + + //构造结构 + jsonMap.keySet().forEach(key -> { + JSONArray list = jsonMap.get(key); + if (Objects.isNull(list)) { + log.error("请求海康,查询海康门禁点事件v2,结果list为null,该楼栋为:{}", key); + return; + } + Integer num = 0; + while (list.stream().iterator().hasNext()) { + JSONObject next = (JSONObject) list.stream().iterator().next(); + Integer inAndOutType = next.getInteger("inAndOutType"); + //进门 + if (1 == inAndOutType) { + ++num; + } else if (0 == inAndOutType) { + --num; + } + } + String dictName = dictService.getDictNameByCode(SecurityEventDict.DEVICE_POSITION, String.valueOf(key)); + resultMap.put(dictName, num); + }); + return resultMap; + } +} diff --git a/casic-web/src/main/resources/config/application-dev.yml b/casic-web/src/main/resources/config/application-dev.yml index 4712961..d95fb6f 100644 --- a/casic-web/src/main/resources/config/application-dev.yml +++ b/casic-web/src/main/resources/config/application-dev.yml @@ -12,19 +12,14 @@ port: 11412 password: ew5T4K3#203lwh database: 1 + serializer: org.springframework.data.redis.serializer.StringRedisSerializer redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer -jms: - pub-sub-domain: true + # session: # store-type: redis -# redis: -# host: 111.198.10.15 -# port: 11412 -# password: ew5T4K3#203lwh -# serializer: org.springframework.data.redis.serializer.StringRedisSerializer -# redisValueSerializer: org.springframework.data.redis.serializer.JdkSerializationRedisSerializer + casic: - #kaptcha-open: false #是否开启登录时验证码 (true/false) + kaptcha-open: false #是否开启登录时验证码 (true/false) no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken #flowable数据源和多数据源配置 db: @@ -40,10 +35,9 @@ level.org.springframework.web: info #所属楼栋及各楼栋内门禁点列表配置 -#1/2/3/4对应字典中4个楼栋 +#1/2/3对应字典中一期二期主楼和录制楼 accessgroup: configMap: 1: [1,2,3] 2: [2,3,4] - 3: [3,4,5] - 4: [4,5,6] \ No newline at end of file + 3: [3,4,5] \ No newline at end of file diff --git a/casic-web/src/main/resources/config/application.yml b/casic-web/src/main/resources/config/application.yml index 95b8eee..86971f8 100644 --- a/casic-web/src/main/resources/config/application.yml +++ b/casic-web/src/main/resources/config/application.yml @@ -26,8 +26,9 @@ spring-session-open: false #是否开启spring session,如果是多机环境需要开启(true/false) session-invalidate-time: 86400 #session失效时间(只在单机环境下生效,,多机环境在SpringSessionConfig类中配置) 单位:秒 session-validation-interval: 900 #多久检测一次失效的session(只在单机环境下生效) 单位:秒 - no-login-urls: /user/login,/kaptcha,/config/baseConfig - - config: - export-path: D:\java\boot\guns-web-1.0.0-SNAPSHOT\export\ - config-path: E:\Develop\IdeaProject\smartcity\casic-smartcity-dcms\casic-web\src\main\resources\config\ \ No newline at end of file + no-login-urls: ${casic.sysUrl}/user/login,${casic.sysUrl}/user/appLogin,${casic.sysUrl}/kaptcha/base64,${casic.sysUrl}/config/baseConfig,/route/mockToken + file: + uploadPath: D:\tmp\ #图片下载本地地址 +# config: +# export-path: D:\java\boot\guns-web-1.0.0-SNAPSHOT\export\ +# config-path: E:\Develop\IdeaProject\smartcity\casic-smartcity-dcms\casic-web\src\main\resources\config\ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8fd6c47..ec30791 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,6 @@ mybatis-plus-boot-starter ${mybatis-plus-boot-starter} - com.alibaba druid