zxl
4 天以前 c83101eb62f5d4906b9c01ceea6b21a37f9e84d8
ycl-server/src/main/java/com/ycl/platform/service/impl/DataCenterServiceImpl.java
@@ -6,6 +6,7 @@
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.DistinctIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.ycl.platform.domain.entity.*;
@@ -1918,6 +1919,7 @@
     */
    @Override
    public Result videoAssessmentFileRatio(DataCenterQuery params) {
        long startTIme = System.currentTimeMillis();
        List<String> likeFileds = Arrays.asList("ip.showValue", "name.showValue", "serialNumber.showValue");
        List<Criteria> andCriteria = MongoUtil.getAndCriteria(params, TIME_FIELD, likeFileds, null);
        Query query = new Query();
@@ -1925,6 +1927,7 @@
        and.andOperator(andCriteria);
        query = Query.query(and);
        long total = mongoTemplate.count(query, MonitorQualifyResult.class);
        MongoUtil.setPage(query, params, TIME_FIELD);
        List<MonitorQualifyResult> resultList = mongoTemplate.find(query, MonitorQualifyResult.class);
        List<MonitorQualifyResultVO> resultVOS = new ArrayList<>();
@@ -1932,43 +1935,45 @@
            MonitorQualifyResultVO vo = MonitorQualifyResult.getVO(result);
            resultVOS.add(vo);
        }
        // 统计数量
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("uy_monitor_qualify");
        //总数
        List<Document> dList1 = new ArrayList<>(2);
        DataCenterQuery totalParams = new DataCenterQuery();
        BeanUtils.copyProperties(params, totalParams);
        totalParams.setStartTime(null);
        setTag(totalParams, dList1);
        Document totalFilter = new Document("$and", dList1);
        //当日档案数
        List<Document> dList2 = new ArrayList<>(2);
        setTag(params, dList2);
        Document newFilter = new Document("$and", dList2);
        long endTime = System.currentTimeMillis();
        log.info("查询档案考核比使用时间:{}ms",endTime-startTIme);
//        // 统计数量
//        MongoDatabase database = mongoTemplate.getDb();
//        MongoCollection<Document> collection = database.getCollection("uy_monitor_qualify");
//        //总数
//        List<Document> dList1 = new ArrayList<>(2);
//        DataCenterQuery totalParams = new DataCenterQuery();
//        BeanUtils.copyProperties(params, totalParams);
//        totalParams.setStartTime(null);
//        setTag(totalParams, dList1);
//        Document totalFilter = new Document("$and", dList1);
//        //当日档案数
//        List<Document> dList2 = new ArrayList<>(2);
//        setTag(params, dList2);
//        Document newFilter = new Document("$and", dList2);
        List<Document> lists = Arrays.asList(totalFilter, newFilter);
        List<String> rList = lists.stream().map(filter -> {
            // 构建聚合管道
            List<Document> pipeline = Arrays.asList(
                    new Document("$match", filter),
                    // $group 去重
                    new Document("$group", new Document("_id", "$serialNumber.showValue")),
                    new Document("$count", "uniqueDeviceIds")
            );
            // 执行聚合查询并获取结果
            AggregateIterable<Document> result = collection.aggregate(pipeline);
            Integer uniqueDeviceIdCount = 0;
            for (Document doc : result) {
                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
                break; // 不需要继续遍历,因为 $count 只会产生一个结果
            }
            return uniqueDeviceIdCount + "";
        }).collect(Collectors.toList());
        BigDecimal onlineRate = BigDecimal.ZERO;
        if (!StringUtils.isEmpty(rList.get(0)) && !"0".equals(rList.get(0))) {
            onlineRate = new BigDecimal(rList.get(1)).divide(new BigDecimal(rList.get(0)), 3,RoundingMode.DOWN).multiply(new BigDecimal("100"));
        }
        List<String> rlist = this.buildVideoAssessmentFileRatioCount(params);
//        List<String> rList = lists.stream().map(filter -> {
//            // 构建聚合管道
//            List<Document> pipeline = Arrays.asList(
//                    new Document("$match", filter),
//                    // $group 去重
//                    new Document("$group", new Document("_id", "$serialNumber.showValue")),
//                    new Document("$count", "uniqueDeviceIds")
//            );
//            // 执行聚合查询并获取结果
//            AggregateIterable<Document> result = collection.aggregate(pipeline);
//            Integer uniqueDeviceIdCount = 0;
//            for (Document doc : result) {
//                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
//                break; // 不需要继续遍历,因为 $count 只会产生一个结果
//            }
//            return uniqueDeviceIdCount + "";
//        }).collect(Collectors.toList());
//        BigDecimal onlineRate = BigDecimal.ZERO;
//        if (!StringUtils.isEmpty(rList.get(0)) && !"0".equals(rList.get(0))) {
//            onlineRate = new BigDecimal(rList.get(1)).divide(new BigDecimal(rList.get(0)), 3,RoundingMode.DOWN).multiply(new BigDecimal("100"));
//        }
//        List<CheckIndexVideo> videoList = new LambdaQueryChainWrapper<>(checkIndexVideoService.getBaseMapper())
//                .select(CheckIndexVideo::getArchivesRate)
//                .eq(params.getDataType().equals(1), CheckIndexVideo::getExamineTag, CheckConstants.Examine_Tag_Province)
@@ -1981,12 +1986,121 @@
//            BigDecimal count = BigDecimal.valueOf(videoList.size());
//            onlineRate = sum.divide(count, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
//        }
        rList.add(this.remove0(onlineRate));
