lohir
2024-10-24 99cc61dad74f04a7616c3541f5e87762585abb93
ycl-server/src/main/java/com/ycl/platform/service/impl/WorkOrderServiceImpl.java
@@ -1,7 +1,10 @@
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.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
@@ -11,6 +14,7 @@
import com.ycl.config.ServerConfig;
import com.ycl.exception.ServiceException;
import com.ycl.platform.domain.entity.*;
import com.ycl.platform.domain.excel.PointExport;
import com.ycl.platform.domain.form.*;
import com.ycl.platform.domain.query.*;
import com.ycl.platform.domain.vo.*;
@@ -55,6 +59,17 @@
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
@@ -82,6 +97,7 @@
    private final SysConfigMapper configMapper;
    private final ReportMapper reportMapper;
    private final WorkOrderCheckImgMapper workOrderCheckImgMapper;
    private final WorkOrderWhiteMapper workOrderWhiteMapper;
    @Value("${rtsp.server:http://127.0.0.1:7788}")
    private String rtspServer;
@@ -93,9 +109,13 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    //TODO:Redis加锁,从Redis读取当日工单数据量
    public synchronized Boolean innerAddWorkOrder(List<WorkOrder> workOrderList) {
        int total = workOrderList.size();
        // 查询出白名单列表
        List<String> serialNumbers = workOrderWhiteMapper.selectList().stream().map(WorkOrderWhite::getSerialNumber).collect(Collectors.toList());
        // 遍历工单列表,判断是否在白名单中
        workOrderList.stream().filter(item -> !serialNumbers.contains(item.getSerialNumber()))
                        .collect(Collectors.toList());
        workOrderList.stream().filter(item -> {
            return StringUtils.hasText(item.getSerialNumber()) && Objects.nonNull(item.getStatus()) && !CollectionUtils.isEmpty(item.getErrorTypeList());
        });
@@ -200,6 +220,25 @@
        List<WorkOrder> notAddList = new ArrayList<>();
        //查redis今日工单数量
        int workOrderNum = 0;
        for (WorkOrder workOrder : waitAddList) {
            YwPoint point = pointMapping.get(workOrder.getSerialNumber());
            if (Objects.isNull(point)) {
                notAddList.add(workOrder);
                continue;
            }
            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()));
            }
        }
        waitAddList.removeAll(notAddList);
        if (CollectionUtils.isEmpty(waitAddList)) {
            return Boolean.TRUE;
        }
        //UUID作为value,保证上锁的线程自己解锁
        String requestId = IdUtils.fastSimpleUUID();
        try {
@@ -223,23 +262,11 @@
            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.randomNO(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()));
            }
            workOrder.setWorkOrderNo(IdUtils.workOrderNO(now, String.format("%05d", workOrderNum)));
            // 保存错误类型
            for (String errorType : workOrder.getErrorTypeList()) {
                WorkOrderErrorType workOrderErrorType = new WorkOrderErrorType();
@@ -249,12 +276,8 @@
                workOrderErrorType.setErrorName(errorType);
                waitAddErrorTypeList.add(workOrderErrorType);
            }
            log.info("即将生成的工单:{}",workOrder);
        }
        waitAddList.removeAll(notAddList);
        if (CollectionUtils.isEmpty(waitAddList)) {
            return Boolean.TRUE;
        }
        //记录工单数
        redisCache.setCacheObject(RedisConstant.WORKORDER_NUM, workOrderNum);
        redisCache.releaseLock(RedisConstant.WORKORDER_NUM_LOCK, requestId);
        // 保存工单和故障类型
