package com.ycl.platform.service.impl; import annotation.DataScope; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.mongodb.client.AggregateIterable; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.ycl.platform.domain.entity.TMonitor; import com.ycl.platform.domain.excel.*; import com.ycl.platform.domain.form.VideoExportForm; import com.ycl.platform.domain.query.DashboardQuery; import com.ycl.platform.domain.query.DataCenterQuery; import com.ycl.platform.domain.query.HomeQuery; import com.ycl.platform.domain.result.BaseResult; import com.ycl.platform.domain.result.HK.*; import com.ycl.platform.domain.result.SYS.TMonitorResult; import com.ycl.platform.domain.result.UY.MonitorQualifyResult; import com.ycl.platform.domain.result.UY.OsdCheckResult; import com.ycl.platform.domain.result.UY.RecordMetaDSumResult; import com.ycl.platform.domain.vo.DynamicColumnVO; import com.ycl.platform.domain.vo.TMonitorVO; import com.ycl.platform.domain.vo.WorkOrderVO; import com.ycl.platform.domain.vo.home.BaseHomeVO; import com.ycl.platform.domain.vo.home.HomeCarVO; import com.ycl.platform.domain.vo.home.HomeFaceVO; 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.service.ITMonitorService; import com.ycl.system.Result; import com.ycl.system.entity.SysDictData; import com.ycl.system.mapper.SysDictDataMapper; import com.ycl.system.page.PageUtil; import com.ycl.system.service.ISysConfigService; import com.ycl.utils.DateUtils; import com.ycl.utils.StringUtils; import com.ycl.utils.poi.ExcelUtil; import constant.ApiConstants; import enumeration.general.AreaDeptEnum; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.Validate; import org.bson.Document; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import pojo.ExcelExp; import utils.poi.ExcelUtilManySheet; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.*; import java.util.function.Function; import java.util.stream.Collectors; /** * 设备资产Service业务层处理 * * @author ruoyi * @date 2024-03-04 */ @Service @Slf4j public class TMonitorServiceImpl extends ServiceImpl implements ITMonitorService { @Autowired private TMonitorMapper tMonitorMapper; @Autowired private YwPointMapper pointMapper; @Autowired private ISysConfigService configService; @Autowired private MongoTemplate mongoTemplate; @Autowired private WorkOrderMapper workOrderMapper; @Autowired private SysDictDataMapper dictDataMapper; @Autowired private DynamicColumnMapper dynamicColumnMapper; @Autowired private ThreadPoolTaskExecutor threadPoolTaskExecutor; /** * 查询设备资产 * * @param id 设备资产主键 * @return 设备资产 */ @Override public TMonitor selectTMonitorById(Long id) { return tMonitorMapper.selectTMonitorById(id); } /** * 查询设备资产列表 * 异常恢复监控、车辆、人脸、视频通用接口 * * @param tMonitor 设备资产 * @return 设备资产 */ @Override @DataScope(deptAlias = "d", userAlias = "u") public List selectTMonitorList(TMonitorVO tMonitor) { // 异常恢复监控 if (Objects.equals(tMonitor.getRecovery(), 1L)) { String time = configService.selectConfigByKey("abnormal.equipment.continuous.attention.time"); if (StringUtils.isBlank(time)) { throw new RuntimeException("请配置异常设备连续关注时间"); } tMonitor.setTime(time); } List monitors = tMonitorMapper.selectTMonitorList(tMonitor); // 异常恢复监控 if (Objects.equals(tMonitor.getRecovery(), 1L)) { //工单号 List orders = monitors.stream().map(TMonitorVO::getWorkOrderNo).collect(Collectors.toList()); if (CollectionUtils.isEmpty(orders)) { return monitors; } List voList = workOrderMapper.getRecoveryInfo(orders); for (TMonitorVO monitor : monitors) { if (!CollectionUtils.isEmpty(voList)) { for (WorkOrderVO workOrderVO : voList) { if (monitor.getWorkOrderNo() != null && monitor.getWorkOrderNo().equals(workOrderVO.getWorkOrderNo())) { monitor.setUnitContact(workOrderVO.getUnitContact()); monitor.setUnitContactPhone(workOrderVO.getUnitContactPhone()); monitor.setYwPeopleName(workOrderVO.getYwPeopleName()); monitor.setErrorType(workOrderVO.getErrorType()); } } } } return monitors; } //设备编号 List numbers = monitors.stream().map(TMonitorVO::getSerialNumber).collect(Collectors.toList()); Query query = new Query(); Date now = new Date(); query.addCriteria(Criteria.where("no").in(numbers) .and("mongoCreateTime").gte(DateUtils.getDayStart(now)).lt(DateUtils.getDayEnd(now)) ); //一机一档信息 List monitorQualifyResults = mongoTemplate.find(query, MonitorQualifyResult.class); // 视频监控设备 if (Objects.equals(tMonitor.getCameraFunType(), "1")) { //OSD信息 List osdCheckResults = mongoTemplate.find(query, OsdCheckResult.class); //录像可用信息 List videoResults = mongoTemplate.find(query, RecordMetaDSumResult.class); for (TMonitorVO monitor : monitors) { monitor.setMongoCreateTime(now); //一机一档 setOneFile(monitorQualifyResults, monitor); //录像 if (!CollectionUtils.isEmpty(videoResults)) { for (RecordMetaDSumResult videoResult : videoResults) { if (monitor.getSerialNumber().equals(videoResult.getNo())) { monitor.setVideoComplete(videoResult.getRecordStatus()); monitor.setVideoLoseTime(videoResult.getMissDuration()); } } } //OSD if (!CollectionUtils.isEmpty(osdCheckResults)) { for (OsdCheckResult osdCheckResult : osdCheckResults) { if (monitor.getSerialNumber().equals(osdCheckResult.getNo())) { monitor.setOSD(OsdCheckResult.checkOsd(osdCheckResult)); monitor.setOSDTime(OsdCheckResult.checkTime(osdCheckResult)); } } } } } // 车辆监控设备 if (Objects.equals(tMonitor.getCameraFunType(), "2")) { //属性一致率、大图 List sampleResults = mongoTemplate.find(query, VehicleDeviceSamplingResult.class); List picAccessResults = mongoTemplate.find(query, PicAccessResult.class); //抓拍量、时钟、上传 List inspectResults = mongoTemplate.find(query, VehicleDeviceInspectionResult.class); for (TMonitorVO monitor : monitors) { monitor.setMongoCreateTime(now); //一机一档 setOneFile(monitorQualifyResults, monitor); //url if (!CollectionUtils.isEmpty(sampleResults)) { for (PicAccessResult picAccessResult : picAccessResults) { if (monitor.getSerialNumber().equals(picAccessResult.getNo())) { BigDecimal bigDecimal = PicAccessResult.calUrl(picAccessResult); monitor.setUrlPercent(bigDecimal); } } } //属性一致率、大图 if (!CollectionUtils.isEmpty(sampleResults)) { for (VehicleDeviceSamplingResult sampleResult : sampleResults) { if (monitor.getSerialNumber().equals(sampleResult.getNo())) { if (sampleResult.getBigUseful() != null) { monitor.setBigUsefulPercent(sampleResult.getBigUseful().getBigUsefulPercent()); } if (sampleResult.getVehDiff() != null) { monitor.setImportantConPercent(sampleResult.getVehDiff().getImportantConPercent()); monitor.setMajorConPercent(sampleResult.getVehDiff().getMajorConPercent()); } } } } //抓拍量、时钟、上传 if (!CollectionUtils.isEmpty(inspectResults)) { for (VehicleDeviceInspectionResult inspectResult : inspectResults) { if (monitor.getSerialNumber().equals(inspectResult.getNo())) { monitor.setSnapResult(inspectResult.getSnapResult()); monitor.setSnapCount(inspectResult.getDataCount()); if (inspectResult.getSnapClock() != null) monitor.setClockPercent(inspectResult.getSnapClock().getClockPercent()); if (inspectResult.getSnapTimely() != null) monitor.setUploadPercent(inspectResult.getSnapTimely().getTimelyPercent()); } } } } } // 人脸监控设备 if (Objects.equals(tMonitor.getCameraFunType(), "3")) { //人脸合格、大图、url访问异常 List sampleResults = mongoTemplate.find(query, FaceDeviceSamplingResult.class); //抓拍量、时钟、上传 List inspectResults = mongoTemplate.find(query, FaceDeviceInspectionResult.class); for (TMonitorVO monitor : monitors) { monitor.setMongoCreateTime(now); //一机一档 setOneFile(monitorQualifyResults, monitor); //人脸合格、大图 if (!CollectionUtils.isEmpty(sampleResults)) { for (FaceDeviceSamplingResult sampleResult : sampleResults) { if (monitor.getSerialNumber().equals(sampleResult.getNo())) { if (sampleResult.getBigUseful() != null) { monitor.setBigUsefulPercent(sampleResult.getBigUseful().getBigUsefulPercent()); } if (sampleResult.getFaceEligibility() != null) monitor.setFacePercent(sampleResult.getFaceEligibility().getFaceEligPercent()); } } } //抓拍量、时钟、上传、建模失败率 if (!CollectionUtils.isEmpty(inspectResults)) { for (FaceDeviceInspectionResult inspectResult : inspectResults) { if (monitor.getSerialNumber().equals(inspectResult.getNo())) { monitor.setSnapResult(inspectResult.getSnapResult()); monitor.setSnapCount(inspectResult.getDataCount()); if (inspectResult.getSnapClock() != null) monitor.setClockPercent(inspectResult.getSnapClock().getClockPercent()); if (inspectResult.getSnapTimely() != null) monitor.setUploadPercent(inspectResult.getSnapTimely().getTimelyPercent()); if (inspectResult.getSnapValidity() != null) monitor.setFailPercent(inspectResult.getSnapValidity().getFailPercent()); } } } } } return monitors; } /** * 补充一机一档信息 * * @param monitorQualifyResults * @param monitor */ private void setOneFile(List monitorQualifyResults, TMonitorVO monitor) { if (!CollectionUtils.isEmpty(monitorQualifyResults)) { for (MonitorQualifyResult oneFile : monitorQualifyResults) { if (monitor.getSerialNumber().equals(oneFile.getNo())) { monitor.setMonitorQualify(MonitorQualifyResult.correct(oneFile)); monitor.setNewMonitor(oneFile.getNewDevice()); } } } } /** * 新增设备资产 * * @param tMonitor 设备资产 * @return 结果 */ @Override public int insertTMonitor(TMonitor tMonitor) { return tMonitorMapper.insertTMonitor(tMonitor); } /** * 修改设备资产 * * @param tMonitor 设备资产 * @return 结果 */ @Override public int updateTMonitor(TMonitor tMonitor) { return tMonitorMapper.updateTMonitor(tMonitor); } /** * 批量删除设备资产 * * @param ids 需要删除的设备资产主键 * @return 结果 */ @Override public int deleteTMonitorByIds(Long[] ids) { return tMonitorMapper.deleteTMonitorByIds(ids); } /** * 删除设备资产信息 * * @param id 设备资产主键 * @return 结果 */ @Override public int deleteTMonitorById(Long id) { return tMonitorMapper.deleteTMonitorById(id); } @Override @DataScope(deptAlias = "d", userAlias = "u") public Map getVideoCount(TMonitorVO tMonitor) { return tMonitorMapper.getVideoCount(tMonitor); } @Override @DataScope(deptAlias = "d", userAlias = "u") public Map recoveryException(TMonitorVO monitor) { // String time = configService.selectConfigByKey("abnormal.equipment.continuous.attention.time"); // monitor.setTime(time); return tMonitorMapper.recoveryException(monitor); } /** * 查mongo查某个月设备总数 * 查看工单数量查看异常的数 * * @param monitorQuery 查询条件 * @return */ @Override public Map home(HomeQuery monitorQuery) { System.out.println(monitorQuery + "~~~~~~~~~~~~~打印"); Map dataMap = new HashMap<>(); Map monthMap1 = new HashMap<>(); Map monthMap2 = new HashMap<>(); List> home = baseMapper.home(monitorQuery); if (ObjectUtils.isNotEmpty(home)) { //拿到数据库 循环查询 System.out.println(home + "~~~~~~~~~~~~~打印"); for (Map map : home) { //得到map的 months键的值 num1键的值 组装为新对象 monthMap1.put(map.get("months").toString(), map.get("num1")); //得到map的 months键的值 num2键的值 组装为新对象 monthMap2.put(map.get("months").toString(), map.get("num2")); } //home 的下标0的 map的 name键的值 dataMap.put("name", home.get(0).get("name")); dataMap.put("state", monthMap1); dataMap.put("state2", monthMap2); } return dataMap; } @Override public Map>> monitorTotal(DashboardQuery dashboardQuery) { List monitorTotalVOS = baseMapper.monitorTotal(dashboardQuery); /** facilityData: { * video:[ * {value: 4589,title: '设备总数'}, * {value: 4294,title: '设备正常数'}, * {value: 295,title: '设备异常数'} * ]} */ Map>> resultMap = new HashMap<>(); for (MonitorTotalVO vo : monitorTotalVOS) { List> list = new ArrayList(); Map total = new HashMap<>(); total.put("value", vo.getTotalNum()); total.put("title", "设备总数"); Map normal = new HashMap<>(); normal.put("value", vo.getNormalNum()); normal.put("title", "正常数"); Map error = new HashMap<>(); error.put("value", vo.getErrorNum()); error.put("title", "异常数"); list.add(total); list.add(normal); list.add(error); resultMap.put(vo.getType(), list); } return resultMap; } @Override public List monitorRate(DashboardQuery dashboardQuery) { return baseMapper.monitorRate(dashboardQuery); } @Override public Result assetManagement(DataCenterQuery query) { IPage page = PageUtil.getPage(query, TMonitorVO.class); baseMapper.assetManagement(page, query); return Result.ok().data(page.getRecords()).total(page.getTotal()); } /** * 导出总量数据 */ @Override public void exportVideoTotal(HttpServletResponse response, VideoExportForm exportForm) throws IOException { //默认查所有部门 if (CollectionUtils.isEmpty(exportForm.getDeptIds())) { List deptIds = new ArrayList<>(); for (AreaDeptEnum value : AreaDeptEnum.values()) { deptIds.add(value.getDeptId()); } exportForm.setDeptIds(deptIds); } List sheet = new ArrayList<>(); //通过Collections静态方法,把list转为线程安全的list List mysheet = Collections.synchronizedList(sheet); VideoExportForm.convertTags(exportForm); Query query = getQuery(exportForm); //月份每日在线数据 List onlineResult = mongoTemplate.find(query, TMonitorResult.class); // 使用 Collectors.toMap 去重,保留每个 No 的第一个遇到的元素 Map uniqueResultsMap = onlineResult.stream() .collect(Collectors.toMap( TMonitorResult::getNo, // keyMapper,这里假设 getNo() 返回 No 字段 Function.identity(), // valueMapper,直接使用对象本身 (existing, replacement) -> existing // mergeFunction,如果有重复,保留第一个 )); // 将 Map 转换为 List List tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); List deviceIds = tMonitorResults.stream().map(BaseResult::getNo).collect(Collectors.toList()); // 将年月字符串解析为YearMonth对象 YearMonth yearMonth = YearMonth.parse(exportForm.getMonth()); // 获取当月的第一天 LocalDate start = yearMonth.atDay(1); // 获取下个月的第一天(通过加上1个月并设置日为1) YearMonth nextMonth = yearMonth.plusMonths(1); LocalDate end = nextMonth.atDay(1); //获取这个月份的部门数据,录像由于是前一天的所以不用createTime字段 Query videoQuery = new Query(Criteria.where("statTime").gte(start).lt(end)); videoQuery.addCriteria(Criteria.where("no").in(deviceIds)); //月份每日录像数据 List recordResult = mongoTemplate.find(videoQuery, RecordMetaDSumResult.class); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String[] weeks = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"}; // 创建一个Map来存储每天的累加数据 Map totalMap = new ConcurrentHashMap<>(); List> futures = new ArrayList<>(); //一个部门一个sheet for (Integer deptId : exportForm.getDeptIds()) { CompletableFuture future = CompletableFuture.runAsync(() -> { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); //筛选部门数据 Set ids = onlineResult.stream().filter(tMonitorResult -> deptId.equals(tMonitorResult.getDeptId())).map(BaseResult::getNo).collect(Collectors.toSet()); if (CollectionUtils.isEmpty(ids)) return; //筛选部门数据 List onlineList = onlineResult.stream().filter(tMonitorResult -> deptId.equals(tMonitorResult.getDeptId())).collect(Collectors.toList()); Map> onlineMap = onlineList.stream() .collect(Collectors.groupingBy(TMonitorResult::getMongoCreateTime)); List recordList = recordResult.stream().filter(result -> ids.contains(result.getNo())).collect(Collectors.toList()); Map> recordMap = recordList.stream().collect(Collectors.groupingBy(RecordMetaDSumResult::getStatTime)); List videoTotalExps = new ArrayList<>(); for (int i = 0; i < 31; i++) { String date = exportForm.getMonth(); date += "-" + (i < 9 ? "0" + (i + 1) : (i + 1)); //总量 VideoTotalExp totalExp = totalMap.computeIfAbsent(date, k -> new VideoTotalExp()); LocalDate parseTime = LocalDate.parse(date, formatter); try { Date parseDate = simpleDateFormat.parse(date); //获取星期几 String week = weeks[parseTime.getDayOfWeek().getValue() - 1]; VideoTotalExp videoExp = new VideoTotalExp(); videoExp.setDate(date); videoExp.setWeek(week); //设置点位在线总量 List onlines = onlineMap.get(parseTime); if (!CollectionUtils.isEmpty(onlines)) { videoExp.setTotal(onlines.size()); long count = onlines.stream() .filter(item -> ApiConstants.UY_OnlineSite_Online.equals(item.getOnline())) .count(); videoExp.setOnline(Integer.valueOf(count + "")); videoExp.setOffline(videoExp.getTotal() - videoExp.getOnline()); } //设置存储情况 List records = recordMap.get(parseDate); if (!CollectionUtils.isEmpty(records)) { videoExp.setNoStore(Integer.valueOf(records.stream() .filter(record -> ApiConstants.UY_RecordStatus_Abnormal.equals(record.getRecordStatus())) .count() + "")); videoExp.setPartStore(Integer.valueOf(records.stream() .filter(record -> ApiConstants.UY_RecordStatus_Interval.equals(record.getRecordStatus())) .count() + "")); } videoTotalExps.add(videoExp); //累加作为全量表 totalExp.setDate(date); totalExp.setWeek(week); totalExp.setTotal((totalExp.getTotal() == null ? 0 : totalExp.getTotal()) + (videoExp.getTotal() == null ? 0 : videoExp.getTotal())); totalExp.setOnline((totalExp.getOnline() == null ? 0 : totalExp.getOnline()) + (videoExp.getOnline() == null ? 0 : videoExp.getOnline())); totalExp.setOffline((totalExp.getOffline() == null ? 0 : totalExp.getOffline()) + (videoExp.getOffline() == null ? 0 : videoExp.getOffline())); totalExp.setNoStore((totalExp.getNoStore() == null ? 0 : totalExp.getNoStore()) + (videoExp.getNoStore() == null ? 0 : videoExp.getNoStore())); totalExp.setPartStore((totalExp.getPartStore() == null ? 0 : totalExp.getPartStore()) + (videoExp.getPartStore() == null ? 0 : videoExp.getPartStore())); totalMap.put(date, totalExp); } catch (ParseException e) { e.printStackTrace(); } } AreaDeptEnum areaDeptEnum = AreaDeptEnum.fromDept(deptId); ExcelExp excelExp = new ExcelExp(areaDeptEnum == null ? "未知" : areaDeptEnum.getName(), videoTotalExps, VideoTotalExp.class); mysheet.add(excelExp); }, threadPoolTaskExecutor); futures.add(future); } // 等待所有任务完成 CompletableFuture allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); allFutures.join(); // 这将阻塞直到所有任务完成 //添加全量表 List totalExps = new ArrayList<>(totalMap.values()); totalExps = totalExps.stream().sorted(Comparator.comparing(VideoTotalExp::getDate)).collect(Collectors.toList()); ExcelExp excelExp = new ExcelExp("全量", totalExps, VideoTotalExp.class); mysheet.add(excelExp); //导出 ExcelUtilManySheet> util = new ExcelUtilManySheet<>(mysheet); util.exportExcelManySheet(response, mysheet); } /** * 导出每日在线数据 */ @Override public void exportVideoOnline(HttpServletResponse response, VideoExportForm exportForm) throws IOException, NoSuchFieldException, IllegalAccessException { log.error("开始导出数据"); log.error("传入的月份:{}",exportForm.getMonth()); //默认查所有部门 if (CollectionUtils.isEmpty(exportForm.getDeptIds())) { List deptIds = new ArrayList<>(); for (AreaDeptEnum value : AreaDeptEnum.values()) { deptIds.add(value.getDeptId()); } exportForm.setDeptIds(deptIds); } List sheet = new ArrayList<>(); //通过Collections静态方法,把list转为线程安全的list List mysheet = Collections.synchronizedList(sheet); VideoExportForm.convertTags(exportForm); Query query = getQuery(exportForm); //月份每日在线数据 List onlineResult = mongoTemplate.find(query, TMonitorResult.class); log.error("月份在线数据:{}条数",onlineResult.size()); // 使用 Collectors.toMap 去重,保留每个 No 的第一个遇到的元素 Map uniqueResultsMap = onlineResult.stream() .collect(Collectors.toMap( TMonitorResult::getNo, // keyMapper,这里假设 getNo() 返回 No 字段 Function.identity(), // valueMapper,直接使用对象本身 (existing, replacement) -> existing // mergeFunction,如果有重复,保留第一个 )); // 将 Map 转换为 List List tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); log.error("去重后大小:{}",tMonitorResults.size()); //获取动态列数据 List pointIds = tMonitorResults.stream().map(TMonitorResult::getPointId).collect(Collectors.toList()); List dynamics = dynamicColumnMapper.getDynamicsByIds("t_yw_point", pointIds); //补充动态列数据 if (!CollectionUtils.isEmpty(dynamics)) { Map> map = dynamics.stream().collect(Collectors.groupingBy(DynamicColumnVO::getRefId)); for (TMonitorResult tMonitorResult : tMonitorResults) { Integer pointId = tMonitorResult.getPointId(); tMonitorResult.setDynamicColumnList(map.get(pointId)); } } //存放区域 与 设备列表 map key为 区域 Map> map = new HashMap<>(); List>> futures = new ArrayList<>(); for (Integer deptId : exportForm.getDeptIds()) { CompletableFuture> future = CompletableFuture.supplyAsync(() -> { List videoDailyExps = new ArrayList<>(); //筛选部门数据 List monitors = tMonitorResults.stream() .filter(tMonitorResult -> deptId.equals(tMonitorResult.getDeptId())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(monitors)) return videoDailyExps; List ids = monitors.stream() .map(BaseResult::getNo) .collect(Collectors.toList()); //筛选mongo区县数据 List onlines = onlineResult.stream() .filter(result -> ids.contains(result.getNo())) .collect(Collectors.toList()); AreaDeptEnum areaDeptEnum = AreaDeptEnum.fromDept(deptId); for (TMonitorResult result : monitors) { VideoDailyExp videoDailyExp = new VideoDailyExp(); videoDailyExp.setSerialNumber(result.getNo()); videoDailyExp.setDeviceName(result.getName()); videoDailyExp.setType(result.getMonitorType()); videoDailyExp.setArea(areaDeptEnum == null ? "未知" : areaDeptEnum.getName()); StringBuilder tag = new StringBuilder("" + (result.getProvinceTag() ? "省厅、" : "") + (result.getImportantTag() ? "重点点位、" : "") + (result.getImportantCommandImageTag() ? "重点指挥图像、" : "") + (result.getDeptTag() ? "部级、" : "")); //动态列处理加在标签里 if (!CollectionUtils.isEmpty(result.getDynamicColumnList())) { for (DynamicColumnVO dynamicColumnVO : result.getDynamicColumnList()) { tag.append(dynamicColumnVO.getColumnValue()).append("、"); } } // 删除字符串末尾的"、" if (tag.toString().endsWith("、")) { tag = new StringBuilder(tag.substring(0, tag.length() - 1)); } videoDailyExp.setTag(tag.toString()); try { setOnlineDaily(videoDailyExp, result, onlines); } catch (Exception e) { log.error(e.getMessage()); } videoDailyExps.add(videoDailyExp); } ExcelExp excelExp = new ExcelExp( areaDeptEnum == null ? "未知" : areaDeptEnum.getName(), videoDailyExps, VideoDailyExp.class ); mysheet.add(excelExp); return videoDailyExps; }, threadPoolTaskExecutor); futures.add(future); map.put(deptId,future.join()); } // 获取全量数据 List totalExps = futures.stream() .map(CompletableFuture::join) .flatMap(List::stream) .collect(Collectors.toList()); ExcelExp excelExp = new ExcelExp("全量", totalExps, VideoDailyExp.class); mysheet.add(excelExp); long face = totalExps.stream().filter(item -> item.getType().contains("1")).count(); long car = totalExps.stream().filter(item -> item.getType().contains("2")).count(); long video = totalExps.stream().filter(item -> item.getType().contains("3")).count(); log.error("人脸数:{}",face); log.error("car数:{}",car); log.error("video数:{}",video); //添加新的sheet 离线数统计表 List videoTypeOffOnlineExps = new ArrayList<>(); //在线率统计表 List videoOnlineRateExps = new ArrayList<>(); for (Integer deptId : map.keySet()){ List list = map.get(deptId); AreaDeptEnum areaDeptEnum = AreaDeptEnum.fromDept(deptId); // 添加离线表记录 //设备类型 1人脸 2车辆 3视频 //人脸 log.error("传入部门集合大小:{} + 部门id:{}" ,list.size(),deptId); VideoTypeOffOnlineExp faceVideoTypeOffOnlineExp = this.getListOfflineCountInfo(list,"1",areaDeptEnum); //卡口 VideoTypeOffOnlineExp carVideoTypeOffOnlineExp =this.getListOfflineCountInfo(list,"2",areaDeptEnum); //视频 VideoTypeOffOnlineExp videoTypeOffOnlineExp = this.getListOfflineCountInfo(list,"3",areaDeptEnum); VideoOnlineRateExp faceVideoOnlineRateExp = this.getListOnLineCountInfo(list,"1",areaDeptEnum); //卡口 VideoOnlineRateExp carVideoOnlineRateExp =this.getListOnLineCountInfo(list,"2",areaDeptEnum); //视频 VideoOnlineRateExp VideoOnlineRateExp = this.getListOnLineCountInfo(list,"3",areaDeptEnum); //将该区域类三种设备类型的 信息 放入 excel对象内 //放入当前区域的人脸设备相关详细 videoTypeOffOnlineExps.add(faceVideoTypeOffOnlineExp); //放入当前区域的车辆设备相关详细 videoTypeOffOnlineExps.add(carVideoTypeOffOnlineExp); //放入当前区域的视频设备相关详细 videoTypeOffOnlineExps.add(videoTypeOffOnlineExp); videoOnlineRateExps.add(faceVideoOnlineRateExp); videoOnlineRateExps.add(carVideoOnlineRateExp); videoOnlineRateExps.add(VideoOnlineRateExp); } //计算自贡市合计 //插入excel时确保数据出现在最后 List allVideoTypeOffOnlineExps = new ArrayList<>(); //插入excel时确保数据出现在最后 List allVideoOnlineRateExps = new ArrayList<>(); //所有离线数据中,各区设备为人脸的对象 合计装配对象 VideoTypeOffOnlineExp allFaceVideosOffline = new VideoTypeOffOnlineExp(); setAllVideoTypeOffOnlineExpCount(videoTypeOffOnlineExps,allFaceVideosOffline,"人脸"); VideoTypeOffOnlineExp allCarVideosOffline = new VideoTypeOffOnlineExp(); setAllVideoTypeOffOnlineExpCount(videoTypeOffOnlineExps,allCarVideosOffline,"卡口"); VideoTypeOffOnlineExp allVideosOffline = new VideoTypeOffOnlineExp(); setAllVideoTypeOffOnlineExpCount(videoTypeOffOnlineExps,allVideosOffline,"视频"); allVideoTypeOffOnlineExps.add(allFaceVideosOffline); allVideoTypeOffOnlineExps.add(allCarVideosOffline); allVideoTypeOffOnlineExps.add(allVideosOffline); //所有在线数据 合计装配对象 VideoOnlineRateExp allFaceVideosOnline = new VideoOnlineRateExp(); setAllVideoTypeOnlineExpCount(face,videoOnlineRateExps,allFaceVideosOnline,"人脸"); VideoOnlineRateExp allCarVideosOnline = new VideoOnlineRateExp(); setAllVideoTypeOnlineExpCount(car,videoOnlineRateExps,allCarVideosOnline,"卡口"); VideoOnlineRateExp allVideosOnline = new VideoOnlineRateExp(); setAllVideoTypeOnlineExpCount(video,videoOnlineRateExps,allVideosOnline,"视频"); allVideoOnlineRateExps.add(allFaceVideosOnline); allVideoOnlineRateExps.add(allCarVideosOnline); allVideoOnlineRateExps.add(allVideosOnline); videoTypeOffOnlineExps.addAll(allVideoTypeOffOnlineExps); videoOnlineRateExps.addAll(allVideoOnlineRateExps); log.error("打印计算离线的信息:{}" ,videoTypeOffOnlineExps ); log.error("打印在线的信息:{}" ,videoOnlineRateExps ); //添加合计数据 ExcelExp excelTypeOffLineExp = new ExcelExp("离线数统计", videoTypeOffOnlineExps, VideoTypeOffOnlineExp.class); mysheet.add(excelTypeOffLineExp); //添加在线率表 ExcelExp excelOnlineRateExp = new ExcelExp("在线率统计",videoOnlineRateExps, VideoOnlineRateExp.class); mysheet.add(excelOnlineRateExp); ExcelUtilManySheet> util = new ExcelUtilManySheet<>(mysheet); util.exportExcelManySheet(response, mysheet); log.error("导出结束"); } //离线设备数据,合计对象,信息装配 public void setAllVideoTypeOffOnlineExpCount(List videoTypeOffOnlineExps, VideoTypeOffOnlineExp videoTypeOffOnlineExp, String type) throws NoSuchFieldException, IllegalAccessException { List filterExps = videoTypeOffOnlineExps.stream().filter(exp -> type.equals(exp.getType())).collect(Collectors.toList()); long allCount = 0; for (VideoTypeOffOnlineExp obj :filterExps){ //obj 对象代表了该区 筛选了的指定type的设备的对象 //计算总的设备离线总数 long count = Long.parseLong(obj.getOfflineCount()); allCount += count; //计算每日 for (int i =1 ;i <= 31; i++){ String fieldName = "day" + i; Field dayField = obj.getClass().getDeclaredField(fieldName); dayField.setAccessible(true); Object value = dayField.get(obj); //获取字段值 if (value != null) { long newFieldValue = Long.parseLong(value.toString()); //获取需要填充的字段 Field videoTypeOffOnlineExpField = videoTypeOffOnlineExp.getClass().getDeclaredField(fieldName); videoTypeOffOnlineExpField.setAccessible(true); //先获取一次 Object oldValue = videoTypeOffOnlineExpField.get(videoTypeOffOnlineExp); //为null 第一次直接诶赋值 if (oldValue == null){ videoTypeOffOnlineExpField.set(videoTypeOffOnlineExp,newFieldValue + ""); }else { //存在旧值 相加覆盖 videoTypeOffOnlineExpField.set(videoTypeOffOnlineExp, (Long.parseLong(oldValue.toString()) + newFieldValue) + ""); } } } } videoTypeOffOnlineExp.setOfflineCount(String.valueOf(allCount)); videoTypeOffOnlineExp.setArea("自贡市"); videoTypeOffOnlineExp.setType(type + "合计"); } //在线设备数据,合计对象,信息装配 public void setAllVideoTypeOnlineExpCount( long allVideoCount,List videoOnlineRateExps, VideoOnlineRateExp videoOnlineRateExp, String type) throws NoSuchFieldException, IllegalAccessException{ List filterExps = videoOnlineRateExps.stream().filter(item -> type.equals(item.getType())).collect(Collectors.toList()); for (VideoOnlineRateExp obj :filterExps){ for (int i = 1;i <= 31; i++){ String countFileName = "count" +i; Field countField = obj.getClass().getDeclaredField(countFileName); countField.setAccessible(true); long newFieldValue = countField.getLong(obj); Field videoOnlineRateExpField = obj.getClass().getDeclaredField(countFileName); videoOnlineRateExpField.setAccessible(true); Object oldValue = videoOnlineRateExpField.get(videoOnlineRateExp); if (oldValue == null){ videoOnlineRateExpField.setLong(videoOnlineRateExp,newFieldValue); }else { //存在旧值 相加覆盖 videoOnlineRateExpField.setLong(videoOnlineRateExp, Long.parseLong(oldValue.toString()) + newFieldValue); } } } //计算完每日在线设备数 //循环一个月 for (int i = 1;i <= 31 ;i++){ //在线率计算 String countFileName = "count" +i; Field countField = videoOnlineRateExp.getClass().getDeclaredField(countFileName); countField.setAccessible(true); long newFieldValue = countField.getLong(videoOnlineRateExp); String fieldName = "day" + i; //每日在线率 double rate = (double) newFieldValue / allVideoCount; //反射添加到对象属性中 Field field = videoOnlineRateExp.getClass().getDeclaredField(fieldName); //设置每日在线设备设备数 field.setAccessible(true); String rateStr = String.format("%.2f", rate * 100) +"%"; if (!"0.00%".equals(rateStr)){ field.set(videoOnlineRateExp, rateStr); } } videoOnlineRateExp.setArea("自贡市"); videoOnlineRateExp.setType(type + "合计"); } /** * 计算离线设备excel对象信息 * @param videoDailyExps 传入的设备集合信息 * @param type 设备类型 1人脸 2车辆 3视频 * @param areaDeptEnum 区域 * @return */ public VideoTypeOffOnlineExp getListOfflineCountInfo(List videoDailyExps, String type, AreaDeptEnum areaDeptEnum ){ VideoTypeOffOnlineExp videoTypeOffOnlineExp = new VideoTypeOffOnlineExp(); List list = videoDailyExps.stream() .filter(device ->device.getType() != null && device.getType().contains(type)).collect(Collectors.toList()); log.error("筛选完设备类型 :{} 后集合的大小:{}",type,list.size()); //离线数量 try { //设置离线数量 以及每日离线数量 setVideoTypeOffOnlineExpCountAndDays(list,videoTypeOffOnlineExp); } catch (Exception e) { log.error(e.getMessage()); } //设备类型 if ("1".equals(type)){ videoTypeOffOnlineExp.setType("人脸"); }else if ("2".equals(type)){ videoTypeOffOnlineExp.setType("卡口"); } else if ("3".equals(type)){ videoTypeOffOnlineExp.setType("视频"); } //修改区域 videoTypeOffOnlineExp.setArea(areaDeptEnum == null ? "未知" : areaDeptEnum.getName()); return videoTypeOffOnlineExp; } private void setVideoTypeOffOnlineExpCountAndDays(List videoDailyExps,VideoTypeOffOnlineExp videoTypeOffOnlineExp)throws NoSuchFieldException, IllegalAccessException { //循环一个月 //离线总数 long AllOffLineCount = 0; for (VideoDailyExp videoDailyExp : videoDailyExps) { if (videoDailyExp.isAllOfflineByMonth()) { AllOffLineCount++; } } //是合计数据不需要下方数据 for (int i = 1; i <= 31; i++) { //每日离线数 long count = 0; String fieldName = "day" + i; for (VideoDailyExp videoDailyExp : videoDailyExps) { // 构造字段名 Field field = videoDailyExp.getClass().getDeclaredField(fieldName); // 确保字段是私有的可以访问 field.setAccessible(true); // 获取字段值 String value = (String) field.get(videoDailyExp); if ("离线".equals(value)) { count++; } } //反射添加到对象属性中 Field field = videoTypeOffOnlineExp.getClass().getDeclaredField(fieldName); field.setAccessible(true); String rateStr = count + ""; if (!"0".equals(rateStr)) { field.set(videoTypeOffOnlineExp, rateStr); } } // } videoTypeOffOnlineExp.setOfflineCount(String.valueOf(AllOffLineCount)); } /** * 计算在线设备excel对象信息 * @param videoDailyExps 传入的设备集合信息 * @param type 设备类型 1人脸 2车辆 3视频 * @param areaDeptEnum 区域 * @return */ public VideoOnlineRateExp getListOnLineCountInfo(List videoDailyExps, String type, AreaDeptEnum areaDeptEnum ){ VideoOnlineRateExp videoOnlineRateExp = new VideoOnlineRateExp(); List list = videoDailyExps.stream() .filter(device ->device.getType() != null && device.getType().contains(type)).collect(Collectors.toList()); log.error("筛选完设备类型 :{} 后集合的大小:{}",type,list.size()); //离线数量 try { setVideoOnlineRateExpCountAndDays(list,videoOnlineRateExp); } catch (Exception e) { log.error(e.getMessage()); } //设备类型 if ("1".equals(type)) { videoOnlineRateExp.setType("人脸"); } else if ("2".equals(type)) { videoOnlineRateExp.setType("卡口"); } else if ("3".equals(type)) { videoOnlineRateExp.setType("视频"); } //修改区域 videoOnlineRateExp.setArea(areaDeptEnum == null ? "未知" : areaDeptEnum.getName()); return videoOnlineRateExp; } private void setVideoOnlineRateExpCountAndDays(List videoDailyExps,VideoOnlineRateExp videoOnlineRateExp)throws NoSuchFieldException, IllegalAccessException { //循环一个月 for (int i = 1;i <= 31 ;i++){ //在线率计算 long count = 0; 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 ++; } } //每日在线率 double rate = (double) count / videoDailyExps.size(); //反射添加到对象属性中 Field field = videoOnlineRateExp.getClass().getDeclaredField(fieldName); Field countField = videoOnlineRateExp.getClass().getDeclaredField(countName); countField.setAccessible(true); //设置每日在线设备设备数 countField.setLong(videoOnlineRateExp, count); field.setAccessible(true); String rateStr = String.format("%.2f", rate * 100) +"%"; if (!"0.00%".equals(rateStr)){ field.set(videoOnlineRateExp, rateStr); } } } /** * 导出每日录像情况数据 */ @Override public void exportVideoRecord(HttpServletResponse response, VideoExportForm exportForm) throws IOException, NoSuchFieldException, IllegalAccessException { //默认查所有部门 if (CollectionUtils.isEmpty(exportForm.getDeptIds())) { List deptIds = new ArrayList<>(); for (AreaDeptEnum value : AreaDeptEnum.values()) { deptIds.add(value.getDeptId()); } exportForm.setDeptIds(deptIds); } VideoExportForm.convertTags(exportForm); Query query = getQuery(exportForm); //月份每日在线数据 List onlineResult = mongoTemplate.find(query, TMonitorResult.class); // 使用 Collectors.toMap 去重,保留每个 No 的第一个遇到的元素 Map uniqueResultsMap = onlineResult.stream() .collect(Collectors.toMap( TMonitorResult::getNo, // keyMapper,这里假设 getNo() 返回 No 字段 Function.identity(), // valueMapper,直接使用对象本身 (existing, replacement) -> existing // mergeFunction,如果有重复,保留第一个 )); // 将 Map 转换为 List List tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); List deviceIds = tMonitorResults.stream().map(BaseResult::getNo).collect(Collectors.toList()); //获取动态列数据 List pointIds = tMonitorResults.stream().map(TMonitorResult::getPointId).collect(Collectors.toList()); List dynamics = dynamicColumnMapper.getDynamicsByIds("t_yw_point", pointIds); //补充动态列数据 if (!CollectionUtils.isEmpty(dynamics)) { Map> map = dynamics.stream().collect(Collectors.groupingBy(DynamicColumnVO::getRefId)); for (TMonitorResult tMonitorResult : tMonitorResults) { Integer pointId = tMonitorResult.getPointId(); tMonitorResult.setDynamicColumnList(map.get(pointId)); } } // 将年月字符串解析为YearMonth对象 YearMonth yearMonth = YearMonth.parse(exportForm.getMonth()); // 获取当月的第一天 LocalDate start = yearMonth.atDay(1); // 获取下个月的第一天(通过加上1个月并设置日为1) YearMonth nextMonth = yearMonth.plusMonths(1); LocalDate end = nextMonth.atDay(1); //获取这个月份的部门数据,录像由于是前一天的所以不用createTime字段 Query videoQuery = new Query(Criteria.where("statTime").gte(start).lt(end)); videoQuery.addCriteria(Criteria.where("no").in(deviceIds)); //月份每日录像线数据 List recordResult = mongoTemplate.find(videoQuery, RecordMetaDSumResult.class); // 预先按部门ID分组 Map> monitorsByDept = tMonitorResults.stream() .collect(Collectors.groupingBy(TMonitorResult::getDeptId)); // 预先构建映射 Map> recordMap = recordResult.stream() .collect(Collectors.groupingBy(RecordMetaDSumResult::getNo)); List>> futures = new ArrayList<>(); for (Integer deptId : exportForm.getDeptIds()) { CompletableFuture> future = CompletableFuture.supplyAsync(() -> { List videoDailyExps = new ArrayList<>(); // 获取当前部门的数据 List monitors = monitorsByDept.getOrDefault(deptId, Collections.emptyList()); if (CollectionUtils.isEmpty(monitors)) return videoDailyExps; AreaDeptEnum areaDeptEnum = AreaDeptEnum.fromDept(deptId); for (TMonitorResult result : monitors) { VideoDailyExp videoDailyExp = new VideoDailyExp(); videoDailyExp.setSerialNumber(result.getNo()); videoDailyExp.setDeviceName(result.getName()); videoDailyExp.setArea(areaDeptEnum == null ? "未知" : areaDeptEnum.getName()); StringBuilder tag = new StringBuilder("" + (result.getProvinceTag() ? "省厅、" : "") + (result.getImportantTag() ? "重点点位、" : "") + (result.getImportantCommandImageTag() ? "重点指挥图像、" : "") + (result.getDeptTag() ? "部级、" : "")); //动态列处理加在标签里 if (!CollectionUtils.isEmpty(result.getDynamicColumnList())) { List dynamicColumnList = result.getDynamicColumnList(); for (DynamicColumnVO dynamicColumnVO : dynamicColumnList) { tag.append(dynamicColumnVO.getColumnValue()).append("、"); } } // 删除字符串末尾的“、” if (tag.toString().endsWith("、")) { tag = new StringBuilder(tag.substring(0, tag.length() - 1)); } videoDailyExp.setTag(tag.toString()); // 使用Map直接获取记录,避免filter操作 List recordsResult = recordMap.get(result.getNo()); try { if (!CollectionUtils.isEmpty(recordsResult)) setRecordDaily(videoDailyExp, result, recordsResult); } catch (Exception e) { log.error(e.getMessage()); } //区县表 videoDailyExps.add(videoDailyExp); } return videoDailyExps; }, threadPoolTaskExecutor); futures.add(future); } // 等待所有任务完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 每个部门的数据单独保存 List> results = futures.stream() .map(CompletableFuture::join) // 获取每个Future的结果 .collect(Collectors.toList()); List totalExps = new ArrayList<>(); List mysheet = new ArrayList<>(); for (List result : results) { ExcelExp excelExp = new ExcelExp( result.get(0).getArea() == null ? "未知" : result.get(0).getArea(), result, VideoDailyExp.class); mysheet.add(excelExp); totalExps.addAll(result); } ExcelExp excelExp = new ExcelExp("全量", totalExps, VideoDailyExp.class); mysheet.add(excelExp); ExcelUtilManySheet> util = new ExcelUtilManySheet<>(mysheet); util.exportExcelManySheet(response, mysheet); } /** * 导出每日录像缺失时长 */ @Override public void exportVideoLoseTime(HttpServletResponse response, VideoExportForm exportForm) throws NoSuchFieldException, IllegalAccessException, IOException { //默认查所有部门 if (CollectionUtils.isEmpty(exportForm.getDeptIds())) { List deptIds = new ArrayList<>(); for (AreaDeptEnum value : AreaDeptEnum.values()) { deptIds.add(value.getDeptId()); } exportForm.setDeptIds(deptIds); } Query query = getQuery(exportForm); //月份每日在线数据 List onlineResult = mongoTemplate.find(query, TMonitorResult.class); // 使用 Collectors.toMap 去重,保留每个 No 的第一个遇到的元素 Map uniqueResultsMap = onlineResult.stream() .collect(Collectors.toMap( TMonitorResult::getNo, // keyMapper,这里假设 getNo() 返回 No 字段 Function.identity(), // valueMapper,直接使用对象本身 (existing, replacement) -> existing // mergeFunction,如果有重复,保留第一个 )); // 将 Map 转换为 List List tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); //获取动态列数据 List pointIds = tMonitorResults.stream().map(TMonitorResult::getPointId).collect(Collectors.toList()); List dynamics = dynamicColumnMapper.getDynamicsByIds("t_yw_point", pointIds); //补充动态列数据 if (!CollectionUtils.isEmpty(dynamics)) { Map> map = dynamics.stream().collect(Collectors.groupingBy(DynamicColumnVO::getRefId)); for (TMonitorResult tMonitorResult : tMonitorResults) { Integer pointId = tMonitorResult.getPointId(); tMonitorResult.setDynamicColumnList(map.get(pointId)); } } List deviceIds = tMonitorResults.stream().map(BaseResult::getNo).collect(Collectors.toList()); // 将年月字符串解析为YearMonth对象 YearMonth yearMonth = YearMonth.parse(exportForm.getMonth()); // 获取当月的第一天 LocalDate start = yearMonth.atDay(1); // 获取下个月的第一天(通过加上1个月并设置日为1) YearMonth nextMonth = yearMonth.plusMonths(1); LocalDate end = nextMonth.atDay(1); //获取这个月份的部门数据,录像由于是前一天的所以不用createTime字段 Query videoQuery = new Query(Criteria.where("statTime").gte(start).lt(end)); videoQuery.addCriteria(Criteria.where("no").in(deviceIds)); //月份每日录像线数据 List recordResult = mongoTemplate.find(videoQuery, RecordMetaDSumResult.class); // 预先按部门ID分组 Map> monitorsByDept = tMonitorResults.stream() .collect(Collectors.groupingBy(TMonitorResult::getDeptId)); // 预先构建映射 Map> recordMap = recordResult.stream() .collect(Collectors.groupingBy(RecordMetaDSumResult::getNo)); List>> futures = new ArrayList<>(); for (Integer deptId : exportForm.getDeptIds()) { CompletableFuture> future = CompletableFuture.supplyAsync(() -> { List videoDailyExps = new ArrayList<>(); // 获取当前部门的数据 List monitors = monitorsByDept.getOrDefault(deptId, Collections.emptyList()); if (CollectionUtils.isEmpty(monitors)) return videoDailyExps; AreaDeptEnum areaDeptEnum = AreaDeptEnum.fromDept(deptId); for (TMonitorResult result : monitors) { VideoDailyExp videoDailyExp = new VideoDailyExp(); videoDailyExp.setSerialNumber(result.getNo()); videoDailyExp.setDeviceName(result.getName()); videoDailyExp.setArea(areaDeptEnum == null ? "未知" : areaDeptEnum.getName()); StringBuilder tag = new StringBuilder("" + (result.getProvinceTag() ? "省厅、" : "") + (result.getImportantTag() ? "重点点位、" : "") + (result.getImportantCommandImageTag() ? "重点指挥图像、" : "") + (result.getDeptTag() ? "部级、" : "")); //动态列处理加在标签里 if (!CollectionUtils.isEmpty(result.getDynamicColumnList())) { List dynamicColumnList = result.getDynamicColumnList(); for (DynamicColumnVO dynamicColumnVO : dynamicColumnList) { tag.append(dynamicColumnVO.getColumnValue()).append("、"); } } // 删除字符串末尾的“、” if (tag.toString().endsWith("、")) { tag = new StringBuilder(tag.substring(0, tag.length() - 1)); } videoDailyExp.setTag(tag.toString()); // 使用Map直接获取记录,避免filter操作 List recordsResult = recordMap.get(result.getNo()); try { if (!CollectionUtils.isEmpty(recordsResult)) setLoseDaily(videoDailyExp, recordsResult); } catch (Exception e) { log.error(e.getMessage()); } videoDailyExps.add(videoDailyExp); } return videoDailyExps; }, threadPoolTaskExecutor); futures.add(future); } // 等待所有任务完成 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 每个部门的数据单独保存 List> results = futures.stream() .map(CompletableFuture::join) // 获取每个Future的结果 .collect(Collectors.toList()); List totalExps = new ArrayList<>(); List mysheet = new ArrayList<>(); for (List result : results) { ExcelExp excelExp = new ExcelExp( result.get(0).getArea() == null ? "未知" : result.get(0).getArea(), result, VideoDailyExp.class); mysheet.add(excelExp); totalExps.addAll(result); } ExcelExp excelExp = new ExcelExp("全量", totalExps, VideoDailyExp.class); mysheet.add(excelExp); ExcelUtilManySheet> util = new ExcelUtilManySheet<>(mysheet); util.exportExcelManySheet(response, mysheet); } //首页视频报表 @Override public Map videoHome(HomeQuery monitorQuery) throws ParseException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { List results = new ArrayList<>(); String month = monitorQuery.getDate(); if (StringUtils.isEmpty(month)) { //如果为空查本月的数据 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM"); month = simpleDateFormat.format(new Date()); } // 创建一个SimpleDateFormat对象来解析日期字符串 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM"); Date date = sdf.parse(month); // 创建一个Calendar对象并设置时间为解析出的Date Calendar calendar = Calendar.getInstance(); calendar.setTime(date); // 设置Calendar为月份的第一天 calendar.set(Calendar.DAY_OF_MONTH, 1); // 获取月份第一天的Date Date startDate = calendar.getTime(); // 设置Calendar为月份的最后一天(通过增加一个月份然后减去一天) calendar.add(Calendar.MONTH, 1); calendar.add(Calendar.DAY_OF_MONTH, -1); // 获取月份最后一天的Date Date endDate = calendar.getTime(); //mongo查录像状态 MongoDatabase database = mongoTemplate.getDb(); MongoCollection collection = database.getCollection("uy_record_meta_d_sum"); Integer examineTag = monitorQuery.getExamineTag(); Document matchConditions = new Document("statTime", new Document("$gte", startDate).append("$lte", endDate)); // 根据examineTag的值动态添加额外的条件 if (examineTag != null && examineTag.equals(1)) { matchConditions.append("provinceTag", true); } else if (examineTag != null && examineTag.equals(2)) { matchConditions.append("deptTag", true); } // 构建聚合管道 List pipeline = Arrays.asList( new Document("$match", matchConditions), new Document("$group", new Document("_id", "$statTime") .append("normalCount", new Document("$sum", new Document("$cond", Arrays.asList( new Document("$eq", Arrays.asList("$recordStatus", 1)), 1, 0 )) )) .append("loseCount", new Document("$sum", new Document("$cond", Arrays.asList( new Document("$eq", Arrays.asList("$recordStatus", 0)), 1, 0 )) )) .append("errCount", new Document("$sum", new Document("$cond", Arrays.asList( new Document("$eq", Arrays.asList("$recordStatus", -1)), 1, 0 )) )) ) ); // 执行聚合查询并获取结果 AggregateIterable result = collection.aggregate(pipeline); for (Document doc : result) { HomeVideoVO homeVideoVO = new HomeVideoVO(); homeVideoVO.setCreateDate(doc.getDate("_id")); homeVideoVO.setIntegrityNum(doc.getInteger("normalCount")); homeVideoVO.setLoseNum(doc.getInteger("loseCount")); homeVideoVO.setErrNum(doc.getInteger("errCount")); results.add(homeVideoVO); } //mongo查点位在线 MongoCollection onlineCollection = database.getCollection("t_monitor_online"); // 构建基本的$match条件 List 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 (examineTag != null && examineTag.equals(1)) { onlineMatch.add(new Document("provinceTag", true)); } else if (examineTag != null && examineTag.equals(2)) { onlineMatch.add(new Document("deptTag", true)); } // 构建聚合管道 List onlinePipeline = Arrays.asList( new Document("$match", new Document("$and", onlineMatch)), new Document("$group", new Document("_id", "$mongoCreateTime") .append("onlineCount", new Document("$sum", new Document("$cond", Arrays.asList( new Document("$eq", Arrays.asList("$online", ApiConstants.UY_OnlineSite_Online)), 1, 0 )) )) ) ); // 执行聚合查询并获取结果 AggregateIterable onlineResult = onlineCollection.aggregate(onlinePipeline); for (Document doc : onlineResult) { HomeVideoVO vo = findOrCreateVO(doc, results, HomeVideoVO.class); vo.setOnline(doc.getInteger("onlineCount")); } results = results.stream().sorted(Comparator.comparing(BaseHomeVO::getCreateDate)).collect(Collectors.toList()); Map resultMap = new HashMap<>(); resultMap.put("list", results); //从字典获取基准线 List baseLines = dictDataMapper.selectDictDataByType("home_baseLine"); String condition; if (examineTag != null && examineTag == 1) { condition = "video_province_baseLine"; } else if (examineTag != null && examineTag == 2) { condition = "video_dept_baseLine"; } else { condition = "video_all_baseLine"; } Optional first = baseLines.stream().filter(sysDictData -> condition.equals(sysDictData.getDictLabel())).findFirst(); if (first.isPresent()) { SysDictData sysDictData = first.get(); resultMap.put("baseLine", Integer.valueOf(sysDictData.getDictValue())); } return resultMap; } /** * 列表导出 * * @param response * @param tMonitor */ @Override public void export(HttpServletResponse response, TMonitorVO tMonitor) { List monitors = tMonitorMapper.exportTMonitorList(tMonitor); //获取动态列数据 List pointIds = monitors.stream().map(TMonitorExp::getPointId).collect(Collectors.toList()); List dynamics = dynamicColumnMapper.getDynamicsByIds("t_yw_point", pointIds); //补充动态列数据 if (!CollectionUtils.isEmpty(dynamics)) { Map> map = dynamics.stream().collect(Collectors.groupingBy(DynamicColumnVO::getRefId)); for (TMonitorExp tMonitorResult : monitors) { Integer pointId = tMonitorResult.getPointId(); tMonitorResult.setDynamicColumnList(map.get(pointId)); } } monitors.forEach(monitor -> { String cameraFunType = monitor.getCameraFunType(); if (!StringUtils.isEmpty(cameraFunType)) { String video = cameraFunType.replaceAll("1", "视频"); String car = video.replaceAll("2", "车辆"); String type = car.replaceAll("3", "人脸"); monitor.setCameraFunType(type); } StringBuilder tag = new StringBuilder("" + (monitor.getProvinceTagVideo() ? "省厅视频、" : "") + (monitor.getProvinceTagCar() ? "省厅车辆、" : "") + (monitor.getProvinceTagFace() ? "省厅人脸、" : "") + (monitor.getImportantTag() ? "重点点位、" : "") + (monitor.getImportantCommandImageTag() ? "重点指挥图像、" : "") + (monitor.getDeptTag() ? "部级、" : "")); //动态列处理加在标签里 if (!CollectionUtils.isEmpty(monitor.getDynamicColumnList())) { List dynamicColumnList = monitor.getDynamicColumnList(); for (DynamicColumnVO dynamicColumnVO : dynamicColumnList) { tag.append(dynamicColumnVO.getColumnValue()).append("、"); } } // 删除字符串末尾的“、” if (tag.toString().endsWith("、")) { tag = new StringBuilder(tag.substring(0, tag.length() - 1)); } monitor.setTag(tag.toString()); }); ExcelUtil util = new ExcelUtil<>(TMonitorExp.class); String sheetName = ""; if ("1".equals(tMonitor.getCameraFunType())) { sheetName = "视频"; } else if ("2".equals(tMonitor.getCameraFunType())) { sheetName = "车辆"; } else if ("3".equals(tMonitor.getCameraFunType())) { sheetName = "人脸"; } util.exportExcel(response, monitors, sheetName); } /** * 清理一机一档 * @return */ @Override @Transactional(rollbackFor = Exception.class) public Result clearMonitor() { tMonitorMapper.clearMonitor(); pointMapper.clearMonitor(); return Result.ok(); } @Override public Result assetManagementCount(DataCenterQuery query) { Map map =tMonitorMapper.assetManagementCount(); return Result.ok().data(map); } //首页车辆报表 @Override public Map carHome(HomeQuery monitorQuery) throws ParseException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { List results = new ArrayList<>(); String month = monitorQuery.getDate(); if (StringUtils.isEmpty(month)) { //如果为空查本月的数据 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM"); month = simpleDateFormat.format(new Date()); } // 创建一个SimpleDateFormat对象来解析日期字符串 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM"); Date date = sdf.parse(month); // 创建一个Calendar对象并设置时间为解析出的Date Calendar calendar = Calendar.getInstance(); calendar.setTime(date); // 设置Calendar为月份的第一天 calendar.set(Calendar.DAY_OF_MONTH, 1); // 获取月份第一天的Date Date startDate = calendar.getTime(); // 设置Calendar为月份的最后一天(通过增加一个月份然后减去一天) calendar.add(Calendar.MONTH, 1); calendar.add(Calendar.DAY_OF_MONTH, -1); // 获取月份最后一天的Date Date endDate = calendar.getTime(); //mongo查抓拍量 MongoDatabase database = mongoTemplate.getDb(); MongoCollection collection = database.getCollection("hk_snapshot_data_monitor"); Integer examineTag = monitorQuery.getExamineTag(); // 构建基本的$match条件 List matchConditions = new ArrayList<>(); matchConditions.add(new Document("mongoCreateTime", new Document("$gte", startDate).append("$lte", endDate))); matchConditions.add(new Document("dataType", new Document("$eq", ApiConstants.HK_DataType_CAR))); if (examineTag != null && examineTag.equals(1)) { matchConditions.add(new Document("provinceTag", true)); } // 构建聚合管道 List pipeline = Arrays.asList( new Document("$match", new Document("$and", matchConditions)), new Document("$group", new Document("_id", "$mongoCreateTime") .append("dataCount", new Document("$sum", "$dataCount")) ) ); // 执行聚合查询并获取结果 AggregateIterable result = collection.aggregate(pipeline); for (Document doc : result) { HomeCarVO homecarVO = new HomeCarVO(); homecarVO.setCreateDate(doc.getDate("_id")); homecarVO.setSnapCount(doc.getInteger("dataCount")); results.add(homecarVO); } MongoCollection onlineCollection = database.getCollection("t_monitor_online"); // 构建基本的$match条件 List onlineMatch = new ArrayList<>(); onlineMatch.add(new Document("mongoCreateTime", new Document("$gte", startDate).append("$lte", endDate))); onlineMatch.add(new Document("monitorType", new Document("$regex", "2"))); if (examineTag != null && examineTag.equals(1)) { onlineMatch.add(new Document("provinceTag", true)); } // 构建聚合管道 List onlinePipeline = Arrays.asList( new Document("$match", new Document("$and", onlineMatch)), new Document("$group", new Document("_id", "$mongoCreateTime") .append("onlineCount", new Document("$sum", new Document("$cond", Arrays.asList( new Document("$eq", Arrays.asList("$online", ApiConstants.UY_OnlineSite_Online)), 1, 0 )) )) ) ); // 执行聚合查询并获取结果 AggregateIterable onlineResult = onlineCollection.aggregate(onlinePipeline); for (Document doc : onlineResult) { HomeCarVO vo = findOrCreateVO(doc, results, HomeCarVO.class); vo.setOnline(doc.getInteger("onlineCount")); } Map resultMap = new HashMap<>(); //按时间排序 results = results.stream().sorted(Comparator.comparing(BaseHomeVO::getCreateDate)).collect(Collectors.toList()); //如果是默认或累和则进行累和以及获取基准线 if (monitorQuery.getCategory() == null || monitorQuery.getCategory().equals(1)) { int snapCount = 0; for (HomeCarVO vo : results) { if (vo.getSnapCount() != null) { snapCount += vo.getSnapCount(); } vo.setSnapCount(snapCount); } //从字典获取基准线 List baseLines = dictDataMapper.selectDictDataByType("home_baseLine"); String condition; if (examineTag != null && examineTag == 1) { condition = "car_province_baseLine"; } else if (examineTag != null && examineTag == 2) { condition = "car_dept_baseLine"; } else { condition = "car_all_baseLine"; } Optional first = baseLines.stream().filter(sysDictData -> condition.equals(sysDictData.getDictLabel())).findFirst(); if (first.isPresent()) { SysDictData sysDictData = first.get(); resultMap.put("baseLine", Integer.valueOf(sysDictData.getDictValue())); } } resultMap.put("list", results); return resultMap; } //首页人脸报表 @Override public Map faceHome(HomeQuery monitorQuery) throws ParseException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { List results = new ArrayList<>(); String month = monitorQuery.getDate(); if (StringUtils.isEmpty(month)) { //如果为空查本月的数据 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM"); month = simpleDateFormat.format(new Date()); } // 创建一个SimpleDateFormat对象来解析日期字符串 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM"); Date date = sdf.parse(month); // 创建一个Calendar对象并设置时间为解析出的Date Calendar calendar = Calendar.getInstance(); calendar.setTime(date); // 设置Calendar为月份的第一天 calendar.set(Calendar.DAY_OF_MONTH, 1); // 获取月份第一天的Date Date startDate = calendar.getTime(); // 设置Calendar为月份的最后一天(通过增加一个月份然后减去一天) calendar.add(Calendar.MONTH, 1); calendar.add(Calendar.DAY_OF_MONTH, -1); // 获取月份最后一天的Date Date endDate = calendar.getTime(); //mongo查抓拍量 MongoDatabase database = mongoTemplate.getDb(); MongoCollection collection = database.getCollection("hk_snapshot_data_monitor"); Integer examineTag = monitorQuery.getExamineTag(); // 构建基本的$match条件 List matchConditions = new ArrayList<>(); matchConditions.add(new Document("mongoCreateTime", new Document("$gte", startDate).append("$lte", endDate))); matchConditions.add(new Document("dataType", new Document("$eq", ApiConstants.HK_DataType_FACE))); if (examineTag != null && examineTag.equals(1)) { matchConditions.add(new Document("provinceTag", true)); } // 构建聚合管道 List pipeline = Arrays.asList( new Document("$match", new Document("$and", matchConditions)), new Document("$group", new Document("_id", "$mongoCreateTime") .append("dataCount", new Document("$sum", "$dataCount")) ) ); // 执行聚合查询并获取结果 AggregateIterable result = collection.aggregate(pipeline); for (Document doc : result) { HomeFaceVO homefaceVO = new HomeFaceVO(); homefaceVO.setCreateDate(doc.getDate("_id")); homefaceVO.setSnapCount(doc.getInteger("dataCount")); results.add(homefaceVO); } //mongo查点位在线 MongoCollection onlineCollection = database.getCollection("t_monitor_online"); // 构建基本的$match条件 List onlineMatch = new ArrayList<>(); onlineMatch.add(new Document("mongoCreateTime", new Document("$gte", startDate).append("$lte", endDate))); onlineMatch.add(new Document("monitorType", new Document("$regex", "3"))); if (examineTag != null && examineTag.equals(1)) { onlineMatch.add(new Document("provinceTag", true)); } // 构建聚合管道 List onlinePipeline = Arrays.asList( new Document("$match", new Document("$and", onlineMatch)), new Document("$group", new Document("_id", "$mongoCreateTime") .append("onlineCount", new Document("$sum", new Document("$cond", Arrays.asList( new Document("$eq", Arrays.asList("$online", ApiConstants.UY_OnlineSite_Online)), 1, 0 )) )) ) ); // 执行聚合查询并获取结果 AggregateIterable onlineResult = onlineCollection.aggregate(onlinePipeline); for (Document doc : onlineResult) { HomeFaceVO vo = findOrCreateVO(doc, results, HomeFaceVO.class); vo.setOnline(doc.getInteger("onlineCount")); } Map resultMap = new HashMap<>(); //按时间排序 results = results.stream().sorted(Comparator.comparing(BaseHomeVO::getCreateDate)).collect(Collectors.toList()); //如果是默认或累和则进行累和以及获取基准线 if (monitorQuery.getCategory() == null || monitorQuery.getCategory().equals(1)) { int snapCount = 0; for (HomeFaceVO vo : results) { if (vo.getSnapCount() != null) { snapCount += vo.getSnapCount(); } vo.setSnapCount(snapCount); } //从字典获取基准线 List baseLines = dictDataMapper.selectDictDataByType("home_baseLine"); String condition; if (examineTag != null && examineTag == 1) { condition = "face_province_baseLine"; } else if (examineTag != null && examineTag == 2) { condition = "face_dept_baseLine"; } else { condition = "face_all_baseLine"; } Optional first = baseLines.stream().filter(sysDictData -> condition.equals(sysDictData.getDictLabel())).findFirst(); if (first.isPresent()) { SysDictData sysDictData = first.get(); resultMap.put("baseLine", Integer.valueOf(sysDictData.getDictValue())); } } resultMap.put("list", results); return resultMap; } private T findOrCreateVO(Document doc, List results, Class clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Date createDate = doc.getDate("_id"); for (T vo : results) { if (vo.getCreateDate().equals(createDate)) { return vo; } } // 如果没有找到匹配项,则创建一个新的VO T vo = clazz.getDeclaredConstructor().newInstance(); vo.setCreateDate(createDate); results.add(vo); return vo; } private Query getQuery(VideoExportForm exportForm) { String month = exportForm.getMonth(); // 将年月字符串解析为YearMonth对象 YearMonth yearMonth = YearMonth.parse(month); // 获取当月的第一天 LocalDate start = yearMonth.atDay(1); // 获取下个月的第一天(通过加上1个月并设置日为1) YearMonth nextMonth = yearMonth.plusMonths(1); LocalDate end = nextMonth.atDay(1); //获取这个月份的部门数据 Query query = new Query(Criteria.where("mongoCreateTime").gte(start).lt(end)); if (!CollectionUtils.isEmpty(exportForm.getDeptIds())) query.addCriteria(Criteria.where("deptId").in(exportForm.getDeptIds())); if (exportForm.getDeptTag() != null) query.addCriteria(Criteria.where("deptTag").is(exportForm.getDeptTag())); if (exportForm.getProvinceTag() != null) query.addCriteria(Criteria.where("provinceTag").is(exportForm.getProvinceTag())); if (exportForm.getImportantTag() != null) query.addCriteria(Criteria.where("importantTag").is(exportForm.getImportantTag())); if (exportForm.getImportantCommandImageTag() != null) query.addCriteria(Criteria.where("importantCommandImageTag").is(exportForm.getImportantCommandImageTag())); return query; } //设置每日在线数据 private void setOnlineDaily(VideoDailyExp videoDailyExp, TMonitorResult result, List onlines) throws NoSuchFieldException, IllegalAccessException { //一个设备当月在线情况 List onlineResult = onlines.stream().filter(online -> online.getNo().equals(result.getNo())).collect(Collectors.toList()); videoDailyExp.setOnlineStateList(onlineResult); for (TMonitorResult monitorResult : onlineResult) { int dayOfMonth = monitorResult.getMongoCreateTime().getDayOfMonth(); String online = ""; if (ApiConstants.UY_OnlineSite_Online.equals(monitorResult.getOnline())) { online += "在线"; } else if (ApiConstants.UY_OnlineSite_Offline.equals(monitorResult.getOnline())) { online += "离线"; } else { online += "未知"; } //反射赋值,字段统一定义为day+1,2,3... Field field = videoDailyExp.getClass().getDeclaredField("day" + dayOfMonth); field.setAccessible(true); field.set(videoDailyExp, online); } } //设置每日录像数据 private void setRecordDaily(VideoDailyExp videoDailyExp, TMonitorResult result, List recordResults) throws NoSuchFieldException, IllegalAccessException { for (RecordMetaDSumResult recordResult : recordResults) { int dayOfMonth = DateUtils.getDayOfMonth(recordResult.getStatTime()); Integer status = recordResult.getRecordStatus(); String text = ""; if (ApiConstants.UY_RecordStatus_Interval.equals(status)) { text += "间歇"; } else if (ApiConstants.UY_RecordStatus_Abnormal.equals(status)) { text += "缺失"; } else if (ApiConstants.UY_RecordStatus_Integrity.equals(status)) { text += "完整"; } //反射赋值,字段统一定义为day+1,2,3... Field field = videoDailyExp.getClass().getDeclaredField("day" + dayOfMonth); field.setAccessible(true); field.set(videoDailyExp, text); } } //设置每日录像缺失时长数据 private void setLoseDaily(VideoDailyExp videoDailyExp, List recordResults) throws NoSuchFieldException, IllegalAccessException { //一个设备当月在线情况 for (RecordMetaDSumResult recordResult : recordResults) { int dayOfMonth = DateUtils.getDayOfMonth(recordResult.getStatTime()); //获取启动日期是当月第几天 //反射赋值,字段统一定义为day+1,2,3... Field field = videoDailyExp.getClass().getDeclaredField("day" + dayOfMonth); field.setAccessible(true); //防止转换为科学计数法 BigDecimal bigDecimal = BigDecimal.valueOf(recordResult.getMissDuration() == null ? 0 : (recordResult.getMissDuration()) * 60); field.set(videoDailyExp, bigDecimal.setScale(2, RoundingMode.HALF_UP).toString()); } } }