//        rList.add(this.remove0(onlineRate));
        HashMap<String, Object> map = new HashMap<>();
        map.put("count", rList);
        map.put("count", rlist);
        map.put("list", resultVOS);
        return Result.ok().data(map).total(total);
    }
    private List<String> buildVideoAssessmentFileRatioCount(DataCenterQuery params) {
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("uy_monitor_qualify");
        // 1. 构建基础过滤条件(依赖setTag,自动处理标签+时间)
        List<Document> baseFilterList = new ArrayList<>();
        setTag(params, baseFilterList);
        // 2. 总数统计(无时间限制)
        List<Document> totalFilterList = new ArrayList<>(baseFilterList);
        totalFilterList.removeIf(doc -> doc.containsKey(TIME_FIELD));
        int totalCount = 0;
        if (totalFilterList.isEmpty()) {
            // 全量统计:用distinct迭代计数(兼容所有驱动)
            totalCount = countDistinctUniqueDevices(collection);
        } else {
            // 条件统计:聚合管道(无AggregateOptions)
            Document totalMatch = buildSafeMatchCondition(totalFilterList, "total");
            totalCount = countUniqueDevices(collection, totalMatch);
        }
        // 3. 当日数统计(条件统计)
        Document currentDayMatch = buildSafeMatchCondition(baseFilterList, "currentDay");
        int currentDayCount = countUniqueDevices(collection, currentDayMatch);
        // 4. 计算在线率
        BigDecimal onlineRate = BigDecimal.ZERO;
        if (totalCount != 0) {
            onlineRate = new BigDecimal(currentDayCount)
                    .divide(new BigDecimal(totalCount), 3, RoundingMode.DOWN)
                    .multiply(new BigDecimal("100"));
        }
        List<String> rList = new ArrayList<>();
        rList.add(String.valueOf(totalCount));
        rList.add(String.valueOf(currentDayCount));
        rList.add(this.remove0(onlineRate));
        return rList;
    }
    private int countDistinctUniqueDevices(MongoCollection<Document> collection) {
        long start = System.currentTimeMillis();
        try {
            // 去重获取设备ID(指定类型为String)
            DistinctIterable<String> deviceIds = collection.distinct(
                    "serialNumber.showValue",
                    String.class
            );
            // 手动迭代计数(兼容所有驱动版本)
            long count = 0;
            for (String ignored : deviceIds) {
                count++;
            }
            log.info("全量唯一设备数统计耗时:{}ms,总数:{}", System.currentTimeMillis() - start, count);
            return (int) count;
        } catch (Exception e) {
            log.error("全量统计失败", e);
            return 0;
        }
    }
    /**
     * 带条件统计:无 AggregateOptions,仅基础聚合管道
     */
    private int countUniqueDevices(MongoCollection<Document> collection, Document match) {
        long start = System.currentTimeMillis();
        List<Document> pipeline = Arrays.asList(
                match, // $match 条件(确保包含索引字段,引导索引命中)
                new Document("$sort", new Document("serialNumber.showValue", 1)), // 利用索引排序
                new Document("$group", new Document("_id", "$serialNumber.showValue")), // 去重
                new Document("$count", "uniqueDeviceIds") // 统计数量
        );
        try {
            // 直接执行聚合,不使用 AggregateOptions
            AggregateIterable<Document> result = collection.aggregate(pipeline);
            Document doc = result.first();
            int count = doc != null ? doc.getInteger("uniqueDeviceIds", 0) : 0;
            log.info("带条件统计耗时:{}ms,结果:{}", System.currentTimeMillis() - start, count);
            return count;
        } catch (Exception e) {
            log.error("带条件统计失败,match:{}", match, e);
            return 0;
        }
    }
    /**
     * 安全构建$match条件:彻底避免$and空数组错误
     */
    private Document buildSafeMatchCondition(List<Document> filterList, String name) {
        // 过滤null+去重,确保条件合法
        List<Document> validConditions = filterList.stream()
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        log.info("{}统计有效条件:{}", name, validConditions);
        if (validConditions.isEmpty()) {
            return new Document("$match", new Document()); // 空条件→匹配所有
        } else if (validConditions.size() == 1) {
            return new Document("$match", validConditions.get(0)); // 单条件→无需$and
        } else {
            return new Document("$match", new Document("$and", validConditions)); // 多条件→$and包裹
        }
    }
    private final ISysConfigService configService;
