zxl
1 天以前 97b1e0d4820606bef726f60e459b66afb1e8eab1
ycl-server/src/main/java/com/ycl/platform/service/impl/TMonitorServiceImpl.java
@@ -28,10 +28,7 @@
import com.ycl.platform.domain.vo.home.HomeVideoVO;
import com.ycl.platform.domain.vo.screen.MonitorRateVO;
import com.ycl.platform.domain.vo.screen.MonitorTotalVO;
import com.ycl.platform.mapper.DynamicColumnMapper;
import com.ycl.platform.mapper.TMonitorMapper;
import com.ycl.platform.mapper.WorkOrderMapper;
import com.ycl.platform.mapper.YwPointMapper;
import com.ycl.platform.mapper.*;
import com.ycl.platform.service.IMonitorConstructionService;
import com.ycl.platform.service.ITMonitorService;
import com.ycl.system.Result;
@@ -611,8 +608,8 @@
        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 -> {
@@ -635,7 +632,7 @@
        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,直接使用对象本身
@@ -643,16 +640,14 @@
                ));
        // 将 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() // 去重,减少数据库查询
@@ -667,36 +662,34 @@
            }
            // 补充动态列数据
            // 去重后的动态列信息
            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();
@@ -729,21 +722,22 @@
                    }
                    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);
@@ -781,8 +775,9 @@
        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()) {
@@ -790,7 +785,7 @@
            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);
@@ -896,7 +891,7 @@
        videoTypeOffOnlineExp.setArea("自贡市");
        videoTypeOffOnlineExp.setType(type + "合计");
    }
    //在线设备数据,合计对象,信息装配
//    在线设备数据,合计对象,信息装配
    public void setAllVideoTypeOnlineExpCount(
            long allVideoCount,List<VideoOnlineRateExp> videoOnlineRateExps,
                                              VideoOnlineRateExp videoOnlineRateExp,
@@ -1072,18 +1067,27 @@
            String fieldName = "day" + i;
            String countName = "count" + i;
            for(VideoDailyExp videoDailyExp: videoDailyExps){
                // 构造字段名
                Field field = videoDailyExp.getClass().getDeclaredField(fieldName);
                // 确保字段是私有的可以访问
                field.setAccessible(true);
                // 获取字段值
                String value = (String) field.get(videoDailyExp);
                if ("在线".equals(value)) {
                    count ++;
                try {
                    // 构造字段名
                    Field field = videoDailyExp.getClass().getDeclaredField(fieldName);
                    // 确保字段是私有的可以访问
                    field.setAccessible(true);
                    // 获取字段值
                    String value = (String) field.get(videoDailyExp);
                    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);
@@ -1366,18 +1370,38 @@
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 获取月份第一天的Date
        Date startDate = calendar.getTime();
        log.info("首页查询开始日期:{}",startDate);
        // 设置Calendar为月份的最后一天(通过增加一个月份然后减去一天)
        calendar.add(Calendar.MONTH, 1);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        // 获取月份最后一天的Date
        Date endDate = calendar.getTime();
        log.info("首页查询结束日期:{}",endDate);
        String constructionType = monitorQuery.getConstructionType();
        List<String> deviceNoList = new ArrayList<>();
        if (StringUtils.isNotBlank(constructionType)){
            List<MonitorConstruction> serialNumberListByConstructionType = monitorConstructionService.getSerialNumberListByConstructionType(constructionType);
            if (!CollectionUtils.isEmpty(serialNumberListByConstructionType)){
                deviceNoList = serialNumberListByConstructionType.stream().map(MonitorConstruction::getSerialNumber).collect(Collectors.toList());
            }
        }
        if (StringUtils.isNotBlank(constructionType) && deviceNoList.isEmpty()) {
            // 当constructionType有值但无对应设备时,返回包含空列表的Map
            Map<String, Object> emptyResult = new HashMap<>();
            emptyResult.put("list", results); // results此时为空列表
            emptyResult.put("baseLine", 0); // 可根据业务默认基准线值调整
            return emptyResult;
        }
        //mongo查录像状态
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("uy_record_meta_d_sum");
        Integer examineTag = monitorQuery.getExamineTag();
        String arealayerno = monitorQuery.getArea();
        Document matchConditions = new Document("statTime", new Document("$gte", startDate).append("$lte", endDate));
        if (!deviceNoList.isEmpty()) {
            log.info("打印分建类型no集合:{}",deviceNoList);
            matchConditions.append("no", new Document("$in", deviceNoList));
        }
        // 根据examineTag的值动态添加额外的条件
        if (examineTag != null && examineTag.equals(1)) {
            matchConditions.append("provinceTag", true);
@@ -1445,6 +1469,9 @@
        List<Document> onlineMatch = new ArrayList<>();
        onlineMatch.add(new Document("mongoCreateTime", new Document("$gte", startDate).append("$lte", endDate)));
        onlineMatch.add(new Document("monitorType", new Document("$regex", "1")));
        if (!deviceNoList.isEmpty()) {
            onlineMatch.add(new Document("no", new Document("$in", deviceNoList)));
        }
        if (examineTag != null && examineTag.equals(1)) {
            onlineMatch.add(new Document("provinceTag", true));
        } else if (examineTag != null && examineTag.equals(2)) {
@@ -1878,6 +1905,7 @@
        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())) {
@@ -1892,8 +1920,6 @@
            field.setAccessible(true);
            field.set(videoDailyExp, online);
        }
    }
    //设置每日录像数据