| | |
| | | import annotation.DataScope; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.mongodb.ExplainVerbosity; |
| | | 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.TMonitorExp; |
| | | import com.ycl.platform.domain.excel.VideoDailyExp; |
| | | import com.ycl.platform.domain.excel.VideoTotalExp; |
| | | 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.service.ITMonitorService; |
| | | import com.ycl.system.Result; |
| | | import com.ycl.system.entity.SysDictData; |
| | | import com.ycl.system.mapper.SysConfigMapper; |
| | | import com.ycl.system.mapper.SysDictDataMapper; |
| | | import com.ycl.system.page.PageUtil; |
| | | import com.ycl.system.service.ISysConfigService; |
| | |
| | | import com.ycl.utils.StringUtils; |
| | | import com.ycl.utils.poi.ExcelUtil; |
| | | import constant.ApiConstants; |
| | | import constant.CheckConstants; |
| | | import enumeration.general.AreaDeptEnum; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import lombok.SneakyThrows; |
| | | 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.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.mongodb.core.MongoTemplate; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | |
| | | import java.lang.reflect.InvocationTargetException; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.text.DecimalFormat; |
| | | import java.text.ParseException; |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | | import java.time.YearMonth; |
| | | import java.time.ZoneId; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.temporal.TemporalAdjusters; |
| | | import java.util.*; |
| | | import java.util.concurrent.*; |
| | | import java.util.function.BinaryOperator; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | * @date 2024-03-04 |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | public class TMonitorServiceImpl extends ServiceImpl<TMonitorMapper, TMonitor> implements ITMonitorService { |
| | | @Autowired |
| | | private TMonitorMapper tMonitorMapper; |
| | |
| | | */ |
| | | @Override |
| | | public void exportVideoOnline(HttpServletResponse response, VideoExportForm exportForm) throws IOException, NoSuchFieldException, IllegalAccessException { |
| | | log.error("开始导出数据"); |
| | | log.error("传入的月份:{}",exportForm.getMonth()); |
| | | //默认查所有部门 |
| | | if (CollectionUtils.isEmpty(exportForm.getDeptIds())) { |
| | | List<Integer> deptIds = new ArrayList<>(); |
| | |
| | | Query query = getQuery(exportForm); |
| | | //月份每日在线数据 |
| | | List<TMonitorResult> onlineResult = mongoTemplate.find(query, TMonitorResult.class); |
| | | log.error("月份在线数据:{}条数",onlineResult.size()); |
| | | // 使用 Collectors.toMap 去重,保留每个 No 的第一个遇到的元素 |
| | | Map<String, TMonitorResult> uniqueResultsMap = onlineResult.stream() |
| | | .collect(Collectors.toMap( |
| | |
| | | )); |
| | | // 将 Map 转换为 List |
| | | List<TMonitorResult> tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); |
| | | log.error("去重后大小:{}",tMonitorResults.size()); |
| | | //获取动态列数据 |
| | | List<Integer> pointIds = tMonitorResults.stream().map(TMonitorResult::getPointId).collect(Collectors.toList()); |
| | | List<DynamicColumnVO> dynamics = dynamicColumnMapper.getDynamicsByIds("t_yw_point", pointIds); |
| | |
| | | tMonitorResult.setDynamicColumnList(map.get(pointId)); |
| | | } |
| | | } |
| | | //存放区域 与 设备列表 map key为 区域 |
| | | Map<Integer, List<VideoDailyExp>> map = new HashMap<>(); |
| | | List<CompletableFuture<List<VideoDailyExp>>> futures = new ArrayList<>(); |
| | | for (Integer deptId : exportForm.getDeptIds()) { |
| | | CompletableFuture<List<VideoDailyExp>> future = CompletableFuture.supplyAsync(() -> { |
| | |
| | | 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("" + |
| | |
| | | ); |
| | | mysheet.add(excelExp); |
| | | |
| | | |
| | | return videoDailyExps; |
| | | }, threadPoolTaskExecutor); |
| | | futures.add(future); |
| | | map.put(deptId,future.join()); |
| | | } |
| | | // 获取全量数据 |
| | | List<VideoDailyExp> totalExps = futures.stream() |
| | | .map(CompletableFuture::join) |
| | | .flatMap(List::stream) |
| | | .collect(Collectors.toList()); |
| | | log.error("打印全量数据:{}",totalExps); |
| | | ExcelExp excelExp = new ExcelExp("全量", totalExps, VideoDailyExp.class); |
| | | mysheet.add(excelExp); |
| | | //添加新的sheet 离线数统计表 |
| | | List<VideoTypeOffOnlineExp> videoTypeOffOnlineExps = new ArrayList<>(); |
| | | //插入excel时确保数据出现在最后 |
| | | List<VideoTypeOffOnlineExp> allVideoTypeOffOnlineExps = new ArrayList<>(); |
| | | |
| | | //在线率统计表 |
| | | List<VideoOnlineRateExp> videoOnlineRateExps = new ArrayList<>(); |
| | | //插入excel时确保数据出现在最后 |
| | | List<VideoOnlineRateExp> allVideoOnlineRateExps = new ArrayList<>(); |
| | | |
| | | for (Integer deptId : map.keySet()){ |
| | | List<VideoDailyExp> 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,false); |
| | | //卡口 |
| | | VideoTypeOffOnlineExp carVideoTypeOffOnlineExp =this.getListOfflineCountInfo(list,"2",areaDeptEnum,false); |
| | | //视频 |
| | | VideoTypeOffOnlineExp videoTypeOffOnlineExp = this.getListOfflineCountInfo(list,"3",areaDeptEnum,false); |
| | | |
| | | VideoOnlineRateExp faceVideoOnlineRateExp = this.getListOnLineCountInfo(list,"1",areaDeptEnum,false); |
| | | //卡口 |
| | | VideoOnlineRateExp carVideoOnlineRateExp =this.getListOnLineCountInfo(list,"2",areaDeptEnum,false); |
| | | //视频 |
| | | VideoOnlineRateExp VideoOnlineRateExp = this.getListOnLineCountInfo(list,"3",areaDeptEnum,false); |
| | | |
| | | |
| | | //将该区域类三种设备类型的 信息 放入 excel对象内 |
| | | //放入当前区域的人脸设备相关详细 |
| | | videoTypeOffOnlineExps.add(faceVideoTypeOffOnlineExp); |
| | | //放入当前区域的车辆设备相关详细 |
| | | videoTypeOffOnlineExps.add(carVideoTypeOffOnlineExp); |
| | | //放入当前区域的视频设备相关详细 |
| | | videoTypeOffOnlineExps.add(videoTypeOffOnlineExp); |
| | | |
| | | videoOnlineRateExps.add(faceVideoOnlineRateExp); |
| | | videoOnlineRateExps.add(carVideoOnlineRateExp); |
| | | videoOnlineRateExps.add(VideoOnlineRateExp); |
| | | |
| | | |
| | | VideoTypeOffOnlineExp ALLfaceVideoTypeOffOnlineExp = this.getListOfflineCountInfo(list,"1",areaDeptEnum,true); |
| | | //卡口 |
| | | VideoTypeOffOnlineExp ALLcarVideoTypeOffOnlineExp =this.getListOfflineCountInfo(list,"2",areaDeptEnum,true); |
| | | //视频 |
| | | VideoTypeOffOnlineExp ALLvideoTypeOffOnlineExp = this.getListOfflineCountInfo(list,"3",areaDeptEnum,true); |
| | | |
| | | VideoOnlineRateExp ALLfaceVideoOnlineRateExp = this.getListOnLineCountInfo(list,"1",areaDeptEnum,true); |
| | | //卡口 |
| | | VideoOnlineRateExp ALLcarVideoOnlineRateExp =this.getListOnLineCountInfo(list,"2",areaDeptEnum,true); |
| | | //视频 |
| | | VideoOnlineRateExp ALLVideoOnlineRateExp = this.getListOnLineCountInfo(list,"3",areaDeptEnum,true); |
| | | |
| | | //添加合计数据 |
| | | allVideoTypeOffOnlineExps.add(ALLfaceVideoTypeOffOnlineExp); |
| | | //放入当前区域的车辆设备相关详细 |
| | | allVideoTypeOffOnlineExps.add(ALLcarVideoTypeOffOnlineExp); |
| | | //放入当前区域的视频设备相关详细 |
| | | allVideoTypeOffOnlineExps.add(ALLvideoTypeOffOnlineExp); |
| | | |
| | | allVideoOnlineRateExps.add(ALLfaceVideoOnlineRateExp); |
| | | allVideoOnlineRateExps.add(ALLcarVideoOnlineRateExp); |
| | | allVideoOnlineRateExps.add(ALLVideoOnlineRateExp); |
| | | |
| | | } |
| | | 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<List<ExcelExp>> util = new ExcelUtilManySheet<>(mysheet); |
| | | util.exportExcelManySheet(response, mysheet); |
| | | log.error("导出结束"); |
| | | } |
| | | |
| | | /** |
| | | * 计算离线设备excel对象信息 |
| | | * @param videoDailyExps 传入的设备集合信息 |
| | | * @param type 设备类型 1人脸 2车辆 3视频 |
| | | * @param areaDeptEnum 区域 |
| | | * @return |
| | | */ |
| | | public VideoTypeOffOnlineExp getListOfflineCountInfo(List<VideoDailyExp> videoDailyExps, |
| | | String type, |
| | | AreaDeptEnum areaDeptEnum, |
| | | boolean isTotal){ |
| | | VideoTypeOffOnlineExp videoTypeOffOnlineExp = new VideoTypeOffOnlineExp(); |
| | | |
| | | List<VideoDailyExp> list = videoDailyExps.stream() |
| | | .filter(device ->device.getType() != null && device.getType().contains(type)).collect(Collectors.toList()); |
| | | log.error("筛选完设备类型 :{} 后集合的大小:{}",type,list.size()); |
| | | //离线数量 |
| | | try { |
| | | //设置离线数量 以及每日离线数量 |
| | | setVideoTypeOffOnlineExpCountAndDays(list,videoTypeOffOnlineExp,isTotal); |
| | | } catch (Exception e) { |
| | | log.error(e.getMessage()); |
| | | } |
| | | //设备类型 |
| | | if(isTotal){ |
| | | if ("1".equals(type)){ |
| | | videoTypeOffOnlineExp.setType("人脸合计"); |
| | | }else if ("2".equals(type)){ |
| | | videoTypeOffOnlineExp.setType("卡口合计"); |
| | | }else if ("3".equals(type)){ |
| | | videoTypeOffOnlineExp.setType("视频合计"); |
| | | } |
| | | }else { |
| | | 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<VideoDailyExp> videoDailyExps,VideoTypeOffOnlineExp videoTypeOffOnlineExp,boolean isTotal)throws NoSuchFieldException, IllegalAccessException { |
| | | //循环一个月 |
| | | //离线总数 |
| | | long AllOffLineCount = 0; |
| | | log.error("传入集合大小:{}", videoDailyExps.size()); |
| | | for (VideoDailyExp videoDailyExp : videoDailyExps) { |
| | | if (videoDailyExp.isAllOfflineByMonth()) { |
| | | AllOffLineCount++; |
| | | } |
| | | } |
| | | //是合计数据不需要下方数据 |
| | | // if (!isTotal) { |
| | | 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<VideoDailyExp> videoDailyExps, |
| | | String type, |
| | | AreaDeptEnum areaDeptEnum, |
| | | boolean isTotal){ |
| | | VideoOnlineRateExp videoOnlineRateExp = new VideoOnlineRateExp(); |
| | | |
| | | List<VideoDailyExp> list = videoDailyExps.stream() |
| | | .filter(device ->device.getType() != null && device.getType().contains(type)).collect(Collectors.toList()); |
| | | log.error("筛选完设备类型 :{} 后集合的大小:{}",type,list.size()); |
| | | //离线数量 |
| | | try { |
| | | //设置离线数量 以及每日离线数量 |
| | | setVideoOnlineRateExpCountAndDays(list,videoOnlineRateExp,isTotal); |
| | | } catch (Exception e) { |
| | | log.error(e.getMessage()); |
| | | } |
| | | //设备类型 |
| | | if(isTotal) { |
| | | if ("1".equals(type)) { |
| | | videoOnlineRateExp.setType("人脸合计"); |
| | | } else if ("2".equals(type)) { |
| | | videoOnlineRateExp.setType("卡口合计"); |
| | | } else if ("3".equals(type)) { |
| | | videoOnlineRateExp.setType("视频合计"); |
| | | } |
| | | }else { |
| | | 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<VideoDailyExp> videoDailyExps,VideoOnlineRateExp videoOnlineRateExp,boolean isTotal)throws NoSuchFieldException, IllegalAccessException { |
| | | |
| | | //循环一个月 |
| | | 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 ++; |
| | | } |
| | | } |
| | | //每日在线率 |
| | | double rate = (double) count / videoDailyExps.size(); |
| | | //反射添加到对象属性中 |
| | | 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); |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | Function.identity(), // valueMapper,直接使用对象本身 |
| | | (existing, replacement) -> existing // mergeFunction,如果有重复,保留第一个 |
| | | )); |
| | | |
| | | // 将 Map 转换为 List |
| | | List<TMonitorResult> tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); |
| | | //获取动态列数据 |
| | |
| | | private void setOnlineDaily(VideoDailyExp videoDailyExp, TMonitorResult result, List<TMonitorResult> onlines) throws NoSuchFieldException, IllegalAccessException { |
| | | //一个设备当月在线情况 |
| | | List<TMonitorResult> 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 = ""; |
| | |
| | | field.setAccessible(true); |
| | | field.set(videoDailyExp, online); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | //设置每日录像数据 |