@@ -2492,6 +2606,7 @@
     */
    @Override
    public Result videoImportantPointLabelingAccuracy(DataCenterQuery params) {
        long startTime = System.currentTimeMillis();
        List<String> likeFileds = Arrays.asList("deviceNo", "osdName");
        SysDept sysDept = getSysDeptByLoginUser();
        List<Criteria> andCriteria;
@@ -2507,147 +2622,248 @@
            andCriteria = MongoUtil.getAndCriteria(params, "checkTime", likeFileds, null);
        }
        Query query = new Query();
        Criteria and = new Criteria();
        and.andOperator(andCriteria);
        query = Query.query(and);
        query.addCriteria(Criteria.where("importantTag").is(Boolean.TRUE));
        List<Criteria> allCriteria  = new ArrayList<>(andCriteria);
        allCriteria.add(Criteria.where("importantTag").is(Boolean.TRUE)); // 基础标签条件
        // 下拉框标注正确查询条件
        if (params.getOption() != null) {
            if (params.getOption() == 1) {
                andCriteria.add(Criteria.where("osdNameCorrect").is(1));
                andCriteria.add(Criteria.where("osdTimeCorrect").is(1));
                andCriteria.add(Criteria.where("osdProvinceCorrect").is(1));
                andCriteria.add(Criteria.where("osdCityCorrect").is(1));
                andCriteria.add(Criteria.where("osdPartCorrect").is(1));
                Criteria and2 = new Criteria();
                and2.andOperator(andCriteria);
                query = Query.query(and2);
                // 叠加:所有字段必须为1(正确)
                allCriteria.add(new Criteria().andOperator(
                        Criteria.where("osdNameCorrect").is(1),
                        Criteria.where("osdTimeCorrect").is(1),
                        Criteria.where("osdProvinceCorrect").is(1),
                        Criteria.where("osdCityCorrect").is(1),
                        Criteria.where("osdPartCorrect").is(1)
                ));
            } else if (params.getOption() == -1) {
                // 使用$or条件连接多个字段检查,每个字段检查是否等于-1
                Criteria c1 = Criteria.where("osdNameCorrect").is(-1);
                Criteria c2 = Criteria.where("osdTimeCorrect").is(-1);
                Criteria c3 = Criteria.where("osdProvinceCorrect").is(-1);
                Criteria c4 = Criteria.where("osdCityCorrect").is(-1);
                Criteria c5 = Criteria.where("osdPartCorrect").is(-1);
                Criteria orOperator = new Criteria().orOperator(c1, c2, c3, c4, c5);
                orOperator.andOperator(andCriteria);
                query = Query.query(orOperator);
                // 叠加:任一字段为-1(异常)
                allCriteria.add(new Criteria().orOperator(
                        Criteria.where("osdNameCorrect").is(-1),
                        Criteria.where("osdTimeCorrect").is(-1),
                        Criteria.where("osdProvinceCorrect").is(-1),
                        Criteria.where("osdCityCorrect").is(-1),
                        Criteria.where("osdPartCorrect").is(-1)
                ));
            } else {
                Criteria c1 = Criteria.where("osdNameCorrect").is(0);
                Criteria c2 = Criteria.where("osdTimeCorrect").is(0);
                Criteria c3 = Criteria.where("osdProvinceCorrect").is(0);
                Criteria c4 = Criteria.where("osdCityCorrect").is(0);
                Criteria c5 = Criteria.where("osdPartCorrect").is(0);
                Criteria orOperator = new Criteria().orOperator(c1, c2, c3, c4, c5);
                orOperator.andOperator(andCriteria);
                query = Query.query(orOperator);
                // 叠加:任一字段为0(未知)
                allCriteria.add(new Criteria().orOperator(
                        Criteria.where("osdNameCorrect").is(0),
                        Criteria.where("osdTimeCorrect").is(0),
                        Criteria.where("osdProvinceCorrect").is(0),
                        Criteria.where("osdCityCorrect").is(0),
                        Criteria.where("osdPartCorrect").is(0)
                ));
            }
        }
        Criteria finalCriteria = new Criteria().andOperator(allCriteria);
        Query query = Query.query(finalCriteria);
        long total = mongoTemplate.count(query, OsdCheckResult.class);
        MongoUtil.setPage(query, params, "checkTime");
        List<OsdCheckResult> resultList = mongoTemplate.find(query, OsdCheckResult.class);
        log.info("分页查询条件:importantTag=true, option={}, startTime={}, endTime={}",
                params.getOption(), params.getStartTime(), params.getEndTime());
        for (OsdCheckResult osdCheckResult : resultList) {
            OsdCheckResult.getError(osdCheckResult);
        }
        // 统计数量
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("osd_check_result");
        // 确保在统计查询中也应用相同的过滤条件
        Document areDocument = null;
        if (areaDeptEnum != null) {
            String areaCodePrefix = areaDeptEnum.getCode();
            areDocument = new Document("deviceNo", new Document("$regex", "^" + areaCodePrefix));
        }
        // 总数
        List<Document> dList = new ArrayList<>(2);
        if (areDocument != null){
            dList.add(areDocument);
        }
        dList.add(new Document("importantTag", Boolean.TRUE));
        setTag(params, dList);
        long endTime = System.currentTimeMillis();
        log.info("查询分页所用时间:{}ms",endTime -startTime);
        Document osdFilter = new Document("$and", dList);
        // 正常数
        List<Document> dList1 = new ArrayList<>(2);
        if (areDocument != null){
            dList1.add(areDocument);
        }
        dList1.add(new Document("importantTag", Boolean.TRUE));
        dList1.add(new Document("osdNameCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdTimeCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdProvinceCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdCityCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdPartCorrect", new Document("$eq", 1)));
        setTag(params, dList1);
        Document osdCorrectFilter = new Document("$and", dList1);
        //异常数
        List<Document> dList2 = new ArrayList<>(2);
        if (areDocument != null){
            dList2.add(areDocument);
        }
        setTag(params, dList2);
        Document importantTagCondition = new Document("importantTag", Boolean.TRUE);
        dList2.add(importantTagCondition);
        List<Document> errorConditions = new ArrayList<>();
        errorConditions.add(new Document("osdNameCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdTimeCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdProvinceCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdCityCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdPartCorrect", new Document("$eq", -1)));
        Document errorFilter = new Document("$or", errorConditions);
        dList2.add(errorFilter);
        Document osdErrorFilter = new Document("$and", dList2);
        // 未知数
        List<Document> dList3 = new ArrayList<>(2);
        if (areDocument != null){
            dList3.add(areDocument);
        }
        setTag(params, dList3);
        dList3.add(importantTagCondition);
        List<Document> unknownConditions = new ArrayList<>();
        unknownConditions.add(new Document("osdNameCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdTimeCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdProvinceCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdCityCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdPartCorrect", new Document("$eq", 0)));
        Document unknownFilter = new Document("$or", unknownConditions);
        dList3.add(unknownFilter);
        Document osdUnknownFilter = new Document("$and", dList3);
        List<Document> lists = Arrays.asList(osdFilter, osdCorrectFilter, osdErrorFilter, osdUnknownFilter);
        List<String> rList = lists.stream().map(filter -> {
            // 构建聚合管道
            List<Document> pipeline = Arrays.asList(
                    new Document("$match", filter),
                    // $group 去重
                    new Document("$group", new Document("_id", "$deviceNo")),
                    new Document("$count", "uniqueDeviceIds")
            );
            // 执行聚合查询并获取结果
            AggregateIterable<Document> result = collection.aggregate(pipeline);
            Integer uniqueDeviceIdCount = 0;
            for (Document doc : result) {
                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
                break; // 不需要继续遍历,因为 $count 只会产生一个结果
            }
            return uniqueDeviceIdCount + "";
        }).collect(Collectors.toList());
        BigDecimal onlineRate = BigDecimal.ZERO;
        if (!StringUtils.isEmpty(rList.get(0)) && !"0".equals(rList.get(0))) {
            onlineRate = new BigDecimal(rList.get(1)).divide(new BigDecimal(rList.get(0)), 3,RoundingMode.DOWN).multiply(new BigDecimal("100"));
        }
        rList.add(this.remove0(onlineRate));