@@ -292,14 +315,14 @@
    @Override
    public Result add(WorkOrderForm form) {
        //查redis今日工单数量
        int workOrderNum = 1;
        int workOrderNum = 0;
        //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 = redisNum == null ? 0 : (Integer) redisNum;
            workOrderNum++;
            redisCache.setCacheObject(RedisConstant.WORKORDER_NUM, workOrderNum);
            redisCache.releaseLock(RedisConstant.WORKORDER_NUM_LOCK, requestId);
@@ -307,19 +330,26 @@
            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.randomNO(now, String.format("%05d", workOrderNum)));
        entity.setErrorType(String.join(",", form.getErrorType()));
        List<WorkOrderErrorType> workOrderErrorTypes = form.getErrorType().stream().map(errorType -> new WorkOrderErrorType(entity.getWorkOrderNo(), errorType)).toList();
        workOrderErrorTypeService.getBaseMapper().insertWorkOrderErrorTypeList(workOrderErrorTypes);
        if (baseMapper.insert(entity) > 0) {
            return Result.ok("添加成功");
        // 查询出白名单列表
        List<String> serialNumbers = workOrderWhiteMapper.selectList().stream().map(WorkOrderWhite::getSerialNumber).collect(Collectors.toList());
        // 遍历工单列表,判断是否在白名单中
         if (serialNumbers.contains(entity.getSerialNumber())){
            return Result.error("该设备在白名单中,不能添加工单");
        }else {
            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<WorkOrderErrorType> 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("添加失败");
        }
        return Result.error("添加失败");
    }
    /**
@@ -558,7 +588,7 @@
                .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())
                .in(WorkOrder::getErrorType, data.getErrorType())
                .between(WorkOrder::getCreateTime, data.getStart(), data.getEnd())
                .orderByDesc(WorkOrder::getCreateTime)
                .last("limit " + data.getFastNumLimit())
@@ -620,6 +650,7 @@
            ywPointService.updateRecovery(serialNumberList, 1);
            return Result.ok("成功下发" + query.getWorkOrderNOList().size() + "条工单");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return Result.error("操作失败");
        } finally {
            distributeUnLock();
@@ -751,69 +782,76 @@
    @Override
    public String getFrameImgByDevice(String deviceId, String channelId, String workOrderNo) {
        String url = String.format(this.rtspServer + "/api/play/start/%s/%s", deviceId, channelId);
    public synchronized String getFrameImgByDevice(String deviceId, String channelId, String workOrderNo) throws Exception {
        String url = String.format(this.rtspServer + "/api/play/start/img/%s/%s", deviceId, channelId);
        String result = HttpUtils.sendGet(url);
        log.info("拿到取流图片响应结果:" + result);
        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());
        if(wvpResult.getCode() == 0) {
            Object imgUrl = (Object) wvpResult.getData();
            imgUrl = Objects.isNull(imgUrl) ? "" : imgUrl;
            log.info("拿到取流图片:" + imgUrl);
            return (String) imgUrl;
        }
        System.out.println("图片URL:" + imgUrl);
        return imgUrl;
        return null;
//        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 = new FFmpegFrameGrabber(rtspUrl);
////                    grabber.setOption("rtsp_transport", "tcp"); // 使用tcp的方式,不然会丢包很严重
////                    grabber.setVideoOption("probesize", "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) {
    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地址
            String rtspUrl = data.getString("rtsp"); // 取mp4地址
            if (StringUtils.hasText(rtspUrl)) {
                System.out.println("目标地址:" + rtspUrl);
                FFmpegFrameGrabber grabber = null;
@@ -867,13 +905,13 @@
    }
    @Override
    public List<DeviceInfoVO> hasErrorWorkOrderList(Date start, Date end) {
    public List<DeviceInfoVO> hasErrorWorkOrderList (Date start, Date end){
        List<DeviceInfoVO> list = baseMapper.hasErrorWorkOrderList(start, end);
        return list;
    }
    @Override
    public void updateImgById(Integer workOrderId, String imgPath) {
    public void updateImgById (Integer workOrderId, String imgPath){
        new LambdaUpdateChainWrapper<>(baseMapper)
                .eq(WorkOrder::getId, workOrderId)
                .set(WorkOrder::getYwCheckResult, imgPath)
@@ -881,7 +919,7 @@
    }
    @Override
    public Result processImg(String workOrderNo) {
    public Result processImg (String workOrderNo){
        WorkOrder workOrder = new LambdaQueryChainWrapper<>(baseMapper)
                .eq(WorkOrder::getWorkOrderNo, workOrderNo)
                .one();
@@ -922,7 +960,7 @@
    }
    @Override
    public Result detailByNo(String workOrderNo) {
    public Result detailByNo (String workOrderNo){
        WorkOrderDetailVO workOrder = baseMapper.detailByNo(workOrderNo);
        // 是否报备
        boolean hasReport = new LambdaQueryChainWrapper<>(reportMapper)
@@ -942,4 +980,100 @@
        workOrder.setImgList(imgList);
        return Result.ok().data(workOrder);
    }
    @Override
    public List<WorkOrderVO> 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<WorkOrderVO> export = baseMapper.export(query);
        System.out.println(export);
        return export;
    }
    /**
     * 工单白名单列表
     *
     * @param query 查询
     * @return {@link List }<{@link WorkOrderWhite }>
     * @author
     */
    @Override
    public Result selectWorkOrderWhiteList(WorkOrderWhiteQuery query) {
        IPage<WorkOrderWhite> page = PageUtil.getPage(query, WorkOrderWhite.class);
        workOrderWhiteMapper.page(page, query);
        return Result.ok().data(page.getRecords()).total(page.getTotal());
    }
    /**
     * 添加工单白名单
     *
     * @param workOrderWhite 白色工单
     * @return {@link Result }
     * @author
     */
    @Override
    public Result addWorkOrderWhite(WorkOrderWhite workOrderWhite) {
        // 通过设备编码查询设备信息
        YwPoint ywPoint = ywPointService.selectBySerialNumber(workOrderWhite.getSerialNumber());
        // 新增白名单设备记录
        if (ywPoint == null){
            return Result.error("设备不存在");
        }
        // 检查是否已经存在该白名单
        WorkOrderWhite flag = workOrderWhiteMapper.selectBySerialNumber(workOrderWhite.getSerialNumber());
        if (flag != null) {
            return Result.error("该设备已存在白名单");
        } else {
            workOrderWhite.setPointName(ywPoint.getPointName());
            workOrderWhite.setCreateBy(SecurityUtils.getUsername());
            workOrderWhiteMapper.insert(workOrderWhite);
            return Result.ok();
        }
    }
    /**
     * 批量删除工单白名单
     *
     * @param ids ids
     * @author
     */
    @Override
    public Result batchDeleteWorkOrderWhite(List<String> ids) {
        workOrderWhiteMapper.batchDelete(ids);
        return Result.ok();
    }
    /**
     * 批量导入白名单
     *
     * @param dataList 数据列表
     * @author
     */
    @Override
    public void batchImportWhite(List<PointExport> dataList) {
        // 获得所有需要新增的白名单对象
        List<WorkOrderWhite> whitelist = dataList.stream().map(pointExport ->
                        new WorkOrderWhite(pointExport.getSerialNumber(), pointExport.getPointName(), SecurityUtils.getUsername()))
                .collect(Collectors.toList());
        // 获得所有已存在的白名单设备编码
        List<String> serialNumbers = workOrderWhiteMapper.selectList().stream().map(WorkOrderWhite::getSerialNumber).collect(Collectors.toList());
        // 筛选出新增、修改的白名单对象
        List<WorkOrderWhite> updateWhiteList = whitelist.stream().filter(white -> serialNumbers.contains(white.getSerialNumber())).collect(Collectors.toList());
        List<WorkOrderWhite> insertWhiteList = whitelist.stream().filter(white ->!serialNumbers.contains(white.getSerialNumber())).collect(Collectors.toList());
        // 新增/修改白名单设备记录
        updateWhiteList.stream().forEach(white -> workOrderWhiteMapper.updateBySerialNumber(white));
        insertWhiteList.stream().forEach(white -> workOrderWhiteMapper.insert(white));
    }
}