package com.ycl.task; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.mongodb.client.result.DeleteResult; import com.ycl.platform.domain.entity.*; import com.ycl.platform.domain.result.HK.PicAccessResult; import com.ycl.platform.domain.result.HK.SnapshotDataMonitorResult; import com.ycl.platform.domain.result.UY.RecordMetaDSumResult; import com.ycl.platform.domain.result.UY.VideoOnlineResult; import com.ycl.platform.domain.vo.CalculateRuleVO; import com.ycl.platform.domain.vo.ContractVO; import com.ycl.platform.domain.vo.ReportVO; import com.ycl.platform.domain.vo.WorkOrderVO; import com.ycl.platform.mapper.*; import com.ycl.platform.service.IContractScoreService; import com.ycl.utils.DateUtils; import constant.ApiConstants; import constant.RedisConstant; import enumeration.ContractRule; import enumeration.ErrorType; import enumeration.general.AuditingStatus; import enumeration.general.ErrorTypeEnum; import enumeration.general.RuleDeductCategoryEnum; import enumeration.general.WorkOrderStatusEnum; import lombok.extern.slf4j.Slf4j; 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.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import javax.management.monitor.Monitor; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; /** * 合同考核定时任务 */ @Slf4j @Component("contractTask") public class ContractTask { @Autowired private MongoTemplate mongoTemplate; @Autowired private TContractMapper contractMapper; @Autowired private YwPointMapper ywPointMapper; @Autowired private ReportMapper reportMapper; @Autowired private ContractRuleRecordMapper recordMapper; @Autowired private IContractScoreService contractScoreService; @Autowired private WorkOrderMapper workOrderMapper; private static final Integer Online = 1; private static final Integer Offline = -1; private static final String AuditStatus_Pass = "1"; private static final String Remark = "系统生成"; private static final Integer randomSize = 50; /** * 合同考核 在线率每日任务检测 * 查生效的合同关联的公司,获取unitId集合 * 根据unitId查询对应点位获取各个公司管理的设备Ids * 查询三种设备在线不在线情况,封装为一个map<国标码,在线状态> * 计算每日每家公司的在线率存入mysql * 月底计算平均值,根据在线率和合同标准扣减分数 */ public void onlineCheck() { log.info("开始计算合同点位在线率"); List ruleVos = contractMapper.getCalculateRule(new Date()).stream() .filter(calculateRuleVO -> ContractRule.CONTRACT_RULE_Online.getName().equals(calculateRuleVO.getRuleName())) .collect(Collectors.toList()); List unitIds = ruleVos.stream().map(CalculateRuleVO::getUnitId).collect(Collectors.toList()); List ywPoints = ywPointMapper.selectList(new QueryWrapper().in("unit_id", unitIds)); //key是unitId value是设备编码集合 Map> unitMap = ywPoints.stream() .collect(Collectors.groupingBy( YwPoint::getUnitId, Collectors.mapping( YwPoint::getSerialNumber, Collectors.toList() ) )); Map onlineStatusMap = new HashMap<>(); //查mongo获取设备在线情况 Date date = DateUtils.getDay(2024, 7, 13); //车辆、人脸 Query query = new Query(); query.addCriteria(Criteria .where("mongoCreateTime").gte(DateUtils.getDayStart(date)).lt(DateUtils.getDayEnd(date))); List results = mongoTemplate.find(query, SnapshotDataMonitorResult.class); for (SnapshotDataMonitorResult result : results) { if (ApiConstants.HK_SnapCount_ResultType_Null != result.getResultType()) { onlineStatusMap.put(result.getExternalIndexCode(), Online); } else { onlineStatusMap.put(result.getExternalIndexCode(), Offline); } } //视频 Query videoQuery = new Query(Criteria .where("mongoCreateTime").gte(DateUtils.getDayStart(date)).lt(DateUtils.getDayEnd(date))); List videoOnlineResults = mongoTemplate.find(videoQuery, VideoOnlineResult.class); for (VideoOnlineResult videoOnlineResult : videoOnlineResults) { onlineStatusMap.put(videoOnlineResult.getDeviceId(), videoOnlineResult.getStatus()); } //查询报备列表 List reportNumbers = reportMapper.selectNumberList(AuditStatus_Pass, DateUtils.getDate()); //计算每个公司的点位在线率 List ruleRecordList = new ArrayList<>(); unitMap.forEach((unitId, serialNumberList) -> { int totalSite = 0; int onlineSite = 0; for (String number : serialNumberList) { //报备过不纳入计算 if (!CollectionUtils.isEmpty(reportNumbers) && reportNumbers.contains(number)) continue; Integer status = onlineStatusMap.get(number); totalSite++; if (Online.equals(status)) { onlineSite++; } } BigDecimal online = new BigDecimal(onlineSite).divide(new BigDecimal(totalSite), 2, RoundingMode.DOWN); ContractRuleRecord contractRuleRecord = new ContractRuleRecord(); contractRuleRecord.setSiteOnline(online); contractRuleRecord.setCreateTime(new Date()); contractRuleRecord.setUnitId(unitId); ruleRecordList.add(contractRuleRecord); }); //存储结果 recordMapper.insertBatch(ruleRecordList); log.info("结束计算合同点位在线率"); } //月底计算在线率分数 public void calculateOnlineScore() { log.info("开始计算合同点位在线率分数"); //如果是月底,需要统计平均在线率然后进行积分扣除 // String now = DateUtils.getDate(); String mouthStart = DateUtils.getMouthStart(new Date()); String mouthEnd = DateUtils.getMouthEnd(new Date()); // if (now.equals(mouthEnd)) { //查一个月的记录 List ruleMonthRecords = recordMapper.selectMonth(mouthStart, mouthEnd); //通过unitId分单位 Map> unitMap = ruleMonthRecords.stream().collect(Collectors.groupingBy(ContractRuleRecord::getUnitId)); //查在线率规则 获取key为合同id,value为在线率规则的map Map> contractMap = contractMapper.getCalculateRule(new Date()).stream() .filter(calculateRuleVO -> ContractRule.CONTRACT_RULE_Online.getName().equals(calculateRuleVO.getRuleName())) .collect(Collectors.groupingBy(CalculateRuleVO::getContractId)); //准备批量打分的集合 List contractScoreList = new ArrayList<>(); contractMap.forEach((contractId, ruleList) -> { //一个合同对应一个单位,因此unitId都相同 CalculateRuleVO calculateRuleVO = ruleList.get(0); Integer unitId = calculateRuleVO.getUnitId(); List ruleRecordList = unitMap.get(Long.parseLong(unitId + "")); if (!CollectionUtils.isEmpty(ruleMonthRecords)) { BigDecimal siteOnlineTotal = ruleRecordList.stream().map(ContractRuleRecord::getSiteOnline).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal siteOnline = siteOnlineTotal.divide(new BigDecimal(ruleRecordList.size()), 2, RoundingMode.DOWN); for (CalculateRuleVO ruleVO : ruleList) { Double max = ruleVO.getMax(); Double min = ruleVO.getMin(); //判断范围在哪个区间 if (checkRange(min, max, siteOnline.multiply(new BigDecimal(100)))) { //需要扣除的分数 Double deductScore = ruleVO.getCalcFraction(); ContractScore contractScore = getContractScore(ruleVO, deductScore, siteOnline + "", Remark); contractScoreList.add(contractScore); } } } }); // } contractScoreService.saveBatch(contractScoreList); log.info("结束计算合同点位在线率分数"); } /** * 检测工单表 进行合同积分扣除 * 查出工单需要扣分的所有规则 * 查出未扣分且已经审核完成了的工单组成map> 工单需要连工单故障表查出多个故障类型 * 循环工单map,每个工单故障类型查对应的规则,根据规则和工单创建时间和审核通过时间进行扣分 * 插入合同积分表,修改工单状态为已扣分 */ public void workOrderDeduct() { log.info("开始扫描工单扣分"); //准备批量打分的集合 List contractScoreList = new ArrayList<>(); List workOrderList = new ArrayList<>(); //查询生效合同对应所有的规则 List calculateRules = contractMapper.getCalculateRule(new Date()); Map>> ruleMap = calculateRules.stream() .collect(Collectors.groupingBy( CalculateRuleVO::getRuleName, // 按规则名称分组 Collectors.groupingBy( CalculateRuleVO::getContractId // 每个规则名称内部再按合同ID分组,value为规则集合 ) )); //前端感知源治理工作(时钟同步规则、OSD规则、一机一档规则) 获取key为合同id,value为规则的map Map> monitorRuleMap = ruleMap.get(ContractRule.CONTRACT_RULE_Monitor.getName()); //存储故障(24小时以内,48小时以内) 获取key为合同id,value为规则的map Map> storeRuleMap = ruleMap.get(ContractRule.CONTRACT_RULE_Store.getName()); //点位异常情况处理 获取key为合同id,value为规则的map Map> siteRuleMap = ruleMap.get(ContractRule.CONTRACT_RULE_Site.getName()); //查询报备列表 List reportNumbers = reportMapper.selectNumberList(AuditStatus_Pass, DateUtils.getDate()); //查询30天内所有未扣分、审核通过的工单 // 获取当前日期 LocalDateTime endTime = LocalDateTime.now(); // 计算30天前的日期 LocalDateTime startTime = endTime.minusDays(30); List workOrders = workOrderMapper.selectPassOrder(startTime, endTime, WorkOrderStatusEnum.AUDITING_SUCCESS.getValue(), "审核通过"); for (WorkOrderVO workOrder : workOrders) { //检测是否报备过 if (!CollectionUtils.isEmpty(reportNumbers)) { if(reportNumbers.contains(workOrder.getSerialNumber())) continue; } String errorType = workOrder.getErrorType(); //存储故障 录像或图片访问异常 if (ErrorType.VIDEO_NONE.getValue().equals(errorType) || ErrorType.PIC_URLABNORMAL.getValue().equals(errorType)) { if (!CollectionUtils.isEmpty(storeRuleMap)) { storeRuleMap.forEach((contractId, rules) -> { Integer unitId = rules.get(0).getUnitId(); //找到对应的规则 if (workOrder.getUnitId().equals(unitId)) { //工单下发时间 Date createTime = workOrder.getDistributeTime(); Date auditTime = workOrder.getAuditTime(); double diffTime = (double) (auditTime.getTime() - createTime.getTime()) / (1000 * 60 * 60); //选择时间范围内的规则 for (CalculateRuleVO rule : rules) { if (checkRange(rule.getMin(), rule.getMax(), new BigDecimal(diffTime))) { double deductScore = rule.getCalcFraction() * Math.ceil(diffTime); ContractScore contractScore = getContractScore(rule, deductScore, Math.round(diffTime * 100) / 100 + "", Remark + "工单编号为:" + workOrder.getWorkOrderNo() + "处理超时,扣除" + deductScore + "分"); contractScoreList.add(contractScore); workOrderList.add(workOrder.getWorkOrderNo()); } } } }); } } //前端感知源治理工作(时钟同步规则、OSD规则、一机一档规则) if (ErrorType.MONITOR_UNQUALIFY.getValue().equals(errorType) || ErrorType.OSD_ERROR.getValue().equals(errorType) || ErrorType.CLOCK_SKEW.getValue().equals(errorType)) { if (!CollectionUtils.isEmpty(monitorRuleMap)) { monitorRuleMap.forEach((contractId, rules) -> { Integer unitId = rules.get(0).getUnitId(); //找到对应的规则 if (workOrder.getUnitId().equals(unitId)) { //工单下发时间 Date createTime = workOrder.getDistributeTime(); Date auditTime = workOrder.getAuditTime(); double diffTime = (double) (auditTime.getTime() - createTime.getTime()) / (1000 * 60 * 60); //选择时间范围内的规则 for (CalculateRuleVO rule : rules) { if (checkRange(rule.getMin(), rule.getMax(), new BigDecimal(diffTime))) { double deductScore = rule.getCalcFraction(); ContractScore contractScore = getContractScore(rule, deductScore, Math.round(diffTime * 100) / 100 + "", Remark + "工单编号为:" + workOrder.getWorkOrderNo() + "处理超时,扣除" + deductScore + "分"); contractScoreList.add(contractScore); workOrderList.add(workOrder.getWorkOrderNo()); } } } }); } } //点位异常情况处理(镜头异常、摄像头遮挡等) if (ErrorType.SCREEN_COLOR_DEVIATION.getValue().equals(errorType) || ErrorType.SNOW_STORM.getValue().equals(errorType) || ErrorType.STRIPE_INTERFERENCE.getValue().equals(errorType) || ErrorType.SCREEN_OCCLUSION.getValue().equals(errorType) || ErrorType.ABNORMAL_CLARITY.getValue().equals(errorType) || ErrorType.ABNORMAL_BRIGHTNESS.getValue().equals(errorType)) { if (!CollectionUtils.isEmpty(monitorRuleMap)) { siteRuleMap.forEach((contractId, rules) -> { Integer unitId = rules.get(0).getUnitId(); //设备是否是该公司运维 if (workOrder.getUnitId().equals(unitId)) { //工单下发时间 Date createTime = workOrder.getDistributeTime(); Date auditTime = workOrder.getAuditTime(); double diffTime = (double) (auditTime.getTime() - createTime.getTime()) / (1000 * 60 * 60); //选择时间范围内的规则 for (CalculateRuleVO rule : rules) { if (checkRange(rule.getMin(), rule.getMax(), new BigDecimal(diffTime))) { double deductScore = 0d; if (ContractRule.CONTRACT_RULE_Store_48H.getName().equals(rule.getRuleCondition())) { //计算超时天数 int day = (int) ((diffTime - 48) / 24 + 1); deductScore = rule.getCalcFraction() * (day); } else { deductScore = rule.getCalcFraction(); } ContractScore contractScore = getContractScore(rule, deductScore, Math.round(diffTime * 100) / 100 + "", Remark + "工单编号为:" + workOrder.getWorkOrderNo() + "处理超时,扣除" + deductScore + "分"); contractScoreList.add(contractScore); workOrderList.add(workOrder.getWorkOrderNo()); } } } }); } } } contractScoreService.saveBatch(contractScoreList); if (!CollectionUtils.isEmpty(workOrderList)) { //修改工单扣分状态为已扣分 UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.in("work_order_no", workOrderList); updateWrapper.set("deduct", 1); workOrderMapper.update(null, updateWrapper); } log.info("结束执行工单扣分"); } /** * 不定期检查数据 扣除积分 * 每天一次随机数判断成功就执行 * 海康取人脸车辆 */ public void randomDeductPic() { Random random = new Random(); //给定随机范围 int number = random.nextInt(randomSize); if (number == 0) { log.info("开始抽查图片完整状态"); //准备批量打分的集合 List contractScoreList = new ArrayList<>(); //查询报备列表 List reportNumbers = reportMapper.selectNumberList(AuditStatus_Pass, DateUtils.getDate()); Date date = DateUtils.getDay(2024, 7, 13); //查图片完整性规则 获取key为合同id,value为规则的map Map> contractMap = contractMapper.getCalculateRule(new Date()).stream() .filter(calculateRuleVO -> ContractRule.CONTRACT_RULE_PicComplete.getName().equals(calculateRuleVO.getRuleName())) .collect(Collectors.groupingBy(CalculateRuleVO::getContractId)); //判断车辆、人脸图片是否可用 Query query = new Query(Criteria .where("mongoCreateTime").gte(DateUtils.getDayStart(date)).lt(DateUtils.getDayEnd(date))); List picAccessResults = mongoTemplate.find(query, PicAccessResult.class); List serialNumbers = picAccessResults.stream().map(PicAccessResult::getExternalIndexCode).collect(Collectors.toList()); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.in("serial_number", serialNumbers); //获取公司所运维的设备集合,key为unitId value为设备国标码集合 Map> unitMonitorMap = ywPointMapper.selectList(queryWrapper).stream() .collect(Collectors.groupingBy(YwPoint::getUnitId, Collectors.mapping( YwPoint::getSerialNumber, Collectors.toList()))); if (!CollectionUtils.isEmpty(contractMap)) { contractMap.forEach((contractId, ruleList) -> { boolean deduct = false; String serialNumber = null; //此规则对应的unitId均相等 CalculateRuleVO ruleVO = ruleList.get(0); Integer unitId = ruleVO.getUnitId(); List monitorList = unitMonitorMap.get(Long.parseLong(unitId + "")); for (PicAccessResult picAccessResult : picAccessResults) { //判断是否报备过 if (!CollectionUtils.isEmpty(reportNumbers)) { if(reportNumbers.contains(picAccessResult.getExternalIndexCode())) continue; } //判断是否是该公司运维 if (monitorList.contains(picAccessResult.getExternalIndexCode())) { //存在大图不可用数据量,需要扣减 if (picAccessResult.getBigDisableCount() > 0) { deduct = true; serialNumber = picAccessResult.getExternalIndexCode(); break; } } } if (deduct) { //需要扣除的分数,此规则只有一条不需要判断范围 Double deductScore = ruleVO.getCalcFraction(); ContractScore contractScore = getContractScore(ruleVO, deductScore, "1", Remark + "国标码为:" + serialNumber + "时间:" + new Date() + "存在大图不可用数据"); contractScoreList.add(contractScore); } }); } contractScoreService.saveBatch(contractScoreList); log.info("结束抽查图片完整状态"); } } /** * 不定期检查数据 扣除积分 * 每天一次随机数判断成功就执行 * 优云取录像 */ public void randomDeductVideo() { Random random = new Random(); //给定随机范围 int number = random.nextInt(randomSize); if (number == 0) { log.info("开始抽查录像完整状态"); //准备批量打分的集合 List contractScoreList = new ArrayList<>(); //查询报备列表 List reportNumbers = reportMapper.selectNumberList(AuditStatus_Pass, DateUtils.getDate()); Date date = DateUtils.getDay(2024, 7, 13); //查图片完整性规则 获取key为合同id,value为规则的map Map> contractMap = contractMapper.getCalculateRule(new Date()).stream() .filter(calculateRuleVO -> ContractRule.CONTRACT_RULE_VideoRecord.getName().equals(calculateRuleVO.getRuleName())) .collect(Collectors.groupingBy(CalculateRuleVO::getContractId)); //取录像数据 Query query = new Query(Criteria .where("mongoCreateTime").gte(DateUtils.getDayStart(date)).lt(DateUtils.getDayEnd(date))); List recordMetaDSumResults = mongoTemplate.find(query, RecordMetaDSumResult.class); List serialNumbers = recordMetaDSumResults.stream().map(RecordMetaDSumResult::getDeviceId).collect(Collectors.toList()); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.in("serial_number", serialNumbers); //获取公司所运维的设备集合,key为unitId value为设备国标码集合 Map> unitMonitorMap = ywPointMapper.selectList(queryWrapper).stream() .collect(Collectors.groupingBy(YwPoint::getUnitId, Collectors.mapping( YwPoint::getSerialNumber, Collectors.toList()))); if (!CollectionUtils.isEmpty(contractMap)) { contractMap.forEach((contractId, ruleList) -> { //此规则对应的unitId均相等 CalculateRuleVO ruleVO = ruleList.get(0); Integer unitId = ruleVO.getUnitId(); List monitorList = unitMonitorMap.get(Long.parseLong(unitId + "")); for (RecordMetaDSumResult result : recordMetaDSumResults) { //判断是否报备过 if (!CollectionUtils.isEmpty(reportNumbers)) { if(reportNumbers.contains(result.getDeviceId())) continue; } //判断是否是该公司运维 if (monitorList.contains(result.getDeviceId())) { //录像状态不完整 if (!Objects.equals(result.getRecordStatus(), ApiConstants.UY_RecordStatus_Integrity)) { for (CalculateRuleVO calculateRuleVO : ruleList) { Double max = calculateRuleVO.getMax(); Double min = calculateRuleVO.getMin(); //判断范围在哪个区间 if (checkRange(min, max, BigDecimal.valueOf(result.getMissDuration()))) { if (calculateRuleVO.getNum() == null) { calculateRuleVO.setNum(1); } else { calculateRuleVO.setNum(calculateRuleVO.getNum() + 1); } } } } } } for (CalculateRuleVO calculateRuleVO : ruleList) { if (calculateRuleVO.getNum() > 0) { //需要扣除的分数,此规则只有一条不需要判断范围 double deductScore = calculateRuleVO.getCalcFraction() * calculateRuleVO.getNum(); ContractScore contractScore = getContractScore(calculateRuleVO, deductScore, calculateRuleVO.getNum() + "", Remark + calculateRuleVO.getNum() + "路设备违反规则"); contractScoreList.add(contractScore); } } }); } contractScoreService.saveBatch(contractScoreList); log.info("结束抽查录像完整状态"); } } private boolean checkRange(Double min, Double max, BigDecimal index) { if (index == null) { return false; } if (max == null && min == null) { return false; } if (max != null && index.setScale(0, RoundingMode.DOWN).compareTo(new BigDecimal(max)) > 0) { return false; } if (min != null && index.setScale(0, RoundingMode.UP).compareTo(new BigDecimal(min)) < 0) { return false; } return true; } private ContractScore getContractScore(CalculateRuleVO rule, double deductScore, String num, String remark) { ContractScore contractScore = new ContractScore(); contractScore.setContractId(Long.parseLong(rule.getContractId() + "")); contractScore.setAuditingStatus(AuditingStatus.PASS); contractScore.setAuditingTime(new Date()); contractScore.setAuditingUser(Remark); contractScore.setUnitId(Long.parseLong(rule.getUnitId() + "")); contractScore.setRuleId(Long.parseLong(rule.getId() + "")); contractScore.setRuleIds("0," + rule.getId()); contractScore.setNum(num); contractScore.setDeductCategory(rule.getDeductCategory().getDesc()); contractScore.setScore(new BigDecimal(deductScore)); contractScore.setRuleName(rule.getRuleName() + "/" + rule.getRuleCondition()); contractScore.setCreateTime(new Date()); contractScore.setUpdateTime(new Date()); contractScore.setRemark(remark); return contractScore; } }