//        // 统计数量
//        MongoDatabase database = mongoTemplate.getDb();
//        MongoCollection<Document> collection = database.getCollection("osd_check_result");
//        // 确保在统计查询中也应用相同的过滤条件
//        Document areDocument = null;
//        if (areaDeptEnum != null) {
//            String areaCodePrefix = areaDeptEnum.getCode();
//            areDocument = new Document("deviceNo", new Document("$regex", "^" + areaCodePrefix));
//        }
//        // 总数
//        List<Document> dList = new ArrayList<>(2);
//        if (areDocument != null){
//            dList.add(areDocument);
//        }
//        dList.add(new Document("importantTag", Boolean.TRUE));
//        setTag(params, dList);
//
//        Document osdFilter = new Document("$and", dList);
//        // 正常数
//        List<Document> dList1 = new ArrayList<>(2);
//        if (areDocument != null){
//            dList1.add(areDocument);
//        }
//        dList1.add(new Document("importantTag", Boolean.TRUE));
//        dList1.add(new Document("osdNameCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdTimeCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdProvinceCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdCityCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdPartCorrect", new Document("$eq", 1)));
//        setTag(params, dList1);
//
//        Document osdCorrectFilter = new Document("$and", dList1);
//        //异常数
//        List<Document> dList2 = new ArrayList<>(2);
//        if (areDocument != null){
//            dList2.add(areDocument);
//        }
//        setTag(params, dList2);
//        Document importantTagCondition = new Document("importantTag", Boolean.TRUE);
//        dList2.add(importantTagCondition);
//        List<Document> errorConditions = new ArrayList<>();
//        errorConditions.add(new Document("osdNameCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdTimeCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdProvinceCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdCityCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdPartCorrect", new Document("$eq", -1)));
//        Document errorFilter = new Document("$or", errorConditions);
//        dList2.add(errorFilter);
//
//        Document osdErrorFilter = new Document("$and", dList2);
//
//        // 未知数
//        List<Document> dList3 = new ArrayList<>(2);
//        if (areDocument != null){
//            dList3.add(areDocument);
//        }
//        setTag(params, dList3);
//        dList3.add(importantTagCondition);
//        List<Document> unknownConditions = new ArrayList<>();
//        unknownConditions.add(new Document("osdNameCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdTimeCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdProvinceCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdCityCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdPartCorrect", new Document("$eq", 0)));
//        Document unknownFilter = new Document("$or", unknownConditions);
//        dList3.add(unknownFilter);
//
//        Document osdUnknownFilter = new Document("$and", dList3);
//        //todo 修改查询逻辑不走循环 连接三次 走一次查询
//        List<Document> lists = Arrays.asList(osdFilter, osdCorrectFilter, osdErrorFilter, osdUnknownFilter);
//        List<String> rList = lists.stream().map(filter -> {
//            // 构建聚合管道
//            List<Document> pipeline = Arrays.asList(
//                    new Document("$match", filter),
//                    // $group 去重
//                    new Document("$group", new Document("_id", "$deviceNo")),
//                    new Document("$count", "uniqueDeviceIds")
//            );
//            // 执行聚合查询并获取结果
//            AggregateIterable<Document> result = collection.aggregate(pipeline);
//            Integer uniqueDeviceIdCount = 0;
//            for (Document doc : result) {
//                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
//                break; // 不需要继续遍历,因为 $count 只会产生一个结果
//            }
//            return uniqueDeviceIdCount + "";
//        }).collect(Collectors.toList());
//
//        BigDecimal onlineRate = BigDecimal.ZERO;
//        if (!StringUtils.isEmpty(rList.get(0)) && !"0".equals(rList.get(0))) {
//            onlineRate = new BigDecimal(rList.get(1)).divide(new BigDecimal(rList.get(0)), 3,RoundingMode.DOWN).multiply(new BigDecimal("100"));
//        }
//        rList.add(this.remove0(onlineRate));
        List<String> countList = this.buildPointLabelingAccuracyCount(areaDeptEnum,params,likeFileds);
        HashMap<String, Object> map = new HashMap<>();
        map.put("count", rList);
        map.put("count", countList);
        map.put("list", resultList);
        return Result.ok().data(map).total(total);
    }
    private List<String> buildPointLabelingAccuracyCount(AreaDeptEnum areaDeptEnum,DataCenterQuery params,List<String> likeFileds){
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("osd_check_result");
        List<Document> baseFilterList = new ArrayList<>();
        baseFilterList.add(new Document("importantTag",new Document("$eq", Boolean.TRUE)));
        if (areaDeptEnum != null){
            baseFilterList.add(new Document("deviceNo",new Document("$regex","^" + areaDeptEnum.getCode())));
        }
        setTag(params, baseFilterList,"checkTime");
        Document matchStage = new Document("$match",new Document("$and",baseFilterList));
        List<Document> pipeline = new ArrayList<>();
        pipeline.add(matchStage);
        Document groupByDeviceStage = new Document("$group",
                new Document("_id","$deviceNo")
                        .append("correctFlag",new Document("$sum",
                                new Document("$cond",Arrays.asList(
                                        new Document("$and",Arrays.asList(
                                        new Document("$eq",Arrays.asList("$osdNameCorrect",1)),
                                        new Document("$eq", Arrays.asList("$osdTimeCorrect", 1)),
                                        new Document("$eq", Arrays.asList("$osdProvinceCorrect", 1)),
                                        new Document("$eq", Arrays.asList("$osdCityCorrect", 1)),
                                        new Document("$eq", Arrays.asList("$osdPartCorrect", 1))
                                )),
                                1,0
                        ))
        ))
                        // 标记:是否任一字段为-1(异常)
                        .append("errorFlag", new Document("$sum",
                                new Document("$cond", Arrays.asList(
                                        new Document("$or", Arrays.asList(
                                                new Document("$eq", Arrays.asList("$osdNameCorrect", -1)),
                                                new Document("$eq", Arrays.asList("$osdTimeCorrect", -1)),
                                                new Document("$eq", Arrays.asList("$osdProvinceCorrect", -1)),
                                                new Document("$eq", Arrays.asList("$osdCityCorrect", -1)),
                                                new Document("$eq", Arrays.asList("$osdPartCorrect", -1))
                                        )),
                                        1, 0
                                ))
                        ))
                        // 标记:是否任一字段为0(未知)
                        .append("unknownFlag", new Document("$sum",
                                new Document("$cond", Arrays.asList(
                                        new Document("$or", Arrays.asList(
                                                new Document("$eq", Arrays.asList("$osdNameCorrect", 0)),
                                                new Document("$eq", Arrays.asList("$osdTimeCorrect", 0)),
                                                new Document("$eq", Arrays.asList("$osdProvinceCorrect", 0)),
                                                new Document("$eq", Arrays.asList("$osdCityCorrect", 0)),
                                                new Document("$eq", Arrays.asList("$osdPartCorrect", 0))
                                        )),
                                        1, 0
                                ))
                        ))
        );
        pipeline.add(groupByDeviceStage);
        Document groupGlobalStage = new Document("$group",
                new Document("_id", null)
                        .append("totalCount", new Document("$sum", 1)) // 核心修改:直接累加设备分组数
                        .append("correctCount", new Document("$sum", "$correctFlag"))
                        .append("errorCount", new Document("$sum", "$errorFlag"))
                        .append("unknownCount", new Document("$sum", "$unknownFlag"))
        );
        pipeline.add(groupGlobalStage);
        // 执行聚合查询
        AggregateIterable<Document> aggregateResult = collection.aggregate(pipeline);
        Document statDoc = null;
        for (Document doc : aggregateResult) {
            statDoc = doc;
            break;
        }
        // 解析结果(默认值0避免空指针)
        int totalCount = 0, correctCount = 0, errorCount = 0, unknownCount = 0;
        if (statDoc != null) {
            totalCount = statDoc.getInteger("totalCount", 0);
            correctCount = statDoc.getInteger("correctCount", 0);
            errorCount = statDoc.getInteger("errorCount", 0);
            unknownCount = statDoc.getInteger("unknownCount", 0);
        }
        BigDecimal accuracyRate = BigDecimal.ZERO;
        if (totalCount != 0) {
            accuracyRate = new BigDecimal(correctCount)
                    .divide(new BigDecimal(totalCount), 3, RoundingMode.DOWN)
                    .multiply(new BigDecimal("100"));
        }
        // 按原格式返回统计结果(total, correct, error, unknown, rate)
        List<String> countList = new ArrayList<>();
        countList.add(String.valueOf(totalCount));
        countList.add(String.valueOf(correctCount));
        countList.add(String.valueOf(errorCount));
        countList.add(String.valueOf(unknownCount));
        countList.add(this.remove0(accuracyRate));
        return countList;
    }
    @Override
    public void videoImportantPointLabelingAccuracyExport(HttpServletResponse response, DataCenterQuery params) {
@@ -2777,116 +2993,225 @@
        long total = mongoTemplate.count(query, OsdCheckResult.class);
        MongoUtil.setPage(query, params, "checkTime");
        List<OsdCheckResult> resultList = mongoTemplate.find(query, OsdCheckResult.class);
        Document areDocument = null;
        if (areaDeptEnum != null) {
            String areaCodePrefix = areaDeptEnum.getCode();
            areDocument = new Document("deviceNo", new Document("$regex", "^" + areaCodePrefix));
        }
//        Document areDocument = null;
//        if (areaDeptEnum != null) {
//            String areaCodePrefix = areaDeptEnum.getCode();
//            areDocument = new Document("deviceNo", new Document("$regex", "^" + areaCodePrefix));
//        }
        for (OsdCheckResult osdCheckResult : resultList) {
            OsdCheckResult.getError(osdCheckResult);
        }
        // 统计数量
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("osd_check_result");
        //总数
        List<Document> dList = new ArrayList<>(3);
        if (areDocument != null){
            dList.add(areDocument);
        }
        dList.add(new Document("importantTag", Boolean.TRUE));
        setTag(params, dList);
        Document osdFilter = new Document("$and", dList);
        //正常数
        List<Document> dList1 = new ArrayList<>(2);
        dList1.add(new Document("importantTag", Boolean.TRUE));
        dList1.add(new Document("osdNameCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdTimeCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdProvinceCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdCityCorrect", new Document("$eq", 1)));
        dList1.add(new Document("osdPartCorrect", new Document("$eq", 1)));
        if (areDocument != null){
            dList1.add(areDocument);
        }
        setTag(params, dList1);
        Document osdCorrectFilter = new Document("$and", dList1);
        //异常数
        List<Document> dList2 = new ArrayList<>(2);
        if (areDocument != null){
            dList2.add(areDocument);
        }
        setTag(params, dList2);
        Document importantTagCondition = new Document("importantTag", Boolean.TRUE);
        dList2.add(importantTagCondition);
        List<Document> errorConditions = new ArrayList<>();
        errorConditions.add(new Document("osdNameCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdTimeCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdProvinceCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdCityCorrect", new Document("$eq", -1)));
        errorConditions.add(new Document("osdPartCorrect", new Document("$eq", -1)));
        Document errorFilter = new Document("$or", errorConditions);
        dList2.add(errorFilter);
        Document osdErrorFilter = new Document("$and", dList2);
        //未知数
        List<Document> dList3 = new ArrayList<>(2);
        if (areDocument != null){
            dList3.add(areDocument);
        }
        setTag(params, dList3);
        dList3.add(importantTagCondition);
        List<Document> unknownConditions = new ArrayList<>();
        unknownConditions.add(new Document("osdNameCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdTimeCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdProvinceCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdCityCorrect", new Document("$eq", 0)));
        unknownConditions.add(new Document("osdPartCorrect", new Document("$eq", 0)));
        // 使用$or逻辑组合剩余的条件
        Document unknownFilter = new Document("$or", unknownConditions);
        dList3.add(unknownFilter);
        Document osdUnknownFilter = new Document("$and", dList3);
        List<Document> lists = Arrays.asList(osdFilter, osdCorrectFilter, osdErrorFilter, osdUnknownFilter);
        List<String> rList = lists.stream().map(filter -> {
            // 构建聚合管道
            List<Document> pipeline = Arrays.asList(
                    new Document("$match", filter),
                    // $group 去重
                    new Document("$group", new Document("_id", "$deviceNo")),
                    new Document("$count", "uniqueDeviceIds")
            );
            // 执行聚合查询并获取结果
            AggregateIterable<Document> result = collection.aggregate(pipeline);
            Integer uniqueDeviceIdCount = 0;
            for (Document doc : result) {
                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
                break; // 不需要继续遍历,因为 $count 只会产生一个结果
            }
            return uniqueDeviceIdCount + "";
        }).collect(Collectors.toList());
//        List<CheckIndexVideo> videoList = new LambdaQueryChainWrapper<>(checkIndexVideoService.getBaseMapper())
//                .select(CheckIndexVideo::getKeyTimingAccuracy)
//                .eq(params.getDataType().equals(1), CheckIndexVideo::getExamineTag, CheckConstants.Examine_Tag_Province)
//                .eq(params.getDataType().equals(2), CheckIndexVideo::getExamineTag, CheckConstants.Examine_Tag_Dept)
//                .between(CheckIndexVideo::getCreateTime, DateUtils.getDayStart(params.getStartTime()), DateUtils.getDayEnd(params.getEndTime()))
//                .list();
//        BigDecimal onlineRate = BigDecimal.ZERO;
//        if (CollectionUtils.isNotEmpty(videoList)) {
//            BigDecimal sum = videoList.stream().map(CheckIndexVideo::getKeyTimingAccuracy).reduce(BigDecimal.ZERO, BigDecimal::add);
//            BigDecimal count = BigDecimal.valueOf(videoList.size());
//            onlineRate = sum.divide(count, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
//        // 统计数量
//        MongoDatabase database = mongoTemplate.getDb();
//        MongoCollection<Document> collection = database.getCollection("osd_check_result");
//        //总数
//        List<Document> dList = new ArrayList<>(3);
//        if (areDocument != null){
//            dList.add(areDocument);
//        }
        BigDecimal onlineRate = BigDecimal.ZERO;
        if (!StringUtils.isEmpty(rList.get(0)) && !"0".equals(rList.get(0))) {
            onlineRate = new BigDecimal(rList.get(1)).divide(new BigDecimal(rList.get(0)), 3,RoundingMode.DOWN).multiply(new BigDecimal("100"));
        }
        rList.add(this.remove0(onlineRate));
//        dList.add(new Document("importantTag", Boolean.TRUE));
//        setTag(params, dList);
//        Document osdFilter = new Document("$and", dList);
//        //正常数
//        List<Document> dList1 = new ArrayList<>(2);
//        dList1.add(new Document("importantTag", Boolean.TRUE));
//        dList1.add(new Document("osdNameCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdTimeCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdProvinceCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdCityCorrect", new Document("$eq", 1)));
//        dList1.add(new Document("osdPartCorrect", new Document("$eq", 1)));
//        if (areDocument != null){
//            dList1.add(areDocument);
//        }
//        setTag(params, dList1);
//        Document osdCorrectFilter = new Document("$and", dList1);
//        //异常数
//        List<Document> dList2 = new ArrayList<>(2);
//        if (areDocument != null){
//            dList2.add(areDocument);
//        }
//        setTag(params, dList2);
//        Document importantTagCondition = new Document("importantTag", Boolean.TRUE);
//        dList2.add(importantTagCondition);
//        List<Document> errorConditions = new ArrayList<>();
//        errorConditions.add(new Document("osdNameCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdTimeCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdProvinceCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdCityCorrect", new Document("$eq", -1)));
//        errorConditions.add(new Document("osdPartCorrect", new Document("$eq", -1)));
//        Document errorFilter = new Document("$or", errorConditions);
//        dList2.add(errorFilter);
//        Document osdErrorFilter = new Document("$and", dList2);
//        //未知数
//        List<Document> dList3 = new ArrayList<>(2);
//        if (areDocument != null){
//            dList3.add(areDocument);
//        }
//        setTag(params, dList3);
//        dList3.add(importantTagCondition);
//        List<Document> unknownConditions = new ArrayList<>();
//        unknownConditions.add(new Document("osdNameCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdTimeCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdProvinceCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdCityCorrect", new Document("$eq", 0)));
//        unknownConditions.add(new Document("osdPartCorrect", new Document("$eq", 0)));
//        // 使用$or逻辑组合剩余的条件
//        Document unknownFilter = new Document("$or", unknownConditions);
//        dList3.add(unknownFilter);
//        Document osdUnknownFilter = new Document("$and", dList3);
//
//        List<Document> lists = Arrays.asList(osdFilter, osdCorrectFilter, osdErrorFilter, osdUnknownFilter);
//        List<String> rList = lists.stream().map(filter -> {
//            // 构建聚合管道
//            List<Document> pipeline = Arrays.asList(
//                    new Document("$match", filter),
//                    // $group 去重
//                    new Document("$group", new Document("_id", "$deviceNo")),
//                    new Document("$count", "uniqueDeviceIds")
//            );
//            // 执行聚合查询并获取结果
//            AggregateIterable<Document> result = collection.aggregate(pipeline);
//            Integer uniqueDeviceIdCount = 0;
//            for (Document doc : result) {
//                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
//                break; // 不需要继续遍历,因为 $count 只会产生一个结果
//            }
//            return uniqueDeviceIdCount + "";
//        }).collect(Collectors.toList());
//
////        List<CheckIndexVideo> videoList = new LambdaQueryChainWrapper<>(checkIndexVideoService.getBaseMapper())
////                .select(CheckIndexVideo::getKeyTimingAccuracy)
////                .eq(params.getDataType().equals(1), CheckIndexVideo::getExamineTag, CheckConstants.Examine_Tag_Province)
////                .eq(params.getDataType().equals(2), CheckIndexVideo::getExamineTag, CheckConstants.Examine_Tag_Dept)
////                .between(CheckIndexVideo::getCreateTime, DateUtils.getDayStart(params.getStartTime()), DateUtils.getDayEnd(params.getEndTime()))
////                .list();
////        BigDecimal onlineRate = BigDecimal.ZERO;
////        if (CollectionUtils.isNotEmpty(videoList)) {
////            BigDecimal sum = videoList.stream().map(CheckIndexVideo::getKeyTimingAccuracy).reduce(BigDecimal.ZERO, BigDecimal::add);
////            BigDecimal count = BigDecimal.valueOf(videoList.size());
////            onlineRate = sum.divide(count, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
////        }
//        BigDecimal onlineRate = BigDecimal.ZERO;
//        if (!StringUtils.isEmpty(rList.get(0)) && !"0".equals(rList.get(0))) {
//            onlineRate = new BigDecimal(rList.get(1)).divide(new BigDecimal(rList.get(0)), 3,RoundingMode.DOWN).multiply(new BigDecimal("100"));
//        }
//        rList.add(this.remove0(onlineRate));
        List<String> rList = this.buildTimeAccuracyCount(areaDeptEnum,params,likeFileds);
        HashMap<String, Object> map = new HashMap<>();
        map.put("count", rList);
        map.put("list", resultList);
        return Result.ok().data(map).total(total);
    }
    private List<String> buildTimeAccuracyCount(AreaDeptEnum areaDeptEnum, DataCenterQuery params, List<String> likeFileds) {
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("osd_check_result");
        List<Document> baseFilterList = new ArrayList<>();
        // 基础过滤条件(与列表查询一致)
        baseFilterList.add(new Document("importantTag", new Document("$eq", Boolean.TRUE))); // 重要标签
        if (areaDeptEnum != null) {
            // 设备号前缀匹配(区域过滤)
            baseFilterList.add(new Document("deviceNo", new Document("$regex", "^" + areaDeptEnum.getCode())));
        }
        // 时间过滤:使用 checkTime,与列表查询、索引统一(调用改造后的 setTag)
        this.setTag(params, baseFilterList, "checkTime");
        // 模糊查询(deviceNo、osdName,与列表查询一致)
//        if (StringUtils.hasText(params.getKeyword()) && !CollectionUtils.isEmpty(likeFileds)) {
//            String keyword = Pattern.quote(params.getKeyword());
//            List<Document> likeConditions = new ArrayList<>();
//            for (String field : likeFileds) {
//                likeConditions.add(new Document(field, new Document("$regex", ".*?" + keyword + ".*")));
//            }
//            baseFilterList.add(new Document("$or", likeConditions));
//        }
        // 构建聚合管道
        List<Document> pipeline = new ArrayList<>();
        // 阶段1:基础过滤
        pipeline.add(new Document("$match", new Document("$and", baseFilterList)));
        // 阶段2:按 deviceNo 分组去重,标记时间字段的状态
        pipeline.add(new Document("$group", new Document("_id", "$deviceNo")
                // 标记:所有字段均为1(正确)→ $and 组合5个条件
                .append("timeCorrectFlag", new Document("$sum",
                        new Document("$cond", Arrays.asList(
                                new Document("$and", Arrays.asList( // 条件:5个字段全部为1
                                        new Document("$eq", Arrays.asList("$osdTimeCorrect", 1)),
                                        new Document("$eq", Arrays.asList("$osdNameCorrect", 1)),
                                        new Document("$eq", Arrays.asList("$osdProvinceCorrect", 1)),
                                        new Document("$eq", Arrays.asList("$osdCityCorrect", 1)),
                                        new Document("$eq", Arrays.asList("$osdPartCorrect", 1))
                                )),
                                1, 0
                        ))
                ))
                // 标记:时间错误(osdTimeCorrect=-1)
                .append("timeErrorFlag", new Document("$sum",
                        new Document("$cond", Arrays.asList(
                                new Document("$or", Arrays.asList( // 条件:5个字段任一为-1
                                        new Document("$eq", Arrays.asList("$osdTimeCorrect", -1)),
                                        new Document("$eq", Arrays.asList("$osdNameCorrect", -1)),
                                        new Document("$eq", Arrays.asList("$osdProvinceCorrect", -1)),
                                        new Document("$eq", Arrays.asList("$osdCityCorrect", -1)),
                                        new Document("$eq", Arrays.asList("$osdPartCorrect", -1))
                                )),
                                1, 0
                        ))
                ))
                // 标记:时间未知(osdTimeCorrect=0)
                .append("timeUnknownFlag", new Document("$sum",
                        new Document("$cond", Arrays.asList(
                                new Document("$or", Arrays.asList( // 条件:5个字段任一为0
                                        new Document("$eq", Arrays.asList("$osdTimeCorrect", 0)),
                                        new Document("$eq", Arrays.asList("$osdNameCorrect", 0)),
                                        new Document("$eq", Arrays.asList("$osdProvinceCorrect", 0)),
                                        new Document("$eq", Arrays.asList("$osdCityCorrect", 0)),
                                        new Document("$eq", Arrays.asList("$osdPartCorrect", 0))
                                )),
                                1, 0
                        ))
                ))
        ));
        // 阶段3:全局统计(汇总设备数)
        pipeline.add(new Document("$group", new Document("_id", null)
                .append("totalCount", new Document("$sum", 1)) // 总设备数(去重后)
                .append("correctCount", new Document("$sum", "$timeCorrectFlag")) // 时间正确的设备数
                .append("errorCount", new Document("$sum", "$timeErrorFlag")) // 时间错误的设备数
                .append("unknownCount", new Document("$sum", "$timeUnknownFlag")) // 时间未知的设备数
        ));
        // 执行聚合查询
        AggregateIterable<Document> aggregateResult = collection.aggregate(pipeline);
        Document statDoc = aggregateResult.first(); // 全局分组仅返回一条结果
        // 解析结果(默认0避免空指针)
        int totalCount = 0, correctCount = 0, errorCount = 0, unknownCount = 0;
        if (statDoc != null) {
            totalCount = statDoc.getInteger("totalCount", 0);
            correctCount = statDoc.getInteger("correctCount", 0);
            errorCount = statDoc.getInteger("errorCount", 0);
            unknownCount = statDoc.getInteger("unknownCount", 0);
        }
        // 计算时间准确率(正确数/总数)
        BigDecimal accuracyRate = BigDecimal.ZERO;
        if (totalCount != 0) {
            accuracyRate = new BigDecimal(correctCount)
                    .divide(new BigDecimal(totalCount), 3, RoundingMode.DOWN)
                    .multiply(new BigDecimal("100"));
        }
        // 按格式返回:[总数, 正确数, 错误数, 未知数, 准确率]
        List<String> countList = new ArrayList<>();
        countList.add(String.valueOf(totalCount));
        countList.add(String.valueOf(correctCount));
        countList.add(String.valueOf(errorCount));
        countList.add(String.valueOf(unknownCount));
        countList.add(this.remove0(accuracyRate));
        return countList;
    }
    /**
     * 车辆:视图库对接稳定性
@@ -3263,6 +3588,8 @@
            );
            // 执行聚合查询并获取结果
            AggregateIterable<Document> result = collection.aggregate(pipeline);
//            Document explain = collection.aggregate(pipeline).explain();
//            log.info("打印计划:{}",explain);
            Integer uniqueDeviceIdCount = 0;
            for (Document doc : result) {
                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
@@ -4398,6 +4725,8 @@
            );
            // 执行聚合查询并获取结果
            AggregateIterable<Document> result = collection.aggregate(pipeline);
//            Document explain = collection.aggregate(pipeline).explain();
//            log.info("打印执行计划设备抓拍图片时钟准确性:{}",explain);
            Integer uniqueDeviceIdCount = 0;
            for (Document doc : result) {
                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
@@ -4639,4 +4968,22 @@
        if (params.getEndTime() != null) mongoCreateTimeRange.append("$lt", params.getEndTime());
        dList.add(new Document("mongoCreateTime", mongoCreateTimeRange));
    }
    private void setTag(DataCenterQuery params, List<Document> dList, String timeField) {
        // 数据类型过滤(保持原有逻辑)
        if (params.getDataType() != null) { // 加空判断,避免NPE
            if (params.getDataType().equals(1)) {
                dList.add(new Document("provinceTag", new Document("$eq", Boolean.TRUE)));
            } else if (params.getDataType().equals(2)) {
                dList.add(new Document("deptTag", new Document("$eq", Boolean.TRUE)));
            }
        }
        // 时间过滤:使用传入的时间字段名(不再硬编码mongoCreateTime)
        if (params.getStartTime() != null || params.getEndTime() != null) {
            Document timeRange = new Document();
            if (params.getStartTime() != null) timeRange.append("$gte", params.getStartTime());
            if (params.getEndTime() != null) timeRange.append("$lt", params.getEndTime());
            dList.add(new Document(timeField, timeRange)); // 动态时间字段
        }
    }
}