package com.ycl.platform.service.impl; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ycl.config.PlatformConfig; import com.ycl.config.ServerConfig; import com.ycl.exception.ServiceException; import com.ycl.platform.domain.entity.*; import com.ycl.platform.domain.form.*; import com.ycl.platform.domain.query.*; import com.ycl.platform.domain.vo.*; import com.ycl.platform.domain.vo.screen.ScreenWorkOrderVO; import com.ycl.platform.domain.vo.screen.WorkOrderRegionVO; import com.ycl.platform.domain.vo.screen.WorkOrderTotalVO; import com.ycl.platform.mapper.*; import com.ycl.platform.service.NotifyService; import com.ycl.platform.service.WorkOrderAuditingRecordService; import com.ycl.platform.service.WorkOrderService; import com.ycl.platform.service.YwPointService; import com.ycl.platform.wvp.StreamContent; import com.ycl.platform.wvp.WVPResult; import com.ycl.system.Result; import com.ycl.system.domain.SysConfig; import com.ycl.system.entity.SysDictData; import com.ycl.system.mapper.SysConfigMapper; import com.ycl.system.mapper.SysDictDataMapper; import com.ycl.system.model.LoginUser; import com.ycl.system.page.PageUtil; import com.ycl.utils.DateUtils; import com.ycl.utils.SecurityUtils; import com.ycl.utils.http.HttpUtils; import com.ycl.utils.redis.RedisCache; import com.ycl.utils.uuid.IdUtils; import constant.Constants; import constant.RedisConstant; import enumeration.general.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.bytedeco.javacv.*; import org.bytedeco.opencv.global.opencv_imgcodecs; import org.bytedeco.opencv.opencv_core.Mat; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * 工单 服务实现类 * * @author xp * @since 2024-03-05 */ @Slf4j @Service @RequiredArgsConstructor public class WorkOrderServiceImpl extends ServiceImpl implements WorkOrderService { private final YwPointService ywPointService; private final WorkOrderAuditingRecordMapper workOrderAuditingRecordMapper; private final WorkOrderAuditingRecordService workOrderAuditingRecordService; private final WorkOrderYwConditionRecordMapper workOrderYwConditionRecordMapper; private final NotifyService notifyService; private final WorkOrderDistributeRecordMapper workOrderDistributeRecordMapper; private final WorkOrderErrorTypeServiceImpl workOrderErrorTypeService; private final SysConfigMapper configMapper; private final ReportMapper reportMapper; private final WorkOrderCheckImgMapper workOrderCheckImgMapper; @Value("${rtsp.server:http://127.0.0.1:7788}") private String rtspServer; private final String DISTRIBUTE_LOCK_KEY = "distributeLock"; private final static String IMPORTANT = "important"; @Autowired private RedisCache redisCache; @Override @Transactional(rollbackFor = Exception.class) public synchronized Boolean innerAddWorkOrder(List workOrderList) { int total = workOrderList.size(); workOrderList.stream().filter(item -> { return StringUtils.hasText(item.getSerialNumber()) && Objects.nonNull(item.getStatus()) && !CollectionUtils.isEmpty(item.getErrorTypeList()); }); if (CollectionUtils.isEmpty(workOrderList)) { return Boolean.TRUE; } // 根据国标码去重 workOrderList = workOrderList.stream() .collect(Collectors.toMap( WorkOrder::getSerialNumber, p -> p, (existing, replacement) -> existing // 冲突时保留第一个 )).values().stream().collect(Collectors.toList()); List serialNumberList = workOrderList.stream().map(WorkOrder::getSerialNumber).collect(Collectors.toList()); // 查出数据库中国标码对应的未完成的工单 List inDatabaseWorkOrderList = baseMapper.getNotFinishedWorkOrders(serialNumberList); inDatabaseWorkOrderList.stream().forEach(item -> { if (StringUtils.hasText(item.getErrorType())) { item.setErrorTypeList(List.of(item.getErrorType().split(","))); } else { item.setErrorTypeList(new ArrayList<>(1)); } }); Map mapping = inDatabaseWorkOrderList.stream().collect((Collectors.toMap(WorkOrder::getSerialNumber, workOrder -> workOrder))); List waitAddList = new ArrayList<>(48); List waitAddErrorTypeList = new ArrayList<>(48); Integer updateNum = 0; Date now = new Date(); // 因故障类型不一致而要更新状态的工单 List willUpdateStatusWorkOrderList = new ArrayList<>(48); // 更改工单类型而要增加的系统运维处理信息 List willAddMsg = new ArrayList<>(48); // 即将要添加的错误类型 List willAddErrorType = new ArrayList<>(96); for (WorkOrder workOrder : workOrderList) { WorkOrder databaseWorkOrder = mapping.get(workOrder.getSerialNumber()); if (Objects.nonNull(databaseWorkOrder)) { List errorNameList = databaseWorkOrder.getErrorTypeList(); List errorTypes = workOrder.getErrorTypeList(); if (errorNameList.containsAll(errorTypes)) { // 如果,国标码、故障类型都一样,则跳过不处理 continue; } else { for (String errorType : errorTypes) { if (!errorNameList.contains(errorType)) { // 错误类型不一样,就新增一个错误类型,并且重置工单状态为待处理 WorkOrderErrorType workOrderErrorType = new WorkOrderErrorType(); workOrderErrorType.setWorkOrderNo(databaseWorkOrder.getWorkOrderNo()); workOrderErrorType.setCreateTime(now); workOrderErrorType.setUpdateTime(now); workOrderErrorType.setErrorName(errorType); willAddErrorType.add(workOrderErrorType); } } databaseWorkOrder.setStatus(WorkOrderStatusEnum.DISTRIBUTED); databaseWorkOrder.setUpdateTime(now); willUpdateStatusWorkOrderList.add(databaseWorkOrder); updateNum++; // 同时新增一个运维处理信息,表明此工单被调整 WorkOrderYwConditionRecord ywRecord = new WorkOrderYwConditionRecord(); ywRecord.setWorkOrderNo(databaseWorkOrder.getWorkOrderNo()); ywRecord.setCommitUser(1); ywRecord.setYwCondition("故障类型更新,工单状态调整为待处理"); ywRecord.setCreateTime(new Date()); ywRecord.setSysMsg(Boolean.TRUE); willAddMsg.add(ywRecord); } } else { workOrder.setCreateTime(new Date()); workOrder.setUpdateTime(new Date()); // // 如果报备过,使用最新报备的错误类型 // Report report = reportMapper.checkPointReported(workOrder.getSerialNumber()); // if (Objects.nonNull(report)) { // workOrder.setErrorType(report.getErrorType()); // } waitAddList.add(workOrder); } } if (willAddErrorType.size() > 0) { workOrderErrorTypeService.getBaseMapper().addMany(willAddErrorType); } if (willAddMsg.size() > 0) { workOrderYwConditionRecordMapper.insertMany(willAddMsg); } log.info("将要更新的工单数:" + willUpdateStatusWorkOrderList.size()); if (willUpdateStatusWorkOrderList.size() > 0) { this.baseMapper.updateMany(willUpdateStatusWorkOrderList); } if (CollectionUtils.isEmpty(waitAddList)) { return Boolean.TRUE; } List willAddSerialNumber = waitAddList.stream().map(WorkOrder::getSerialNumber).collect(Collectors.toList()); List pointList = new LambdaQueryChainWrapper<>(ywPointService.getBaseMapper()) .select(YwPoint::getUnitId, YwPoint::getSerialNumber, YwPoint::getImportantTag, YwPoint::getImportantTag, YwPoint::getProvinceTag, YwPoint::getImportantCommandImageTag) .in(YwPoint::getSerialNumber, willAddSerialNumber) .list(); Map pointMapping = pointList.stream().collect(Collectors.toMap(YwPoint::getSerialNumber, point -> point)); // 查出重点点位、普通点位的处理时间 SysConfig important = configMapper.checkConfigKeyUnique("important.wordkorder.time"); SysConfig normal = configMapper.checkConfigKeyUnique("normal.wordkorder.alarm.time"); // 如果即将生成工单,但是设备国标码查不到点位,则不添加? List notAddList = new ArrayList<>(); //查redis今日工单数量 int workOrderNum = 0; //UUID作为value,保证上锁的线程自己解锁 String requestId = IdUtils.fastSimpleUUID(); try { for (int i = 0; i < 3; i++) { boolean result = redisCache.acquireLock(RedisConstant.WORKORDER_NUM_LOCK, requestId, 10000); if (result) { //查今日工单量 Object redisNum = redisCache.getCacheObject(RedisConstant.WORKORDER_NUM); workOrderNum = redisNum == null ? 0 : (Integer) redisNum; break; } else { if (i == 2) { log.error("锁被占用"); return Boolean.FALSE; } //等待一段时间后继续 Thread.sleep(5000); } } } catch (InterruptedException e) { log.error("获取锁异常"); return Boolean.FALSE; } for (WorkOrder workOrder : waitAddList) { YwPoint point = pointMapping.get(workOrder.getSerialNumber()); if (Objects.isNull(point)) { notAddList.add(workOrder); continue; } //数字前面补0 workOrderNum++; workOrder.setWorkOrderNo(IdUtils.workOrderNO(now, String.format("%05d", workOrderNum))); if (Objects.nonNull(point.getUnitId())) { workOrder.setUnitId(Math.toIntExact(point.getUnitId())); } if (point.getImportantTag() || point.getImportantCommandImageTag()) { workOrder.setProcessingPeriod(Integer.valueOf(important.getConfigValue())); } else { workOrder.setProcessingPeriod(Integer.valueOf(normal.getConfigValue())); } // 保存错误类型 for (String errorType : workOrder.getErrorTypeList()) { WorkOrderErrorType workOrderErrorType = new WorkOrderErrorType(); workOrderErrorType.setWorkOrderNo(workOrder.getWorkOrderNo()); workOrderErrorType.setCreateTime(now); workOrderErrorType.setUpdateTime(now); workOrderErrorType.setErrorName(errorType); waitAddErrorTypeList.add(workOrderErrorType); } } waitAddList.removeAll(notAddList); if (CollectionUtils.isEmpty(waitAddList)) { return Boolean.TRUE; } //记录工单数 redisCache.setCacheObject(RedisConstant.WORKORDER_NUM, workOrderNum); redisCache.releaseLock(RedisConstant.WORKORDER_NUM_LOCK, requestId); // 保存工单和故障类型 baseMapper.addMany(waitAddList); if (!CollectionUtils.isEmpty(waitAddErrorTypeList)) { workOrderErrorTypeService.getBaseMapper().addMany(waitAddErrorTypeList); } // 如果是直接下发,添加下发记录 if (WorkOrderStatusEnum.DISTRIBUTED.equals(waitAddList.get(0).getStatus())) { ArrayList list = new ArrayList<>(); List distributedRecordList = waitAddList.stream().map(item -> { list.add(item.getSerialNumber()); WorkOrderDistributeRecord workOrderDistributeRecord = new WorkOrderDistributeRecord(); workOrderDistributeRecord.setWorkOrderNo(item.getWorkOrderNo()); workOrderDistributeRecord.setDistributeWay(WorkOrderDistributeWayEnum.DIRECT_DISTRIBUTE); workOrderDistributeRecord.setUserId(1L); workOrderDistributeRecord.setCreateTime(now); workOrderDistributeRecord.setUpdateTime(now); return workOrderDistributeRecord; }).collect(Collectors.toList()); workOrderDistributeRecordMapper.insertBatch(distributedRecordList); // 同步点位状态 ywPointService.updateRecovery(list, 1); } log.info("传入工单总数: {},实际添加工单数:{}, 实际修改工单数:{}", total, waitAddList.size(), updateNum); return Boolean.TRUE; } /** * 添加 * * @param form * @return */ @Override public Result add(WorkOrderForm form) { //查redis今日工单数量 int workOrderNum = 1; //UUID作为value,保证上锁的线程自己解锁 String requestId = IdUtils.fastSimpleUUID(); boolean result = redisCache.acquireLock(RedisConstant.WORKORDER_NUM_LOCK, requestId, 10000); if (result) { //查今日工单量 Object redisNum = redisCache.getCacheObject(RedisConstant.WORKORDER_NUM); workOrderNum = redisNum == null ? 1 : (Integer) redisNum; workOrderNum++; redisCache.setCacheObject(RedisConstant.WORKORDER_NUM, workOrderNum); redisCache.releaseLock(RedisConstant.WORKORDER_NUM_LOCK, requestId); } else { return Result.error("工单正在添加,请稍后再试"); } WorkOrder entity = WorkOrderForm.getEntityByForm(form, null); entity.setCreateTime(DateUtils.getNowDate()); entity.setStatus(WorkOrderStatusEnum.WAIT_DISTRIBUTE); Date now = new Date(); entity.setCreateTime(now); entity.setUpdateTime(now); entity.setWorkOrderNo(IdUtils.workOrderNO(now, String.format("%05d", workOrderNum))); entity.setErrorType(String.join(",", form.getErrorType())); List workOrderErrorTypes = form.getErrorType().stream().map(errorType -> new WorkOrderErrorType(entity.getWorkOrderNo(), errorType)).toList(); workOrderErrorTypeService.getBaseMapper().insertWorkOrderErrorTypeList(workOrderErrorTypes); if (baseMapper.insert(entity) > 0) { return Result.ok("添加成功"); } return Result.error("添加失败"); } /** * 修改 * * @param form * @return */ @Override public Result update(WorkOrderForm form) { WorkOrder entity = baseMapper.selectById(form.getId()); // 为空抛IllegalArgumentException,做全局异常处理 Assert.notNull(entity, "记录不存在"); BeanUtils.copyProperties(form, entity); Date now = new Date(); entity.setUpdateTime(now); if (baseMapper.updateById(entity) > 0) { return Result.ok("修改成功"); } return Result.error("修改失败"); } @Override @Transactional(rollbackFor = Exception.class) public Result auditing(WorkOrderAuditingForm form) { WorkOrder workOrder = baseMapper.selectById(form.getId()); // 工单状态 workOrder.setStatus(form.getAuditingResult()); baseMapper.updateById(workOrder); // 添加一条审核记录 WorkOrderAuditingRecord workOrderAuditingRecord = new WorkOrderAuditingRecord(); workOrderAuditingRecord.setWorkOrderNo(workOrder.getWorkOrderNo()); workOrderAuditingRecord.setAuditingUser(SecurityUtils.getLoginUser().getUserId().intValue()); workOrderAuditingRecord.setResult(form.getAuditingResult().getDesc()); workOrderAuditingRecord.setRemark(form.getAuditingRemark()); workOrderAuditingRecordMapper.insert(workOrderAuditingRecord); // 添加新通知 Notify notify = Notify.genEntityByUnit(NotifyTypeEnum.WORK_ORDER, form.getAuditingResult().getDesc(), workOrder.getUnitId(), UrgentLevelEnum.WARNING, workOrder.getWorkOrderNo()); notifyService.save(notify); // 同步点位状态 if (form.getAuditingResult() == WorkOrderStatusEnum.AUDITING_SUCCESS) { ywPointService.updateRecovery(Collections.singletonList(workOrder.getSerialNumber()), 0); } return Result.ok("操作成功"); } @Override @Transactional(rollbackFor = Exception.class) public Result batchAuditing(WorkOrderBatchAuditingForm form) { // 根据故障类型获取列表 List list = new LambdaQueryChainWrapper<>(baseMapper) .in(WorkOrder::getStatus, WorkOrderStatusEnum.YW_HANDLE.getValue()) .in(WorkOrder::getErrorType, form.getErrorTypes()) .select(WorkOrder::getId, WorkOrder::getUnitId, WorkOrder::getWorkOrderNo, WorkOrder::getSerialNumber) .list(); if (list.isEmpty()) { return Result.error("没有工单可以审核"); } List workOrderNoList = list.stream().map(WorkOrder::getWorkOrderNo).collect(Collectors.toList()); List serialNumbers = list.stream().map(WorkOrder::getSerialNumber).toList(); // 工单状态 LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); lambdaUpdateWrapper.in(WorkOrder::getWorkOrderNo, workOrderNoList); lambdaUpdateWrapper.set(WorkOrder::getStatus, form.getAuditingResult()); baseMapper.update(lambdaUpdateWrapper); // 添加多条审核记录 List workOrderAuditingRecords = new ArrayList<>(); for (String workOrderNo : workOrderNoList) { WorkOrderAuditingRecord workOrderAuditingRecord = new WorkOrderAuditingRecord(); workOrderAuditingRecord.setWorkOrderNo(workOrderNo); workOrderAuditingRecord.setAuditingUser(SecurityUtils.getLoginUser().getUserId().intValue()); workOrderAuditingRecord.setResult(form.getAuditingResult().getDesc()); workOrderAuditingRecord.setRemark(form.getAuditingRemark()); workOrderAuditingRecords.add(workOrderAuditingRecord); } workOrderAuditingRecordService.saveBatch(workOrderAuditingRecords); // 添加新通知 List notifies = new ArrayList<>(); for (WorkOrder workOrder : list) { Notify notify = Notify.genEntityByUnit(NotifyTypeEnum.WORK_ORDER, form.getAuditingResult().getDesc(), workOrder.getUnitId(), UrgentLevelEnum.WARNING, workOrder.getWorkOrderNo()); notifies.add(notify); } // 同步点位状态 if (form.getAuditingResult() == WorkOrderStatusEnum.AUDITING_SUCCESS) { ywPointService.updateRecovery(serialNumbers, 0); } notifyService.saveBatch(notifies); return Result.ok("操作成功"); } @Override @Transactional(rollbackFor = Exception.class) public Result ywCondition(WorkOrderYWConditionForm form) { WorkOrder workOrder = baseMapper.selectById(form.getId()); if (Objects.isNull(workOrder)) { throw new ServiceException("工单不存在"); } // 工单状态 workOrder.setStatus(WorkOrderStatusEnum.YW_HANDLE); workOrder.setYwHandleTime(LocalDateTime.now()); baseMapper.updateById(workOrder); // 添加一条运维情况记录 WorkOrderYwConditionRecord workOrderYwConditionRecord = new WorkOrderYwConditionRecord(); workOrderYwConditionRecord.setWorkOrderNo(workOrder.getWorkOrderNo()); workOrderYwConditionRecord.setCommitUser(SecurityUtils.getLoginUser().getUserId().intValue()); workOrderYwConditionRecord.setYwCondition(form.getYwCondition()); workOrderYwConditionRecord.setYwProofMaterials(form.getYwProofMaterials()); workOrderYwConditionRecord.setSysMsg(Boolean.FALSE); workOrderYwConditionRecordMapper.insert(workOrderYwConditionRecord); return Result.ok("操作成功"); } @Override public List selectYwConditionByYwId(String workOrderNo) { List ywConditionList = workOrderYwConditionRecordMapper.selectYwConditionByYwId(workOrderNo); ywConditionList.stream().forEach(item -> { if (Objects.nonNull(item.getSysMsg()) && item.getSysMsg()) { item.setUnitName("系统消息"); } }); return ywConditionList; } @Override public List selectYwAuditingListByYwId(String workOrderNo) { return new LambdaQueryChainWrapper<>(workOrderAuditingRecordMapper) .eq(WorkOrderAuditingRecord::getWorkOrderNo, workOrderNo) .orderByAsc(WorkOrderAuditingRecord::getCreateTime) .list(); } @Override public Result ywResult(WorkOrderYWResultForm form) { return null; } @Override public Result checkResult(WorkOrderCheckResultForm form) { return null; } /** * 批量删除 * * @param ids * @return */ @Override public Result remove(List ids) { if (baseMapper.deleteBatchIds(ids) > 0) { return Result.ok("删除成功"); } return Result.error("删除失败"); } /** * id删除 * * @param id * @return */ @Override public Result removeById(String id) { if (baseMapper.deleteById(id) > 0) { return Result.ok("删除成功"); } return Result.error("删除失败"); } /** * 分页查询 * * @param query * @return */ @Override public Result page(WorkOrderQuery query) { IPage page = PageUtil.getPage(query, WorkOrderVO.class); query.setUnitId(SecurityUtils.getUnitId()); query.setStart(DateUtils.getDayStart(query.getStart())); query.setEnd(DateUtils.getDayEnd(query.getEnd())); baseMapper.page(page, query); if (!CollectionUtils.isEmpty(page.getRecords())) { page.getRecords().stream().forEach(item -> { if (StringUtils.hasText(item.getErrorType())) { item.setErrorTypeList(List.of(item.getErrorType().split(","))); } if (StringUtils.hasText(item.getImgListStr())) { item.setImgList(List.of(item.getImgListStr().split(","))); } }); } return Result.ok().data(page.getRecords()).total(page.getTotal()); } @Override public Result distributePage(DistributeWorkOrderQuery query) { IPage page = PageUtil.getPage(query, WorkOrderVO.class); baseMapper.distributePage(page, query); return Result.ok().data(page).total(page.getTotal()); } @Override @Transactional public Result distributeFast(DistributeWorkOrderVO data) { // 获取当前时间 LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault()); data.setEnd(now); switch (data.getFastWay()) { case LAST_HOUR: data.setStart(now.minusHours(1)); break; case LAST_TWO_HOUR: data.setStart(now.minusHours(2)); break; case LAST_DAY: data.setStart(now.minusDays(1)); break; default: break; } if (Objects.isNull(data.getStart())) { throw new RuntimeException("无法生成快速下发的时间范围,请选择正确的快速下发方式"); } // 查询符合条件的工单 List list = new LambdaQueryChainWrapper<>(baseMapper) .select(WorkOrder::getSerialNumber, WorkOrder::getWorkOrderNo) .eq(WorkOrder::getStatus, WorkOrderStatusEnum.WAIT_DISTRIBUTE) .eq(Objects.nonNull(data.getUnitId()), WorkOrder::getUnitId, data.getUnitId()) .eq(WorkOrder::getErrorType, data.getErrorType()) .between(WorkOrder::getCreateTime, data.getStart(), data.getEnd()) .orderByDesc(WorkOrder::getCreateTime) .last("limit " + data.getFastNumLimit()) .list(); List workOrderNoList = list.stream().map(WorkOrder::getWorkOrderNo).toList(); List serialNumberList = list.stream().map(WorkOrder::getSerialNumber).toList(); if (workOrderNoList.isEmpty()) { return Result.error("没有符合条件的工单"); } if (!getDistributeLock()) { return Result.error("此刻有人下发中,为避免冲突,请稍后重试"); } try { new LambdaUpdateChainWrapper<>(baseMapper) .set(WorkOrder::getStatus, WorkOrderStatusEnum.DISTRIBUTED) .in(WorkOrder::getWorkOrderNo, workOrderNoList) .update(); addDistributeRecord(workOrderNoList, WorkOrderDistributeWayEnum.FAST_DISTRIBUTE); // 同步点位状态 ywPointService.updateRecovery(serialNumberList, 1); return Result.ok("成功下发" + workOrderNoList.size() + "条工单"); } catch (Exception e) { return Result.error("操作失败"); } finally { distributeUnLock(); } } @Override @Transactional public Result selectedIdsDistribute(DistributeWorkOrderQuery query) { WorkOrderDistributeWayEnum distributeWayEnum = WorkOrderDistributeWayEnum.SELECTED_DISTRIBUTE; if (!getDistributeLock()) { return Result.error("此刻有人下发中,为避免冲突,请稍后重试"); } try { if (query.getWorkOrderNOList().isEmpty()) { query.setWorkOrderNOList(new LambdaQueryChainWrapper<>(baseMapper) .eq(WorkOrder::getStatus, WorkOrderStatusEnum.WAIT_DISTRIBUTE) .eq(Objects.nonNull(query.getUnitId()), WorkOrder::getUnitId, query.getUnitId()) .select(WorkOrder::getWorkOrderNo) .list() .stream() .map(WorkOrder::getWorkOrderNo) .collect(Collectors.toList())); distributeWayEnum = WorkOrderDistributeWayEnum.ALL_DISTRIBUTE; } if (query.getWorkOrderNOList().isEmpty()) { return Result.error("没有工单待下发"); } new LambdaUpdateChainWrapper<>(baseMapper) .set(WorkOrder::getStatus, WorkOrderStatusEnum.DISTRIBUTED) .in(WorkOrder::getWorkOrderNo, query.getWorkOrderNOList()) .update(); addDistributeRecord(query.getWorkOrderNOList(), distributeWayEnum); // 同步点位状态 List serialNumberList = new LambdaQueryChainWrapper<>(baseMapper).select(WorkOrder::getSerialNumber).in(WorkOrder::getWorkOrderNo, query.getWorkOrderNOList()).list().stream().map(WorkOrder::getSerialNumber).toList(); ywPointService.updateRecovery(serialNumberList, 1); return Result.ok("成功下发" + query.getWorkOrderNOList().size() + "条工单"); } catch (Exception e) { return Result.error("操作失败"); } finally { distributeUnLock(); } } /** * 申请工单下发锁 * * @return 工单下发锁申请结果 */ public synchronized Boolean getDistributeLock() { if (Objects.isNull(redisCache.getCacheObject(DISTRIBUTE_LOCK_KEY))) { redisCache.setCacheObject(DISTRIBUTE_LOCK_KEY, "1", 30, TimeUnit.SECONDS); return true; } else { return false; } } /** * 工单下发锁释放 */ public synchronized void distributeUnLock() { redisCache.deleteObject(DISTRIBUTE_LOCK_KEY); } /** * 添加工单下发记录 * * @param workOrderNoList 工单id */ private void addDistributeRecord(List workOrderNoList, WorkOrderDistributeWayEnum distributeWay) { LoginUser loginUser = SecurityUtils.getLoginUser(); workOrderDistributeRecordMapper.insertBatch( workOrderNoList.stream() .map(no -> new WorkOrderDistributeRecord(no, loginUser.getUserId(), distributeWay)) .toList() ); } /** * 根据id查找 * * @param id * @return */ @Override public Result detail(String id) { WorkOrder entity = baseMapper.selectById(id); Assert.notNull(entity, "记录不存在"); WorkOrderVO vo = WorkOrderVO.getVoByEntity(entity, null); return Result.ok().data(vo); } /** * 列表 * * @return */ @Override public Result all() { List entities = baseMapper.selectList(null); List vos = entities.stream() .map( entity -> WorkOrderVO.getVoByEntity(entity, null) ) .collect(Collectors.toList()); return Result.ok().data(vos); } @Override public Result screenWorkOrder(ScreenQuery query) { ScreenWorkOrderVO screen = baseMapper.screenWorkOrder(query); return Result.ok().data(screen); } @Override public Map home(HomeQuery monitorQuery) { Map dataMap = new HashMap<>(); Map data1 = new HashMap<>(); Map data2 = new HashMap<>(); Map data3 = new HashMap<>(); List> home = baseMapper.home(monitorQuery); if (ObjectUtils.isNotEmpty(home)) { for (Map map : home) { if (Objects.nonNull(map.get("dateType")) && StringUtils.hasText(map.get("dateType").toString())) { data1.put(map.get("dateType").toString(), map.get("num1")); data2.put(map.get("dateType").toString(), map.get("num2")); data3.put(map.get("dateType").toString(), map.get("num3")); } } dataMap.put("name", home.get(0).get("name")); } dataMap.put("complete", data1); dataMap.put("waiting", data2); dataMap.put("pending", data3); return dataMap; } @Override public WorkOrderTotalVO workOrderTotal(DashboardQuery dashboardQuery) { return baseMapper.workOrderTotal(dashboardQuery); } @Override public List workOrderRegion(DashboardQuery dashboardQuery) { //初始化所有区域数据 List vos = new ArrayList<>(); for (AreaDeptEnum value : AreaDeptEnum.values()) { WorkOrderRegionVO vo = new WorkOrderRegionVO(); vo.setArea(value.getName()); vo.setDoneNum(0); vo.setTodoNum(0); vos.add(vo); } List workOrderRegionVOS = baseMapper.workOrderRegion(dashboardQuery); for (WorkOrderRegionVO vo : vos) { for (WorkOrderRegionVO workOrder : workOrderRegionVOS) { //赋值 if (vo.getArea().equals(workOrder.getArea())) { BeanUtils.copyProperties(workOrder, vo); } } } return vos; } @Override public synchronized String getFrameImgByDevice(String deviceId, String channelId, String workOrderNo) { String url = String.format(this.rtspServer + "/api/play/start/%s/%s", deviceId, channelId); String result = HttpUtils.sendGet(url); WVPResult wvpResult = JSON.parseObject(result, WVPResult.class); String imgUrl = null; if (wvpResult.getCode() == 0) { JSONObject data = (JSONObject) wvpResult.getData(); String rtspUrl = data.getString("mp4"); // 取mp4地址 if (StringUtils.hasText(rtspUrl)) { System.out.println("目标地址:" + rtspUrl); FFmpegFrameGrabber grabber = null; try { grabber = new FFmpegFrameGrabber(rtspUrl); // grabber.setOption("rtsp_transport", "tcp"); // 使用tcp的方式,不然会丢包很严重 // grabber.setVideoOption("probesize", "10000"); // 设置捕获分析的最大字节 //设置10s超时 grabber.setTimeout(10000); grabber.start(); Frame frame = grabber.grabImage(); // 直接捕获一帧 if (frame != null) { System.out.println("成功捕获一帧"); // 将Frame转换为Mat OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); Mat mat = converter.convertToMat(frame); imgUrl = workOrderNo + "_" + IdUtils.fastSimpleUUID() + ".png"; // 生成图片路径 String imgPath = PlatformConfig.getProfile() + "/" + imgUrl; System.out.println("图片保存地址:" + imgPath); imgUrl = Constants.RESOURCE_PREFIX + "/" + imgUrl; // 保存图片 opencv_imgcodecs.imwrite(imgPath, mat); } else { System.out.println("未捕获到帧"); } } catch (FrameGrabber.Exception e) { e.printStackTrace(); } finally { if (grabber != null) { try { grabber.stop(); // 停止捕获 } catch (FrameGrabber.Exception e) { e.printStackTrace(); } } } } } else { System.out.println("请求失败,错误码:" + wvpResult.getCode() + "--" + wvpResult.getMsg()); } System.out.println("图片URL:" + imgUrl); return imgUrl; } @Override public void saveFrameImgByDevice(String deviceId, String channelId, String workOrderNo) { String url = String.format(this.rtspServer + "/api/play/start/%s/%s", deviceId, channelId); String result = HttpUtils.sendGet(url); WVPResult wvpResult = JSON.parseObject(result, WVPResult.class); String imgUrl = null; if (wvpResult.getCode() == 0) { JSONObject data = (JSONObject) wvpResult.getData(); String rtspUrl = data.getString("fmp4"); // 取mp4地址 if (StringUtils.hasText(rtspUrl)) { System.out.println("目标地址:" + rtspUrl); FFmpegFrameGrabber grabber = null; try { grabber = FFmpegFrameGrabber.createDefault(rtspUrl); //设置10s超时 grabber.setTimeout(10000); grabber.start(); Frame frame = grabber.grabImage(); // 直接捕获一帧 if (frame != null) { System.out.println("成功捕获一帧"); // 将Frame转换为Mat OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); Mat mat = converter.convertToMat(frame); imgUrl = workOrderNo + "_" + IdUtils.fastSimpleUUID() + ".png"; // 生成图片路径 String imgPath = PlatformConfig.getProfile() + "/" + imgUrl; System.out.println("图片保存地址:" + imgPath); imgUrl = Constants.RESOURCE_PREFIX + "/" + imgUrl; // 保存图片 opencv_imgcodecs.imwrite(imgPath, mat); } else { System.out.println("未捕获到帧"); } } catch (FrameGrabber.Exception e) { e.printStackTrace(); } finally { if (grabber != null) { try { grabber.stop(); // 停止捕获 } catch (FrameGrabber.Exception e) { e.printStackTrace(); } // 通常不需要调用release(),因为stop()会处理资源释放 // grabber.release(); // 释放资源 } } } } else { System.out.println("请求失败,错误码:" + wvpResult.getCode()); } System.out.println("图片URL:" + imgUrl); if (StringUtils.hasText(imgUrl)) { WorkOrderCheckImg img = new WorkOrderCheckImg(); img.setWorkOrderNo(workOrderNo); img.setImgUrl(imgUrl); img.setCreateTime(new Date()); workOrderCheckImgMapper.insert(img); } } @Override public List hasErrorWorkOrderList(Date start, Date end) { List list = baseMapper.hasErrorWorkOrderList(start, end); return list; } @Override public void updateImgById(Integer workOrderId, String imgPath) { new LambdaUpdateChainWrapper<>(baseMapper) .eq(WorkOrder::getId, workOrderId) .set(WorkOrder::getYwCheckResult, imgPath) .update(); } @Override public Result processImg(String workOrderNo) { WorkOrder workOrder = new LambdaQueryChainWrapper<>(baseMapper) .eq(WorkOrder::getWorkOrderNo, workOrderNo) .one(); if (Objects.isNull(workOrder)) { throw new RuntimeException("此工单不存在"); } // 运维记录 List workOrderYwConditionRecordVOS = this.selectYwConditionByYwId(workOrderNo); // 审核记录 List workOrderAuditingRecords = this.selectYwAuditingListByYwId(workOrderNo); WorkOrderProcessVO process = new WorkOrderProcessVO(); process.setYwList(workOrderYwConditionRecordVOS); process.setAuditingList(workOrderAuditingRecords); // 查询点位事前事后最新的一条数据是否审核通过 ReportAuditingRecordVO beforeRecord = ywPointService.getReportResult(workOrder.getSerialNumber(), "事前报备"); ReportAuditingRecordVO afterRecord = ywPointService.getReportResult(workOrder.getSerialNumber(), "事后报备"); Date now = new Date(); if (Objects.nonNull(beforeRecord)) { if (now.before(beforeRecord.getBeginCreateTime())) { process.setBeforeReportMsg("事前报备已失效"); } else if (now.after(beforeRecord.getEndCreateTime())) { process.setBeforeReportMsg("事前报备未生效"); } else { process.setBeforeReportMsg("已事前报备"); } } if (Objects.nonNull(afterRecord)) { if (now.before(afterRecord.getBeginCreateTime())) { process.setAfterReportMsg("事后报备已失效"); } else if (now.after(afterRecord.getEndCreateTime())) { process.setAfterReportMsg("事后报备未生效"); } else { process.setAfterReportMsg("已事后报备"); } } return Result.ok().data(process); } @Override public Result detailByNo(String workOrderNo) { WorkOrderDetailVO workOrder = baseMapper.detailByNo(workOrderNo); // 是否报备 boolean hasReport = new LambdaQueryChainWrapper<>(reportMapper) .eq(Report::getSerialNumber, workOrder.getSerialNumber()) .exists(); workOrder.setHasReport(hasReport); // 故障类型 List errorList = workOrderErrorTypeService.getBaseMapper().getErrorList(workOrder.getWorkOrderNo()); List errList = errorList.stream().map(SysDictData::getDictLabel).collect(Collectors.toList()); workOrder.setErrorTypeList(errList); // 检测图片 List imgList = new LambdaQueryChainWrapper<>(workOrderCheckImgMapper) .eq(WorkOrderCheckImg::getWorkOrderNo, workOrderNo) .orderByDesc(WorkOrderCheckImg::getCreateTime) .last("limit 20") .list(); workOrder.setImgList(imgList); return Result.ok().data(workOrder); } @Override public List export(WorkOrderExportQuery query) { query.setUnitId(SecurityUtils.getUnitId()); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if (query.getStart() == null) { query.setStart(format.format(DateUtils.getDayStart(new Date()))); } else { query.setStart(query.getStart() + " 00:00:00"); } if (query.getEnd() == null) { query.setStart(format.format(DateUtils.getDayEnd(new Date()))); } else { query.setEnd(query.getEnd() + " 23:59:59"); } List export = baseMapper.export(query); System.out.println(export); return export; } }