ycl-pojo/src/main/java/com/ycl/platform/domain/dto/MonitorConstructionDTO.java
New file @@ -0,0 +1,22 @@ package com.ycl.platform.domain.dto; import annotation.Excel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.web.multipart.MultipartFile; /** * zgyw * * @author : zxl * @date : 2025-10-20 14:20 **/ @Data public class MonitorConstructionDTO { @Excel(name = "设备编码") private String serialNumber; @Excel(name = "建设类型标签") private String tag; } ycl-pojo/src/main/java/com/ycl/platform/domain/entity/DemeritRecord.java
@@ -8,6 +8,7 @@ import lombok.Data; import java.math.BigDecimal; import java.util.Date; /** * zgyw @@ -27,4 +28,8 @@ @TableField("construction_type") private String constructionType; //录像计算生成时间 @TableField("record_time") private Date recordTime; } ycl-pojo/src/main/java/com/ycl/platform/domain/entity/MonitorConstruction.java
New file @@ -0,0 +1,32 @@ package com.ycl.platform.domain.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.ycl.platform.base.AbsEntity; import com.ycl.system.entity.BaseEntity; import lombok.Data; /** * zgyw * * @author : zxl * @date : 2025-10-20 11:37 **/ @Data @TableName("t_monitor_construction") public class MonitorConstruction extends AbsEntity { /** * 设备编号 */ @TableField(value = "serial_number") private String serialNumber; /** * 设备标签json字符串 */ @TableField(value = "tag") private String tag; } ycl-pojo/src/main/java/com/ycl/platform/domain/vo/TMonitorVO.java
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.ycl.system.entity.BaseEntity; import lombok.Data; import org.apache.ibatis.annotations.Param; import java.math.BigDecimal; import java.time.LocalDate; @@ -342,4 +343,10 @@ * 设备厂商: 0海康 1大华 2宇视 */ private Integer deviceType; List<String> ids; /** * 建设类型标签 */ private String tag; } ycl-pojo/src/main/java/com/ycl/platform/domain/vo/screen/DemeritRecordVO.java
@@ -1,9 +1,11 @@ package com.ycl.platform.domain.vo.screen; import com.fasterxml.jackson.annotation.JsonFormat; import com.ycl.platform.base.AbsVo; import lombok.Data; import java.math.BigDecimal; import java.util.Date; /** * zgyw @@ -33,4 +35,8 @@ */ private BigDecimal demerit; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date recordTime; } ycl-server/src/main/java/com/ycl/platform/controller/MonitorConstructionController.java
New file @@ -0,0 +1,35 @@ package com.ycl.platform.controller; import com.ycl.platform.service.IMonitorConstructionService; import com.ycl.system.Result; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; /** * zgyw * * @author : zxl * @date : 2025-10-20 13:55 **/ @RestController @RequestMapping("/monitorConstruction") @RequiredArgsConstructor public class MonitorConstructionController { private final IMonitorConstructionService monitorConstructionService; @PostMapping("/import") public Result importExcel(@RequestBody MultipartFile file) { return monitorConstructionService.importExcel(file); } @PostMapping("/importTemplate") public void importTemplate(HttpServletResponse httpServletResponse) { monitorConstructionService.getImportTemplate(httpServletResponse); } } ycl-server/src/main/java/com/ycl/platform/controller/TMonitorController.java
@@ -39,7 +39,7 @@ @GetMapping("/list") public TableDataInfo list(TMonitorVO tMonitor) { startPage(); List<TMonitorVO> list = tMonitorService.selectTMonitorList(tMonitor); return getDataTable(list); } ycl-server/src/main/java/com/ycl/platform/mapper/IMonitorConstructionMapper.java
New file @@ -0,0 +1,14 @@ package com.ycl.platform.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ycl.platform.domain.entity.MonitorConstruction; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; @Mapper public interface IMonitorConstructionMapper extends BaseMapper<MonitorConstruction> { int insertBatch(@Param("list") List<MonitorConstruction> list); } ycl-server/src/main/java/com/ycl/platform/mapper/TMonitorMapper.java
@@ -45,7 +45,7 @@ * @return 设备资产集合 */ public List<TMonitorVO> selectTMonitorList(TMonitorVO tMonitor); public List<TMonitorVO> selectTMonitorListAndIds(TMonitorVO tMonitor); /** * 查询设备资产列表 * ycl-server/src/main/java/com/ycl/platform/service/IMonitorConstructionService.java
New file @@ -0,0 +1,29 @@ package com.ycl.platform.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ycl.platform.domain.entity.MonitorConstruction; import com.ycl.system.Result; import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.multipart.MultipartFile; import java.util.List; public interface IMonitorConstructionService extends IService<MonitorConstruction> { /** * 导入设备标签 * @param file * @return */ Result importExcel(MultipartFile file); /** * 导出设备模板 * @return */ void getImportTemplate(HttpServletResponse httpServletResponse); List<MonitorConstruction> getSerialNumberListByConstructionType(String constructionType); } ycl-server/src/main/java/com/ycl/platform/service/impl/CheckScoreServiceImpl.java
@@ -565,21 +565,21 @@ //大屏展示考核得分 @Override public Map<String, Map<String, Object>> dashboard(DashboardQuery dashboardQuery) { // Date now = new Date(); Date now = new Date(); Calendar cal = Calendar.getInstance(); // 2. 设置为今年10月12号 00:00:00(清除时分秒,避免当前时间干扰) cal.set(Calendar.MONTH, Calendar.OCTOBER); // 10月(用常量更直观,避免记0基) // cal.set(Calendar.MONTH, 9); // 也可以用数字9(不推荐,可读性差) cal.set(Calendar.DAY_OF_MONTH, 12); // 日期设为12号 cal.set(Calendar.HOUR_OF_DAY, 12); // 小时设为0(24小时制) cal.set(Calendar.MINUTE, 0); // 分钟设为0 cal.set(Calendar.SECOND, 0); // 秒设为0 cal.set(Calendar.MILLISECOND, 0); // 毫秒设为0 // 3. 转成Date对象 Date now = cal.getTime(); // Calendar cal = Calendar.getInstance(); // //// 2. 设置为今年10月12号 00:00:00(清除时分秒,避免当前时间干扰) // cal.set(Calendar.MONTH, Calendar.OCTOBER); // 10月(用常量更直观,避免记0基) //// cal.set(Calendar.MONTH, 9); // 也可以用数字9(不推荐,可读性差) // cal.set(Calendar.DAY_OF_MONTH, 12); // 日期设为12号 // cal.set(Calendar.HOUR_OF_DAY, 12); // 小时设为0(24小时制) // cal.set(Calendar.MINUTE, 0); // 分钟设为0 // cal.set(Calendar.SECOND, 0); // 秒设为0 // cal.set(Calendar.MILLISECOND, 0); // 毫秒设为0 // //// 3. 转成Date对象 // Date now = cal.getTime(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ycl-server/src/main/java/com/ycl/platform/service/impl/IMonitorConstructionServiceImpl.java
New file @@ -0,0 +1,142 @@ package com.ycl.platform.service.impl; import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ycl.platform.domain.dto.MonitorConstructionDTO; import com.ycl.platform.domain.dto.ReportImportDTO; import com.ycl.platform.domain.entity.MonitorConstruction; import com.ycl.platform.mapper.IMonitorConstructionMapper; import com.ycl.platform.service.IMonitorConstructionService; import com.ycl.system.Result; import com.ycl.utils.StringUtils; import com.ycl.utils.poi.ExcelUtil; import enumeration.ConstructionTypeEnum; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * zgyw * * @author : zxl * @date : 2025-10-20 13:58 **/ @Service @Slf4j @RequiredArgsConstructor public class IMonitorConstructionServiceImpl extends ServiceImpl<IMonitorConstructionMapper, MonitorConstruction> implements IMonitorConstructionService { private final IMonitorConstructionMapper monitorConstructionMapper; @Override @Transactional(rollbackFor = Exception.class) public Result importExcel(MultipartFile file) { log.info("进入导入逻辑"); ExcelUtil<MonitorConstructionDTO> excelUtil = new ExcelUtil<>(MonitorConstructionDTO.class); List<MonitorConstructionDTO> list = null; List<MonitorConstructionDTO> distinctList = null; try { list = excelUtil.importExcel(file.getInputStream()); distinctList = list.stream() .filter(Objects::nonNull)//过滤掉null的对象 .filter(dto -> dto.getSerialNumber() != null)//过滤掉 getSerialNumber为null的对象 .collect(Collectors.toMap( MonitorConstructionDTO::getSerialNumber, dto -> dto, (existing, replacement) -> existing )) .values() .stream() .collect(Collectors.toList()); } catch (IOException e) { log.error("请检查导入excel表格内容"); throw new RuntimeException("请检查导入excel表格内容"); } List<MonitorConstruction> data = new ArrayList<>(); for (MonitorConstructionDTO dto : distinctList) { MonitorConstruction monitorConstruction = new MonitorConstruction(); monitorConstruction.setSerialNumber(dto.getSerialNumber()); monitorConstruction.setTag(dto.getTag()); data.add(monitorConstruction); } List<String> serialNumbers = data.stream() .map(MonitorConstruction::getSerialNumber) .collect(Collectors.toList()); //删除已存在的设备对应标签 if (CollectionUtils.isNotEmpty(serialNumbers)) { log.info("删除标签数据行数:{}",serialNumbers.size()); QueryWrapper<MonitorConstruction> queryWrapper = new QueryWrapper<>(); queryWrapper.in("serial_number", serialNumbers); queryWrapper.eq("deleted",false); baseMapper.delete(queryWrapper); } if (CollectionUtils.isNotEmpty(data)) { //插入标签表中 log.info("插入标签数据行数:{}",data.size()); saveBatch(data); } return Result.ok(); } @Override public void getImportTemplate(HttpServletResponse httpServletResponse){ ExcelUtil<MonitorConstructionDTO> excelUtil = new ExcelUtil<>(MonitorConstructionDTO.class); excelUtil.exportExcel(httpServletResponse, null, "设备标签模板"); } @Override public List<MonitorConstruction> getSerialNumberListByConstructionType(String constructionType) { List<MonitorConstruction> list = new ArrayList<>(); if (ConstructionTypeEnum.PHASE_ONE_TWO.name().equals(constructionType)){ //一二期 list = new LambdaQueryChainWrapper<>(baseMapper).eq(MonitorConstruction::getDeleted, Boolean.FALSE) .eq(MonitorConstruction::getTag, ConstructionTypeEnum.PHASE_ONE_TWO.getDesc()) .list(); }else if (ConstructionTypeEnum.PHASE_THREE.name().equals(constructionType)){ //三期 list = new LambdaQueryChainWrapper<>(baseMapper).eq(MonitorConstruction::getDeleted, Boolean.FALSE) .eq(MonitorConstruction::getTag, ConstructionTypeEnum.PHASE_THREE.getDesc()) .list(); }else if (ConstructionTypeEnum.PHASE_FOURTH.name().equals(constructionType)){ //四期人脸 list = new LambdaQueryChainWrapper<>(baseMapper).eq(MonitorConstruction::getDeleted, Boolean.FALSE) .eq(MonitorConstruction::getTag, ConstructionTypeEnum.PHASE_FOURTH.getDesc()) .list(); }else if (ConstructionTypeEnum.EASTERN_NEW_CITY.name().equals(constructionType)){ //东部新城 list = new LambdaQueryChainWrapper<>(baseMapper).eq(MonitorConstruction::getDeleted, Boolean.FALSE) .eq(MonitorConstruction::getTag, ConstructionTypeEnum.EASTERN_NEW_CITY.getDesc()) .list(); }else if (ConstructionTypeEnum.CHECK_ENTER_SICHUAN.name().equals(constructionType)){ //入川即检 list = new LambdaQueryChainWrapper<>(baseMapper).eq(MonitorConstruction::getDeleted, Boolean.FALSE) .eq(MonitorConstruction::getTag, ConstructionTypeEnum.CHECK_ENTER_SICHUAN.getDesc()) .list(); }else if (ConstructionTypeEnum.YAN_TAN_PHASE_TWO_FACE.name().equals(constructionType)){ //沿滩二期人脸 list = new LambdaQueryChainWrapper<>(baseMapper).eq(MonitorConstruction::getDeleted, Boolean.FALSE) .eq(MonitorConstruction::getTag, ConstructionTypeEnum.YAN_TAN_PHASE_TWO_FACE.getDesc()) .list(); } return list; } } ycl-server/src/main/java/com/ycl/platform/service/impl/TMonitorServiceImpl.java
@@ -6,6 +6,7 @@ import com.mongodb.client.AggregateIterable; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import com.ycl.platform.domain.entity.MonitorConstruction; import com.ycl.platform.domain.entity.TMonitor; import com.ycl.platform.domain.excel.*; import com.ycl.platform.domain.form.VideoExportForm; @@ -31,6 +32,7 @@ import com.ycl.platform.mapper.TMonitorMapper; import com.ycl.platform.mapper.WorkOrderMapper; import com.ycl.platform.mapper.YwPointMapper; import com.ycl.platform.service.IMonitorConstructionService; import com.ycl.platform.service.ITMonitorService; import com.ycl.system.Result; import com.ycl.system.entity.SysDictData; @@ -74,6 +76,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import static com.ycl.utils.PageUtils.startPage; /** * 设备资产Service业务层处理 * @@ -99,7 +103,8 @@ private DynamicColumnMapper dynamicColumnMapper; @Autowired private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Autowired private IMonitorConstructionService monitorConstructionService; /** * 查询设备资产 * @@ -129,7 +134,24 @@ } tMonitor.setTime(time); } List<TMonitorVO> monitors = tMonitorMapper.selectTMonitorList(tMonitor); List<TMonitorVO> monitors = new ArrayList<>(); if (StringUtils.isNotBlank(tMonitor.getConstructionType())){ List<MonitorConstruction> list = monitorConstructionService.getSerialNumberListByConstructionType(tMonitor.getConstructionType()); log.info("打印查询设备标签数:{},建设类型标签:{}",list.size(), tMonitor.getConstructionType() ); //获得设备编号集合 通过建设类型标签 if(!CollectionUtils.isEmpty(list)){ tMonitor.setIds( list.stream().map(MonitorConstruction::getSerialNumber).collect(Collectors.toList())); startPage(); monitors = tMonitorMapper.selectTMonitorListAndIds(tMonitor); } }else{ startPage(); monitors = tMonitorMapper.selectTMonitorList(tMonitor); } // 异常恢复监控 if (Objects.equals(tMonitor.getRecovery(), 1L)) { //工单号 @@ -346,6 +368,13 @@ @Override @DataScope(deptAlias = "d", userAlias = "u") public Map<String, String> getVideoCount(TMonitorVO tMonitor) { List<MonitorConstruction> list = monitorConstructionService.getSerialNumberListByConstructionType(tMonitor.getConstructionType()); //获得设备编号集合 通过建设类型标签 tMonitor.setIds( list.stream().map(MonitorConstruction::getSerialNumber).collect(Collectors.toList())); return tMonitorMapper.getVideoCount(tMonitor); } @@ -556,8 +585,6 @@ ExcelUtilManySheet<List<ExcelExp>> util = new ExcelUtilManySheet<>(mysheet); util.exportExcelManySheet(response, mysheet); } /** * 导出每日在线数据 */ @@ -578,9 +605,34 @@ // 使用线程安全的List,预先指定容量 List<ExcelExp> mysheet = Collections.synchronizedList(new ArrayList<>()); VideoExportForm.convertTags(exportForm); Query query = getQuery(exportForm); Query query = getQuery(exportForm);//装配条件 // 月份每日在线数据 List<TMonitorResult> onlineResult = mongoTemplate.find(query, TMonitorResult.class); log.info("大小:{}",onlineResult.size()); //此处需要过滤掉设备全景在线 细节不在线的情况 可以按 point分组 分我许多组之后再做处理 Map<String, List<TMonitorResult>> ipToDevices = onlineResult.stream() .collect(Collectors.groupingBy(TMonitorResult::getIp)); // onlineResult = ipToDevices.values().stream() // .map(devices -> { // // 检查分组中是否有 online = true 的设备 // List<TMonitorResult> onlineDevices = devices.stream() // .filter(monitor -> monitor.getOnline() == 1) // 假设online字段的getter是isOnline() // .collect(Collectors.toList()); // // if (!onlineDevices.isEmpty()) { // // 若存在online=true的设备,只保留第一个(或取任意一个,按需调整) // return onlineDevices.get(0); // } else { // // 若全为online=false,只保留第一个 // return devices.get(0); // } // }) // .collect(Collectors.toList()); log.info("月份在线数据:{}条数", onlineResult.size()); // 使用Collectors.toMap去重,保留每个No的第一个遇到的元素 Map<String, TMonitorResult> uniqueResultsMap = onlineResult.stream() @@ -589,9 +641,14 @@ Function.identity(), // valueMapper,直接使用对象本身 (existing, replacement) -> existing // mergeFunction,如果有重复,保留第一个 )); // 将 Map 转换为 List List<TMonitorResult> tMonitorResults = new ArrayList<>(uniqueResultsMap.values()); log.info("去重后大小:{}", tMonitorResults.size()); // 获取动态列数据并构建缓存Map Map<Integer, List<DynamicColumnVO>> dynamicColumnMap = new HashMap<>(); if (!tMonitorResults.isEmpty()) { @@ -600,6 +657,8 @@ .map(TMonitorResult::getPointId) .distinct() // 去重,减少数据库查询 .collect(Collectors.toList()); //获取集合点位的补充列信息 List<DynamicColumnVO> dynamics = dynamicColumnMapper.getDynamicsByIds("t_yw_point", pointIds); if (!CollectionUtils.isEmpty(dynamics)) { @@ -631,6 +690,9 @@ CompletableFuture<ExcelExp> future = CompletableFuture.supplyAsync(() -> { // 直接从预分组的Map中获取,避免每次过滤 List<TMonitorResult> monitors = deptMonitorMap.getOrDefault(currentDeptId, Collections.emptyList()); if (monitors.isEmpty()) { return null; } @@ -1458,6 +1520,22 @@ @Override public void export(HttpServletResponse response, TMonitorVO tMonitor) { List<TMonitorExp> monitors = tMonitorMapper.exportTMonitorList(tMonitor); //过滤出设备建设类型 if (StringUtils.isNotBlank(tMonitor.getConstructionType())){ List<MonitorConstruction> list = monitorConstructionService.getSerialNumberListByConstructionType(tMonitor.getConstructionType()); //获得设备编号集合 通过建设类型标签 List<String> serialNumberList = list.stream().map(MonitorConstruction::getSerialNumber).collect(Collectors.toList()); monitors = monitors.stream() .filter(result -> { String sn = result.getSerialNumber(); // 任一字段非空且在集合中即可 return (sn != null && serialNumberList.contains(sn)); }) .collect(Collectors.toList()); } //获取动态列数据 List<Integer> pointIds = monitors.stream().map(TMonitorExp::getPointId).collect(Collectors.toList()); List<DynamicColumnVO> dynamics = dynamicColumnMapper.getDynamicsByIds("t_yw_point", pointIds); ycl-server/src/main/java/com/ycl/platform/service/impl/WorkOrderServiceImpl.java
@@ -1303,10 +1303,23 @@ } // 是否报备 boolean hasReport = new LambdaQueryChainWrapper<>(reportMapper) .eq(Report::getSerialNumber, workOrder.getSerialNumber()) .exists(); workOrder.setHasReport(hasReport); Date target = workOrder.getCreateTime(); Report reports = new LambdaQueryChainWrapper<>(reportMapper) .eq(Report::getSerialNumber,workOrder.getWorkOrderNo()) .eq(Report::getStatus,1) .orderByDesc(Report::getCreateTime) .last("LIMIT 1") .one(); boolean isInRange = false; if (reports != null){ Date start = reports.getBeginCreateTime(); Date end = reports.getEndCreateTime(); isInRange = target.after(start) || target.equals(start) // target >= start && target.before(end) || target.equals(end); } workOrder.setHasReport(isInRange); // 故障类型 List<SysDictData> errorList = workOrderErrorTypeService.getBaseMapper().getErrorList(workOrder.getWorkOrderNo()); List<String> errList = errorList.stream().map(SysDictData::getDictLabel).collect(Collectors.toList()); ycl-server/src/main/java/com/ycl/task/DemeritRecordTask.java
@@ -5,9 +5,11 @@ import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.google.common.util.concurrent.AtomicDouble; import com.ycl.platform.domain.entity.DemeritRecord; import com.ycl.platform.domain.entity.MonitorConstruction; import com.ycl.platform.domain.entity.Report; import com.ycl.platform.domain.result.UY.RecordMetaDSumResult; import com.ycl.platform.mapper.DemeritRecordMapper; import com.ycl.platform.mapper.IMonitorConstructionMapper; import com.ycl.platform.mapper.ReportMapper; import com.ycl.platform.service.IDemeritRecordService; import com.ycl.utils.DateUtils; @@ -50,6 +52,8 @@ private final ReportMapper reportMapper; private final IMonitorConstructionMapper monitorConstructionMapper; private static final ExecutorService executorService = new ThreadPoolExecutor(16, 128, 5000, @@ -59,21 +63,12 @@ ); private final IDemeritRecordService demeritRecordService; // 提取公共过滤方法 private Predicate<RecordMetaDSumResult> deviceNameStartsWith(String prefix) { return result -> result.getDeviceName() != null && result.getDeviceName().startsWith(prefix); } private Predicate<RecordMetaDSumResult> deviceNameStartsWithAny(String... prefixes) { return result -> result.getDeviceName() != null && Arrays.stream(prefixes).anyMatch(prefix -> result.getDeviceName().startsWith(prefix)); } private DemeritRecord buildDemeritRecord(String constructionType,BigDecimal demerit,Integer deptId) { private DemeritRecord buildDemeritRecord(String constructionType,BigDecimal demerit,Integer deptId,Date recordTime) { DemeritRecord record = new DemeritRecord(); record.setConstructionType(constructionType); record.setDemerit(demerit); record.setDeptId(deptId); record.setRecordTime(recordTime); return record; } private BigDecimal calculateTotalDeduction(List<RecordMetaDSumResult> records) { @@ -126,7 +121,7 @@ log.info("日期:{},查询出的设备录像记录数{}",today,results.size()); //过滤掉非全景的设备 且 1则为细节,如果是0则为全景 results.stream().filter(obj -> results = results.stream().filter(obj -> { String deviceId = obj.getDeviceId(); if (deviceId == null || deviceId.length() < 7) { @@ -135,7 +130,7 @@ // 获取倒数第七位的字符 char seventhFromEnd = deviceId.charAt(deviceId.length() - 7); return seventhFromEnd != '1'; //为1 则会 false 去除掉 }); }).collect(Collectors.toList()); log.info("过滤后剩余全景设备数{}",results.size()); //只考核LT_、(三期) @@ -143,28 +138,43 @@ // DX_R、(四区人脸) // DX_RS、(四区人脸) // (需要排除DX_R2、DX_RD、J_、T1、T3以及没有前缀的设备) List<String> prefixes = Arrays.asList("LT_", "DX_", "DX_R", "DX_RS"); results.stream() // List<String> prefixes = Arrays.asList("LT_", "DX_", "DX_R", "DX_RS"); //查询设备标签表中的MonitorConstruction列表 List<MonitorConstruction> monitorConstructionList = new LambdaQueryChainWrapper<>(monitorConstructionMapper) .eq(MonitorConstruction::getDeleted, Boolean.FALSE) .list(); List<String> serialNumberList = monitorConstructionList.stream() .map(MonitorConstruction::getSerialNumber).collect(Collectors.toList()); //过滤获得包含了这些标签的设备录像情况集合 results = results.stream() .filter(result -> { String deviceName = result.getDeviceName(); if (deviceName == null) { return false; } return prefixes.stream().anyMatch(deviceName::startsWith); String sn = result.getNo(); // 任一字段非空且在集合中即可 return (sn != null && serialNumberList.contains(sn)); }) .collect(Collectors.toList()); log.info("剩余考核设备过滤后设备数{}",results.size()); //过滤掉报备的设备 //查询在当前时间有报备的所有设备, //因为录像数据的时间 List<String> deviceIds = new LambdaQueryChainWrapper<>(reportMapper) Date yesterday =new Date(); Calendar calendar = Calendar.getInstance(); calendar.setTime(yesterday); calendar.add(Calendar.DAY_OF_YEAR, -1); // 减去1天 测试用 yesterday = calendar.getTime(); log.info("测试时间:{}",yesterday); List<Report> list = new LambdaQueryChainWrapper<>(reportMapper) .eq(Report::getStatus, 1) .ge(Report::getBeginCreateTime, today) .le(Report::getEndCreateTime, today) .list().stream() .ge(Report::getBeginCreateTime, DateUtils.getDayStart(yesterday)) .le(Report::getEndCreateTime, DateUtils.getDayEnd(yesterday)) .list(); log.info("报备记录:{}",list); List<String> deviceIds = list.stream() .collect(Collectors.toMap( Report::getSerialNumber, // key: serialNumber Function.identity(), // value: Report对象本身 @@ -177,7 +187,7 @@ Set<String> deviceIdSet = new HashSet<>(deviceIds); log.info("报备设备数{}",deviceIdSet.size()); results.stream() results = results.stream() .filter(result -> { // 获取当前对象的deviceId String resultDeviceId = result.getDeviceId(); @@ -202,6 +212,24 @@ Map<String,List<RecordMetaDSumResult>> groupByArealayerno = results.stream() .collect(Collectors.groupingBy(RecordMetaDSumResult::getArealayerno)); //按建设类型标签分组设备NO monitorConstructionList //按标签分组 Map<String, List<String>> groupByTag = monitorConstructionList.stream() // 分组键:提取每个对象的 tag(注意处理 tag 为 null 的情况,避免键为 null) .collect(Collectors.groupingBy( mc -> mc.getTag() != null ? mc.getTag() : "DEFAULT_TAG", Collectors.mapping(MonitorConstruction::getSerialNumber, Collectors.toList()) )); List<String> phaseOneTwoSerials = groupByTag.getOrDefault(ConstructionTypeEnum.PHASE_ONE_TWO.getDesc(), Collections.emptyList()); List<String> phaseThreeSerials = groupByTag.getOrDefault(ConstructionTypeEnum.PHASE_THREE.getDesc(), Collections.emptyList()); List<String> phaseFourthSerials = groupByTag.getOrDefault(ConstructionTypeEnum.PHASE_FOURTH.getDesc(), Collections.emptyList()); List<String> checkEnterSichuan = groupByTag.getOrDefault(ConstructionTypeEnum.CHECK_ENTER_SICHUAN.getDesc(), Collections.emptyList()); List<String> easternNewCity= groupByTag.getOrDefault(ConstructionTypeEnum.EASTERN_NEW_CITY.getDesc(), Collections.emptyList()); List<String> yanTanPhaseTwoFace = groupByTag.getOrDefault(ConstructionTypeEnum.YAN_TAN_PHASE_TWO_FACE.getDesc(), Collections.emptyList()); //循环分组后的map for (Map.Entry<String, List<RecordMetaDSumResult>> entry : groupByArealayerno.entrySet()) { String arealayerno = entry.getKey(); @@ -218,65 +246,62 @@ if (CollectionUtils.isNotEmpty(resultList)) { // 对每个List进行处理 分建类型处理集合 List<RecordMetaDSumResult> phase_one_two = resultList.stream() .filter(deviceNameStartsWith("DX_")) .filter(result -> { String no = result.getNo(); return no != null && phaseOneTwoSerials.contains(no); }) .collect(Collectors.toList()); log.info("一二期考核记录数{}",phase_one_two.size()); List<RecordMetaDSumResult> phase_three = resultList.stream() .filter(deviceNameStartsWith("LT_")) .filter(result -> { String no = result.getNo(); return no != null && phaseThreeSerials.contains(no); }) .collect(Collectors.toList()); log.info("三期考核记录数{}",phase_three.size()); List<RecordMetaDSumResult> phase_fourth = resultList.stream() .filter(deviceNameStartsWithAny("DX_R", "DX_RS")) .filter(result -> { String no = result.getNo(); return no != null && phaseFourthSerials.contains(no); }) .collect(Collectors.toList()); log.info("四期考核记录数{}",phase_fourth.size()); if (CollectionUtils.isNotEmpty(phase_one_two)){ BigDecimal phaseOneTwoDeduction = calculateTotalDeduction(phase_one_two); DemeritRecord demeritRecordPhaseOneTwo = buildDemeritRecord( ConstructionTypeEnum.PHASE_ONE_TWO.name(), phaseOneTwoDeduction, areaDeptEnum.getDeptId()); demeritRecords.add(demeritRecordPhaseOneTwo); }else{ DemeritRecord phaseOneTwoDeduction = buildDemeritRecord( ConstructionTypeEnum.PHASE_ONE_TWO.name(), BigDecimal.ZERO, areaDeptEnum.getDeptId()); demeritRecords.add(phaseOneTwoDeduction); List<RecordMetaDSumResult> check_enter_sichuan = resultList.stream() .filter(result ->{ String no = result.getNo(); return no != null && checkEnterSichuan.contains(no); }) .collect(Collectors.toList()); log.info("入川即检{}", check_enter_sichuan.size()); List<RecordMetaDSumResult> eastern_new_city = resultList.stream() .filter(result ->{ String no = result.getNo(); return no != null && easternNewCity.contains(no); }) .collect(Collectors.toList()); log.info("东部新城{}", eastern_new_city.size()); List<RecordMetaDSumResult> yan_tan_phase_two_face = resultList.stream() .filter(result ->{ String no = result.getNo(); return no != null && yanTanPhaseTwoFace.contains(no); }) .collect(Collectors.toList()); log.info("沿滩二期人脸{}", yan_tan_phase_two_face.size()); //一二期 buildAndAddDemeritRecords(phase_one_two, ConstructionTypeEnum.PHASE_ONE_TWO.name(), areaDeptEnum.getDeptId(),yesterday,demeritRecords); //三期 buildAndAddDemeritRecords(phase_three, ConstructionTypeEnum.PHASE_THREE.name(), areaDeptEnum.getDeptId(),yesterday,demeritRecords); //四期 buildAndAddDemeritRecords(phase_fourth, ConstructionTypeEnum.PHASE_FOURTH.name(), areaDeptEnum.getDeptId(),yesterday,demeritRecords); //入川即检 buildAndAddDemeritRecords(check_enter_sichuan, ConstructionTypeEnum.CHECK_ENTER_SICHUAN.name(), areaDeptEnum.getDeptId(),yesterday,demeritRecords); //东部新城 buildAndAddDemeritRecords(eastern_new_city, ConstructionTypeEnum.EASTERN_NEW_CITY.name(), areaDeptEnum.getDeptId(),yesterday,demeritRecords); //沿滩二期人脸 buildAndAddDemeritRecords(yan_tan_phase_two_face, ConstructionTypeEnum.YAN_TAN_PHASE_TWO_FACE.name(), areaDeptEnum.getDeptId(),yesterday,demeritRecords); } if (CollectionUtils.isNotEmpty(phase_three)){ BigDecimal phaseThreeDeduction = calculateTotalDeduction(phase_three); DemeritRecord demeritRecordPhaseThree = buildDemeritRecord( ConstructionTypeEnum.PHASE_THREE.name(), phaseThreeDeduction, areaDeptEnum.getDeptId()); demeritRecords.add(demeritRecordPhaseThree); }else { DemeritRecord phaseThreeDeduction = buildDemeritRecord( ConstructionTypeEnum.PHASE_THREE.name(), BigDecimal.ZERO, areaDeptEnum.getDeptId()); demeritRecords.add(phaseThreeDeduction); } if (CollectionUtils.isNotEmpty(phase_fourth)){ BigDecimal phaseFourthDeduction = calculateTotalDeduction(phase_fourth); DemeritRecord demeritRecordPhaseFourth = buildDemeritRecord( ConstructionTypeEnum.PHASE_FOURTH.name(), phaseFourthDeduction, areaDeptEnum.getDeptId()); demeritRecords.add(demeritRecordPhaseFourth); }else{ DemeritRecord phaseFourthDeduction = buildDemeritRecord( ConstructionTypeEnum.PHASE_FOURTH.name(), BigDecimal.ZERO, areaDeptEnum.getDeptId()); demeritRecords.add(phaseFourthDeduction); } } } @@ -292,4 +317,25 @@ log.info("结束计算每日扣分记录情况:插入数据量{},数据信息:{}",demeritRecords.size(),demeritRecords); } public void buildAndAddDemeritRecords(List<RecordMetaDSumResult> constructionByRecordMetaList, String constructionType,Integer areaDeptId,Date recordTime, List<DemeritRecord> demeritRecords) { if (CollectionUtils.isNotEmpty(constructionByRecordMetaList)) { BigDecimal deduction = calculateTotalDeduction(constructionByRecordMetaList); DemeritRecord demeritRecord = buildDemeritRecord( constructionType, deduction, areaDeptId, DateUtils.getDayStart(recordTime)); demeritRecords.add(demeritRecord); }else{ DemeritRecord demeritRecord = buildDemeritRecord( constructionType, BigDecimal.ZERO, areaDeptId, DateUtils.getDayStart(recordTime)); demeritRecords.add(demeritRecord); } } } ycl-server/src/main/java/com/ycl/task/UYTask.java
@@ -182,6 +182,8 @@ * online字段来自于优云,pingOnline为主动ping检测的。存入mongo给数据中心查阅 */ public void pointOnline() throws ExecutionException, InterruptedException { log.info("开始检测点位在线"); Integer times = 2; SysConfig config = new SysConfig(); @@ -261,6 +263,11 @@ unKnownList.add(item.getIp()); } }); if(!CollectionUtils.isEmpty(onLineList)){ log.error("在线点位集合:{}",onLineList); } log.error("unKnownList:{}",unKnownList); if(!CollectionUtils.isEmpty(offLineList)) { log.error("修改离线的点位集合:{}",offLineList); @@ -289,6 +296,10 @@ }else if("3".equals(type)){ mongoData.setProvinceTag(mongoData.getProvinceTagFace()); } //修改线上 if(mongoData.getPingOnline()){ mongoData.setOnline(1); } mongoList.add(mongoData); } } ycl-server/src/main/resources/mapper/zgyw/DemeritREcordMapper.xml
@@ -18,7 +18,8 @@ ter.dept_id, ter.create_time, ter.construction_type, ter.demerit ter.demerit, ter.record_time from t_demerit_record ter where ter.deleted = 0 <if test="query.deptId != null and query.deptId != ''"> AND ter.dept_id = #{query.deptId} @@ -28,13 +29,14 @@ </if> <!-- 时间范围筛选:按日查询 --> <if test="query.searchType == 'day' and query.dayDate != null"> AND ter.create_time >= #{query.dayDate} <!-- 当天00:00:00 --> AND ter.create_time <DATE_ADD(#{query.dayDate}, INTERVAL 1 DAY) <!-- 次日00:00:00(不包含) --> AND ter.record_time >= #{query.dayDate} <!-- 当天00:00:00 --> AND ter.record_time <DATE_ADD(#{query.dayDate}, INTERVAL 1 DAY) <!-- 次日00:00:00(不包含) --> </if> <!-- 时间范围筛选:按月查询 --> <if test="query.searchType == 'month' and query.monthDate != null"> AND ter.create_time >= #{query.monthDate} <!-- 当月1日00:00:00 --> AND ter.create_time <DATE_ADD(LAST_DAY(#{query.monthDate}), INTERVAL 1 DAY) <!-- 下月1日00:00:00(不包含) --> </if> ORDER BY ter.record_time DESC </select> </mapper> ycl-server/src/main/resources/mapper/zgyw/IMonitorConstructionMapper.xml
New file @@ -0,0 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ycl.platform.mapper.IMonitorConstructionMapper"> <insert id="insertBatch"> INSERT INTO t_monitor_construction(serial_number,tag,deleted) values <foreach collection="list" item="item" index="index" separator=","> ( #{item.serialNumber},#{item.tag},0) </foreach> </insert> </mapper> ycl-server/src/main/resources/mapper/zgyw/TMonitorMapper.xml
@@ -106,7 +106,8 @@ WHEN p.online = -1 OR p.ping_online = -1 THEN -1 ELSE 0 END AS onState, civil_code, d.dept_id, d.dept_name, d.area, p.province_tag_video,p.province_tag_car,p.province_tag_face,p.dept_tag, IF(COUNT(w.id) OVER() > 0, '是', '否') AS error, u.unit_name,p.recovery_time,p.reason,p.start_time,p.end_time, w.work_order_no IF(COUNT(w.id) OVER() > 0, '是', '否') AS error, u.unit_name,p.recovery_time,p.reason,p.start_time,p.end_time, w.work_order_no, tmc.tag from t_monitor m left join t_yw_point p on m.serial_number = p.serial_number and p.deleted = 0 left join sys_dept d on p.dept_id = d.dept_id and d.del_flag = 0 @@ -117,6 +118,7 @@ ) SELECT * FROM cte WHERE rn=1 ) w on m.serial_number = w.serial_number and w.deleted = 0 left join t_yw_unit u on p.unit_id = u.id and u.deleted = 0 LEFT JOIN t_monitor_construction tmc on m.serial_number = tmc.serial_number and tmc.deleted = 0 <where> p.examine_status = 1 <if test="serialNumber != null and serialNumber != ''">and m.serial_number = #{serialNumber}</if> @@ -166,35 +168,94 @@ <if test="cameraDept != null and cameraDept != ''">and camera_dept = #{cameraDept}</if> <if test="hybm != null and hybm != ''">and hybm = #{hybm}</if> <if test="lxbm != null ">and lxbm = #{lxbm}</if> <if test="constructionType != null and constructionType != ''"> <choose> <when test="constructionType == 'PHASE_ONE_TWO'"> and m.name LIKE 'DX_%' </when> <when test="constructionType == 'PHASE_THREE'"> and m.name LIKE 'LT_%' </when> <when test="constructionType == 'PHASE_FOURTH'"> and ( m.name LIKE 'DX_R%' OR m.name LIKE 'DX_RS%' ) </when> <when test="constructionType == 'EASTERN_NEW_CITY'"> and m.name LIKE 'DX_RD%' </when> <when test="constructionType == 'YAN_TAN_PHASE_TWO_FACE'"> and m.name LIKE 'DX_R2%' </when> </choose> </if> ${params.dataScope} </where> </select> <select id="selectTMonitorListAndIds" resultType="com.ycl.platform.domain.vo.TMonitorVO"> select m.id, m.serial_number, name, site_type, mac_addr, ip, camera_fun_type, longitude, latitude, camera_capture_area, CASE WHEN p.online = 1 AND p.ping_online = 1 THEN 1 WHEN p.online = -1 OR p.ping_online = -1 THEN -1 ELSE 0 END AS onState, civil_code, d.dept_id, d.dept_name, d.area, p.province_tag_video,p.province_tag_car,p.province_tag_face,p.dept_tag, IF(COUNT(w.id) OVER() > 0, '是', '否') AS error, u.unit_name,p.recovery_time,p.reason,p.start_time,p.end_time, w.work_order_no, tmc.tag from t_monitor m left join t_yw_point p on m.serial_number = p.serial_number and p.deleted = 0 left join sys_dept d on p.dept_id = d.dept_id and d.del_flag = 0 left join ( WITH cte AS ( SELECT *,row_number() OVER(PARTITION BY serial_number ORDER BY create_time DESC) rn FROM t_work_order WHERE deleted = 0 AND status != 'AUDITING_SUCCESS' ) SELECT * FROM cte WHERE rn=1 ) w on m.serial_number = w.serial_number and w.deleted = 0 left join t_yw_unit u on p.unit_id = u.id and u.deleted = 0 LEFT JOIN t_monitor_construction tmc on m.serial_number = tmc.serial_number and tmc.deleted = 0 <where> p.examine_status = 1 <if test="ids != null and ids.size() > 0"> and m.serial_number in <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </if> <if test="serialNumber != null and serialNumber != ''">and m.serial_number = #{serialNumber}</if> <if test="name != null and name != ''"> and (name like concat('%', #{name}, '%') or m.ip like concat('%', #{name}, '%') or m.serial_number like concat('%', #{name}, '%') or u.unit_name like concat('%', #{name}, '%')) </if> <if test="provinceTag != null and cameraFunType == 1">and p.province_tag_video = #{provinceTag}</if> <if test="provinceTag != null and cameraFunType == 2">and p.province_tag_car = #{provinceTag}</if> <if test="provinceTag != null and cameraFunType == 3">and p.province_tag_face = #{provinceTag}</if> <if test="provinceTag != null and recovery == 1">and (p.province_tag_face = #{provinceTag} or p.province_tag_video = #{provinceTag} or p.province_tag_car = #{provinceTag})</if> <if test="deptTag != null ">and p.dept_tag = #{deptTag}</if> <if test="siteType != null ">and site_type = #{siteType}</if> <if test="macAddr != null and macAddr != ''">and mac_addr = #{macAddr}</if> <if test="ip != null and ip != ''">and ip = #{ip}</if> <if test="cameraFunType != null and cameraFunType != ''">and camera_fun_type like concat('%', #{cameraFunType}, '%') </if> <if test="longitude != null and longitude != ''">and longitude = #{longitude}</if> <if test="latitude != null and latitude != ''">and latitude = #{latitude}</if> <if test="cameraCaptureArea != null and cameraCaptureArea != ''">and camera_capture_area = #{cameraCaptureArea} </if> <if test="time !=null and time !=''">and TIMESTAMPDIFF(DAY, p.recovery_time, NOW()) <![CDATA[<=]]> #{time}</if> <if test="onState != null and onState == 1">and (p.online = #{onState} and p.ping_online = #{onState})</if> <if test="onState != null and onState == -1">and (p.online = #{onState} or p.ping_online = #{onState})</if> <if test="onState != null and onState == 0">and (p.online = #{onState} and p.ping_online = #{onState})</if> <if test="civilCode != null and civilCode != ''">and civil_code = #{civilCode}</if> <if test="integratedDevice != null ">and integrated_device = #{integratedDevice}</if> <if test="cameraBrand != null ">and camera_brand = #{cameraBrand}</if> <if test="address != null and address != ''">and d.dept_id = #{address}</if> <if test="netWorking != null ">and net_working = #{netWorking}</if> <if test="publicSecurity != null and publicSecurity != ''">and public_security = #{publicSecurity}</if> <if test="installedTime != null ">and installed_time = #{installedTime}</if> <if test="managementUnit != null and managementUnit != ''">and management_unit = #{managementUnit}</if> <if test="muContactInfo != null and muContactInfo != ''">and mu_contact_info = #{muContactInfo}</if> <if test="storageDays != null ">and storage_days = #{storageDays}</if> <if test="monitorAzimuth != null ">and monitor_azimuth = #{monitorAzimuth}</if> <if test="scenePhotoAddr != null and scenePhotoAddr != ''">and scene_photo_addr = #{scenePhotoAddr}</if> <if test="model != null and model != ''">and model = #{model}</if> <if test="siteVulgo != null and siteVulgo != ''">and site_vulgo = #{siteVulgo}</if> <if test="cameraType != null ">and camera_type = #{cameraType}</if> <if test="cameraLightType != null ">and camera_light_type = #{cameraLightType}</if> <if test="encodedFormat != null ">and encoded_format = #{encodedFormat}</if> <if test="cameraDept != null and cameraDept != ''">and camera_dept = #{cameraDept}</if> <if test="hybm != null and hybm != ''">and hybm = #{hybm}</if> <if test="lxbm != null ">and lxbm = #{lxbm}</if> ${params.dataScope} </where> </select> <select id="exportTMonitorList" resultType="com.ycl.platform.domain.excel.TMonitorExp"> select m.id, m.serial_number, name, ip, camera_fun_type, CASE @@ -441,6 +502,12 @@ <if test="address != null"> and p.dept_id = #{address} </if> <if test="ids != null and ids.size() > 0"> and m.serial_number in <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </if> <if test="constructionType != null and constructionType != ''"> <choose> <when test="constructionType == 'PHASE_ONE_TWO'"> @@ -464,6 +531,7 @@ </when> </choose> </if> ${params.dataScope} </where> </select>