| | |
| | | List<TMonitorResult> onlineResult = mongoTemplate.find(query, TMonitorResult.class); |
| | | log.info("大小:{}",onlineResult.size()); |
| | | //此处需要过滤掉设备全景在线 细节不在线的情况 可以按 point分组 分我许多组之后再做处理 |
| | | Map<String, List<TMonitorResult>> ipToDevices = onlineResult.stream() |
| | | .collect(Collectors.groupingBy(TMonitorResult::getIp)); |
| | | // Map<String, List<TMonitorResult>> ipToDevices = onlineResult.stream() |
| | | // .collect(Collectors.groupingBy(TMonitorResult::getIp)); //重要操作 按ip分组 |
| | | |
| | | // onlineResult = ipToDevices.values().stream() |
| | | // .map(devices -> { |
| | |
| | | |
| | | log.info("月份在线数据:{}条数", onlineResult.size()); |
| | | // 使用Collectors.toMap去重,保留每个No的第一个遇到的元素 |
| | | Map<String, TMonitorResult> uniqueResultsMap = onlineResult.stream() |
| | | Map<String, TMonitorResult> fullDataMap = onlineResult.stream() |
| | | .collect(Collectors.toMap( |
| | | TMonitorResult::getNo, // keyMapper,这里假设 getNo() 返回 No 字段 |
| | | Function.identity(), // valueMapper,直接使用对象本身 |
| | |
| | | )); |
| | | |
| | | |
| | | // 将 Map 转换为 List |
| | | List<TMonitorResult> tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); |
| | | log.info("去重后大小:{}", tMonitorResults.size()); |
| | | |
| | | |
| | | // 将 Map 转换为 List 去重后减少数据库消耗 |
| | | List<TMonitorResult> tMonitorResults = new ArrayList<>(fullDataMap.values()); |
| | | // log.info("去重后大小:{}", tMonitorResults.size()); |
| | | |
| | | // 获取动态列数据并构建缓存Map |
| | | Map<Integer, List<DynamicColumnVO>> dynamicColumnMap = new HashMap<>(); |
| | | if (!tMonitorResults.isEmpty()) { |
| | | //获取点位集合 |
| | | //获取ip集合 |
| | | List<Integer> pointIds = tMonitorResults.stream() |
| | | .map(TMonitorResult::getPointId) |
| | | .distinct() // 去重,减少数据库查询 |
| | |
| | | } |
| | | |
| | | // 补充动态列数据 |
| | | // 去重后的动态列信息 |
| | | for (TMonitorResult result : tMonitorResults) { |
| | | result.setDynamicColumnList(dynamicColumnMap.getOrDefault(result.getPointId(), Collections.emptyList())); |
| | | } |
| | | } |
| | | |
| | | // 按部门分组,减少后续循环中的过滤操作 |
| | | Map<Integer, List<TMonitorResult>> deptMonitorMap = tMonitorResults.stream() |
| | | Map<Integer, List<TMonitorResult>> deptMonitorMap = tMonitorResults.stream() //去重后指向 每个设备只有第一天的数据 |
| | | .collect(Collectors.groupingBy(TMonitorResult::getDeptId)); |
| | | |
| | | // 按设备编号分组onlineResult,加速后续查找 |
| | | Map<String, List<TMonitorResult>> noToOnlineMap = onlineResult.stream() |
| | | Map<String, List<TMonitorResult>> noToOnlineMap = onlineResult.stream() //这里值所以数据以设备标号分组,得到其详情 如 1号到31号的录像情况 |
| | | .collect(Collectors.groupingBy(TMonitorResult::getNo)); |
| | | |
| | | // 并行处理各部门数据 |
| | | List<CompletableFuture<ExcelExp>> futures = new ArrayList<>(exportForm.getDeptIds().size()); |
| | | Map<Integer, List<VideoDailyExp>> deptExpMap = new ConcurrentHashMap<>(); |
| | | List<CompletableFuture<ExcelExp>> futures = new ArrayList<>(exportForm.getDeptIds().size());//按前端传入的 部门编号 来判断需要开多少个线程 |
| | | |
| | | Map<Integer, List<VideoDailyExp>> deptExpMap = new ConcurrentHashMap<>(); |
| | | for (Integer deptId : exportForm.getDeptIds()) { |
| | | // 使用部门ID的最终变量 |
| | | final Integer currentDeptId = deptId; |
| | | CompletableFuture<ExcelExp> future = CompletableFuture.supplyAsync(() -> { |
| | | // 直接从预分组的Map中获取,避免每次过滤 |
| | | // deptMonitorMap上面已经在去重后分过组了(这里只是体现了去重的作用,下方每日数据是通过no在noToOnlineMap中取到的) |
| | | |
| | | List<TMonitorResult> monitors = deptMonitorMap.getOrDefault(currentDeptId, Collections.emptyList()); |
| | | |
| | | |
| | | |
| | | if (monitors.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | List<VideoDailyExp> videoDailyExps = new ArrayList<>(monitors.size()); |
| | | AreaDeptEnum areaDeptEnum = AreaDeptEnum.fromDept(currentDeptId); |
| | | String areaName = areaDeptEnum == null ? "未知" : areaDeptEnum.getName(); |
| | |
| | | } |
| | | videoDailyExp.setTag(tag.toString()); |
| | | |
| | | // 设置在线数据 |
| | | // 设置在线数据重点位置 |
| | | try { |
| | | // 从预构建的Map中获取,避免每次过滤 |
| | | // 从预构建的Map中获取,避免每次过滤 正确获得在线数据位置 |
| | | List<TMonitorResult> onlines = noToOnlineMap.getOrDefault(result.getNo(), Collections.emptyList()); |
| | | // 重点查看下面这个方法 videoDailyExp 传入需要组装对象的 videoDailyExp 和 数据源result包含动态列信息的对象 和他对应1到31天的在离线状态 |
| | | setOnlineDaily(videoDailyExp, result, onlines); |
| | | } catch (Exception e) { |
| | | log.error("设置在线数据异常", e); |
| | | } |
| | | |
| | | // |
| | | videoDailyExps.add(videoDailyExp); |
| | | } |
| | | |
| | | // 存储结果到线程安全的Map |
| | | // |
| | | // 存储结果到线程安全的Map 结果如 按区分分组 对应设备的 1到31日的在离线详情 |
| | | deptExpMap.put(currentDeptId, videoDailyExps); |
| | | |
| | | // |
| | | return new ExcelExp(areaName, videoDailyExps, VideoDailyExp.class); |
| | | }, threadPoolTaskExecutor); |
| | | |
| | |
| | | log.info("car数:{}", car); |
| | | log.info("video数:{}", video); |
| | | |
| | | // 处理离线数统计和在线率统计 |
| | | // 离线数统计 |
| | | List<VideoTypeOffOnlineExp> videoTypeOffOnlineExps = new ArrayList<>(); |
| | | // 在线率统计 |
| | | List<VideoOnlineRateExp> videoOnlineRateExps = new ArrayList<>(); |
| | | |
| | | for (Map.Entry<Integer, List<VideoDailyExp>> entry : deptExpMap.entrySet()) { |
| | |
| | | List<VideoDailyExp> list = entry.getValue(); |
| | | AreaDeptEnum areaDeptEnum = AreaDeptEnum.fromDept(deptId); |
| | | |
| | | // 批量处理三种设备类型 |
| | | // 批量处理三种设备类型 每个设备1到31号在离线情况 |
| | | addDeviceStats(list, areaDeptEnum, "1", "人脸", videoTypeOffOnlineExps, videoOnlineRateExps); |
| | | addDeviceStats(list, areaDeptEnum, "2", "卡口", videoTypeOffOnlineExps, videoOnlineRateExps); |
| | | addDeviceStats(list, areaDeptEnum, "3", "视频", videoTypeOffOnlineExps, videoOnlineRateExps); |
| | |
| | | String fieldName = "day" + i; |
| | | String countName = "count" + i; |
| | | for(VideoDailyExp videoDailyExp: videoDailyExps){ |
| | | try { |
| | | // 构造字段名 |
| | | Field field = videoDailyExp.getClass().getDeclaredField(fieldName); |
| | | // 确保字段是私有的可以访问 |
| | |
| | | if ("在线".equals(value)) { |
| | | count ++; |
| | | } |
| | | } catch (NoSuchFieldException e) { |
| | | // 字段不存在时跳过当前循环,记录日志 |
| | | log.warn("VideoDailyExp 不存在字段: {}", fieldName, e); |
| | | } catch (IllegalAccessException e) { |
| | | // 字段访问异常时跳过,记录日志 |
| | | log.error("访问字段 {} 失败", fieldName, e); |
| | | } |
| | | } |
| | | //每日在线率 |
| | | double rate = (double) count / videoDailyExps.size(); |
| | | log.info("打印计算出的count:{}",count); |
| | | //反射添加到对象属性中 |
| | | Field field = videoOnlineRateExp.getClass().getDeclaredField(fieldName); |
| | | Field countField = videoOnlineRateExp.getClass().getDeclaredField(countName); |
| | |
| | | List<TMonitorResult> onlineResult = onlines.stream().filter(online -> online.getNo().equals(result.getNo())).collect(Collectors.toList()); |
| | | videoDailyExp.setOnlineStateList(onlineResult); |
| | | for (TMonitorResult monitorResult : onlineResult) { |
| | | //为空白的原因 如进入第1号时 monitorResult没有对应一号的数据,就是一号mongodb里面没有对应该设备的数据 |
| | | int dayOfMonth = monitorResult.getMongoCreateTime().getDayOfMonth(); |
| | | String online = ""; |
| | | if (ApiConstants.UY_OnlineSite_Online.equals(monitorResult.getOnline())) { |
| | |
| | | field.setAccessible(true); |
| | | field.set(videoDailyExp, online); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | //设置每日录像数据 |