软件发布及追溯系统.md 30 KB

软件发布及追溯系统

项目背景

随着产品不断升级,产品复杂度不断升级,软件烧录和写入技术难度和产品使用的涉及面及软件更新频次不断增加,以往老的管理方式已经无法支撑目前的软件管理的新常态要求

近期集团内各家工厂的几个软件重大投诉如软件版本代码写错和客户使用的IP地址以及ECU代码写错问题频发,引起客户强烈不满和管理层的高度重视

经过讨论,拟在集团工厂层面导入“软件发布及追溯系统”,对嵌入式软件的发布和生产使用进行全面管控

image-20231017191643319

人员情况

由我本人为主要开发人员,项目管理由经理把控。

技术栈

前端:Vue2 Quasar \ 后端:Java Mybatis Plus SpringBoot \ 中间件:Redis \ 文件上传:阿里云OSS \ 数据库:SqlServer \ 其他:C# WindowsService后台程序

计划用时

cinwell website

主要工作

负责前期需求调研,后端框架搭建,数据库建模,基础代码开发,Vue前端框架搭建,页面功能开发。 以及核心功能:软件发布上传,下载,推送,通知等功能开发。 包括进度汇报等。

问题与难点

集团领导派发的项目经理影响力不够,项目难以在TC(技术中心)推进,导致项目在一段时间内停滞,需求反复变更。

成果

一期UAT测试通过,交付客户IT团队进行维护。

预览(初版-测试数据)

软件上传界面(测试数据) Alt text

Alt text

产品簇界面(测试数据) Alt text

详情回顾 Alt text

代码片段

软件发布


package com.ciemis.svms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ciemis.svms.base.exception.BusinessException;
import com.ciemis.svms.base.util.DateUtil;
import com.ciemis.svms.base.util.OssClient;
import com.ciemis.svms.base.ws.SocketManager;
import com.ciemis.svms.entity.*;
import com.ciemis.svms.mapper.SoftItemSoftwareMapper;
import com.ciemis.svms.param.ApprovalSoftwareParam;
import com.ciemis.svms.param.FileParam;
import com.ciemis.svms.param.SoftwareParam;
import com.ciemis.svms.param.SoftwareQuery;
import com.ciemis.svms.properties.OssProperties;
import com.ciemis.svms.properties.RepositoryProperties;
import com.ciemis.svms.service.*;
import com.ciemis.svms.vo.SoftItemSoftwareVo;
import com.ciemis.svms.vo.SoftwareServiceResultVo;
import com.ciemis.svms.vo.SysUserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.socket.WebSocketSession;

import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 软件ITEM 服务实现类
 * </p>
 *
 * @author 杨超杰
 * @since 2021-04-09
 */
@Service
public class SoftItemSoftwareServiceImpl extends ServiceImpl<SoftItemSoftwareMapper, SoftItemSoftware> implements ISoftItemSoftwareService {

    @Autowired
    RedisService redisService;

    @Autowired
    ISoftItemSoftwareService softwareService; //废弃

    @Autowired
    ISoftSoftwareRelationService softwareRelationService;

    @Autowired
    IOssFileRecordService ossFileRecordService;

    @Autowired
    private SimpMessagingTemplate template;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysNoticeService noticeService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    OssProperties properties;

    @Autowired
    IDataPlantService plantService;

    @Autowired
    RepositoryProperties repositoryProperties;

    @Autowired
    IDataProjectService projectService;

    @Autowired
    ISysItemApprovalService approvalService;

    @Autowired
    ISoftPushMachineService pushMachineService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveReleaseSoftware(SysUserVo currentUser, SoftwareParam softwareParam) {
        SoftItemSoftware softItemSoftware = new SoftItemSoftware();
        QueryWrapper<SoftItemSoftware> checkId = new QueryWrapper<>();
        checkId.eq("SoftwareCode", softwareParam.getSoftwareCode());
        if (softwareService.count(checkId) > 0) {
            throw new BusinessException(500, "软件ID重复");
        }

        BeanUtil.copyProperties(softwareParam, softItemSoftware);

        SysUser user = userService.getAccount(softwareParam.getReceiveUser());

        if (Objects.isNull(user)) {
            throw new BusinessException(500, "没有找到制造工程师用户");
        }

        softItemSoftware.setFlag(SoftItemSoftware.Status.CREATE.name());
        softItemSoftware.setPublishDate(LocalDateTime.now());
        softItemSoftware.setPublisher(currentUser.getCode());
        softItemSoftware.setPublisherName(currentUser.getName());
        softItemSoftware.setUploadType(softwareParam.getUploadType());
        softItemSoftware.setServiceStatus(SoftItemSoftware.WindowsServiceStatus.PENDING.name());
        softItemSoftware.setTargetPlant(user.getPlant());
        softItemSoftware.setReceiveUser(user.getCode());
        softItemSoftware.setReceiveName(user.getName());
        softwareService.save(softItemSoftware);

        SysNotice sysNotice = new SysNotice();
        sysNotice.setCreateTime(LocalDateTime.now());
        sysNotice.setFromUser(currentUser.getCode());
        sysNotice.setStatus(SysNotice.Status.CREATE.name());
        sysNotice.setToUser(softItemSoftware.getUploadFileUser());
        sysNotice.setRelationField(String.valueOf(softItemSoftware.getSoftwareId()));
        sysNotice.setType(SysNotice.Type.A.name());
        if (SoftItemSoftware.Type.UPGRADE.name().equals(softwareParam.getUploadType())) {
            sysNotice.setSubject(softItemSoftware.getSoftwareName() + "USB升级包上传");
            sysNotice.setMessage(softItemSoftware.getSoftwareName() + "USB升级包 已经创建,请上传文件");
        } else {
            sysNotice.setSubject(softItemSoftware.getSoftwareName() + "软件上传");
            sysNotice.setMessage(softItemSoftware.getSoftwareName() + "已经创建,请上传文件");
        }

        sysNotice.setFromUsername(currentUser.getName());
        QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
        menuQueryWrapper.eq("Code", "uploadSoftware");
        SysMenu sysMenu = menuService.getOne(menuQueryWrapper);

        sysNotice.setHandleUrl(sysMenu.getPath() + "/" + softItemSoftware.getSoftwareId());

        noticeService.save(sysNotice);

        redisService.addNotice(softItemSoftware.getUploadFileUser(), sysNotice);
        //通知
        WebSocketSession webSocketSession = SocketManager.get(softItemSoftware.getUploadFileUser());
        if (webSocketSession != null) {
            /**
             * 主要防止broken pipe
             */
            JSONObject noticeResult = new JSONObject();
            noticeResult.put("add", sysNotice);
            template.convertAndSendToUser(softItemSoftware.getUploadFileUser(), "/queue/notice", noticeResult.toJSONString());
        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadFileBySoftware(SysUserVo currentUser, SoftwareParam softwareParam) {


        if (softwareParam.getFiles().length <= 0) {
            throw new BusinessException(500, "文件不能为空");
        }

        if (!currentUser.getCode().equals(softwareParam.getUploadFileUser())) {
            throw new BusinessException(500, "当前上传用户与指定上传用户不一致");
        }

        //添加文件至OSS File
        SoftItemSoftware softItemSoftware = softwareService.getById(softwareParam.getSoftwareId());


        if (Objects.isNull(softItemSoftware)) {
            throw new BusinessException(500, "软件信息不存在!");
        }
        BeanUtil.copyProperties(softwareParam, softItemSoftware);
        List<OssFileRecord> ossFileRecordList = new ArrayList<>();
        List<SoftSoftwareRelation> softSoftwareRelations = new ArrayList<>();
        for (int i = 0; i < softwareParam.getFiles().length; i++) {
            FileParam fileParam = softwareParam.getFiles()[i];
            OssFileRecord ossFileRecord = new OssFileRecord();
            ossFileRecord.setFileId(fileParam.getSignature());
            ossFileRecord.setFileName(fileParam.getFileName());
            ossFileRecord.setCreateTime(softItemSoftware.getPublishDate());
            ossFileRecord.setCreateUser(currentUser.getCode());
            ossFileRecord.setSize(fileParam.getSize());
            ossFileRecord.setStatus(OssFileRecord.FileStatus.CREATE.name());
            ossFileRecord.setFileType(fileParam.getSuffix());
            ossFileRecord.setOssUrl(fileParam.getUrl());
            ossFileRecordList.add(ossFileRecord);

            //关系映射

            SoftSoftwareRelation relation = new SoftSoftwareRelation();
            relation.setFileId(ossFileRecord.getFileId());
            relation.setSoftwareCode(softItemSoftware.getSoftwareCode());
            relation.setType(fileParam.getType());
            softSoftwareRelations.add(relation);
        }

        softItemSoftware.setFlag(SoftItemSoftware.Status.UPLOADING.name());

        softwareService.updateById(softItemSoftware);

        //保存oss file record
        ossFileRecordService.saveBatch(ossFileRecordList);

        //保存文件映射
        softwareRelationService.saveBatch(softSoftwareRelations);

        //保存软件信息
        //缓存待上传文件
        List<FileParam> currentWaitFiles = Arrays.stream(softwareParam.getFiles()).collect(Collectors.toList());
        currentWaitFiles.forEach((fileParam -> {
            fileParam.setSoftwareCode(softItemSoftware.getSoftwareCode());
        }));
        redisService.addFile(currentUser.getCode(), currentWaitFiles);
    }

    @Override
    public List<SoftItemSoftwareVo> selectSoftwareItem(SoftwareQuery softItemSoftware) {
        return baseMapper.selectSoftwareItem(softItemSoftware);
    }

    @Override
    public List<SoftItemSoftwareVo> selectSoftwareManagement(SoftwareQuery condition) {
        return baseMapper.selectSoftwareManagement(condition);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSoftware(String userCode, Integer id) {
        SoftItemSoftware softItemSoftware = softwareService.getById(id);
        if (Objects.isNull(softItemSoftware)) {
            throw new BusinessException(500, "找不到软件");
        }
        if (softItemSoftware.getFlag().equals(SoftItemSoftware.Status.CREATE.name()) ||
                softItemSoftware.getFlag().equals(SoftItemSoftware.Status.PENDING.name())) {
            //删除关联
//            QueryWrapper<SoftSoftwareRelation> delSoftRelationWrapper = new QueryWrapper<>();
//            delSoftRelationWrapper.eq("SoftwareCode", softItemSoftware.getSoftwareCode());
//            softwareRelationService.remove(delSoftRelationWrapper);

            //删除软件记录
            softItemSoftware.setFlag(SoftItemSoftware.Status.DELETE.name());

            softwareService.updateById(softItemSoftware);
            //删除OSS文件

            noticeService.deleteNoticeByRelation(String.valueOf(softItemSoftware.getSoftwareId()));

            //删除通知
            redisService.removeNoticeBySoftwareId(String.valueOf(softItemSoftware.getSoftwareId()), softItemSoftware.getUploadFileUser());


            //通知
            WebSocketSession webSocketSession = SocketManager.get(softItemSoftware.getUploadFileUser());
            if (webSocketSession != null) {
                /**
                 * 主要防止broken pipe
                 */
                List<SysNotice> sysNotices = redisService.getAllNotice(userCode);
                sysNotices.removeIf((file) -> file.getRelationField().equals(String.valueOf(softItemSoftware.getSoftwareId())));
                JSONObject noticeResult = new JSONObject();
                noticeResult.put("override", sysNotices);
                template.convertAndSendToUser(softItemSoftware.getUploadFileUser(), "/queue/notice", noticeResult.toJSONString());
            }
            //TODO 软件删除后文件记录不删除 待定
//            ossFileRecordService.remove()

        } else {
            throw new BusinessException(500, "当前状态不允许删除");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSoftware(SysUserVo currentUser, SoftwareParam softwareParam) {
        SoftItemSoftware softItemSoftware = softwareService.getById(softwareParam.getSoftwareId());
        if (Objects.isNull(softItemSoftware)) {
            throw new BusinessException(500, "软件信息不存在");
        }

        if (softwareParam.getFiles().length == 0) {
            BeanUtil.copyProperties(softwareParam, softItemSoftware);
            softwareService.updateById(softItemSoftware);
        } else {
            if (!currentUser.getCode().equals(softwareParam.getUploadFileUser())) {
                throw new BusinessException(500, "当前上传用户与指定上传用户不一致");
            }
//            if (!softItemSoftware.getFlag().equals(SoftItemSoftware.Status.CREATE.name()) ||
//                    !softItemSoftware.getFlag().equals(SoftItemSoftware.Status.PENDING.name())) {
//                throw new BusinessException(500, "当前状态不允许修改");
//            }
//
            if (softItemSoftware.getFlag().equals(SoftItemSoftware.Status.CREATE.name()) ||
                    softItemSoftware.getFlag().equals(SoftItemSoftware.Status.PENDING.name())) {
                List<FileParam> newFiles = Arrays.stream(softwareParam.getFiles()).filter(FileParam::isCreate).collect(Collectors.toList());
                List<FileParam> removeFiles = Arrays.stream(softwareParam.getFiles()).filter(FileParam::isDelete).collect(Collectors.toList());
                List<String> removeRecords = removeFiles.stream().map(FileParam::getSignature).collect(Collectors.toList());
                List<SoftSoftwareRelation> newRelations = new ArrayList<>();
                List<OssFileRecord> newRecords = new ArrayList<>();
                newFiles.forEach((item) -> {
                    SoftSoftwareRelation relation = new SoftSoftwareRelation();
                    relation.setFileId(item.getSignature());
                    relation.setSoftwareCode(softItemSoftware.getSoftwareCode());
                    relation.setType(item.getType());
                    newRelations.add(relation);
                    OssFileRecord ossFileRecord = new OssFileRecord();
                    ossFileRecord.setFileId(item.getSignature());
                    ossFileRecord.setFileName(item.getFileName());
                    ossFileRecord.setCreateTime(softItemSoftware.getPublishDate());
                    ossFileRecord.setCreateUser(currentUser.getCode());
                    ossFileRecord.setSize(item.getSize());
                    ossFileRecord.setStatus(OssFileRecord.FileStatus.CREATE.name());
                    ossFileRecord.setFileType(item.getSuffix());
                    ossFileRecord.setOssUrl(item.getUrl());
                    newRecords.add(ossFileRecord);
                });

                if (!removeFiles.isEmpty()) {
                    softwareRelationService.removeByIds(removeRecords);
                }//添加新的记录
                softwareRelationService.saveBatch(newRelations);

                ossFileRecordService.saveBatch(newRecords);

                if (!removeFiles.isEmpty()) {
                    //删除阿里云OSS旧文件
                    OSSClient client = OssClient.initOSS(properties);
                    List<String> urls = new ArrayList<>();
                    removeFiles.forEach(oss -> {
                        urls.add(softItemSoftware.getBurnAfterItemCode() + '/' + oss.getFileName());
                    });
                    urls.forEach((url) -> {
                        client.deleteObject(properties.getBucket(), url);
                    });
                    //删除旧文件记录
                    ossFileRecordService.removeByIds(removeRecords);
                }
                redisService.addFile(currentUser.getCode(), newFiles);
            } else {
                throw new BusinessException(500, "当前状态不允许修改");
            }
        }
    }

    @Override
    public SoftItemSoftware selectSoftwareByCode(String code) {
        return baseMapper.selectSoftwareByCode(code);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void publishTest(SysUserVo currentUser, Integer id) {
        SoftItemSoftware softItemSoftware = softwareService.getById(id);
        if (Objects.isNull(softItemSoftware)) {
            throw new NullPointerException("软件不存在");
        }
        if (!softItemSoftware.getFlag().equals(SoftItemSoftware.Status.PENDING.name())) {
            throw new BusinessException(500, "当前状态不允许发布");
        }
        softItemSoftware.setFlag(SoftItemSoftware.Status.TEST.name());
        softItemSoftware.setServiceStatus(SoftItemSoftware.WindowsServiceStatus.TEST.name());

        SysNotice sysNotice = new SysNotice();
        sysNotice.setType(SysNotice.Type.B.name());
//        sysNotice.setHandleUrl("/FullScene/ReceiveSoftware/" + softItemSoftware.getSoftwareId());
        sysNotice.setHandleUrl(null);
        sysNotice.setSubject(softItemSoftware.getSoftwareName() + " 已发布");
        sysNotice.setToUser(softItemSoftware.getReceiveUser());
        sysNotice.setStatus(SysNotice.Status.CREATE.name());
        sysNotice.setMessage(softItemSoftware.getSoftwareName() + " 已发布,请接收");
        sysNotice.setFromUsername(currentUser.getName());
        sysNotice.setFromUser(currentUser.getCode());
        sysNotice.setToUser(softItemSoftware.getReceiveUser());
        sysNotice.setCreateTime(LocalDateTime.now());
        sysNotice.setRelationField(String.valueOf(softItemSoftware.getSoftwareId()));
        //审批单

        SysItemApproval approval = new SysItemApproval();
        approval.setFlag(SysItemApproval.Status.TEST.name());
        approval.setSoftwareId(softItemSoftware.getSoftwareId());
        approval.setTopFgItem(softItemSoftware.getBurnAfterItemCode());
        approval.setLastModifyDate(LocalDateTime.now());
        approval.setLastModifyUser(currentUser.getCode());
        approvalService.save(approval);

        softItemSoftware.setApprovalId(approval.getId());

        softwareService.updateById(softItemSoftware);

        noticeService.save(sysNotice);
        //通知
        WebSocketSession webSocketSession = SocketManager.get(softItemSoftware.getReceiveUser());
        if (webSocketSession != null) {
            /**
             * 主要防止broken pipe
             */
            JSONObject noticeResult = new JSONObject();
            noticeResult.put("add", sysNotice);
            template.convertAndSendToUser(softItemSoftware.getUploadFileUser(), "/queue/notice", noticeResult.toJSONString());
        }
        redisService.addNotice(softItemSoftware.getReceiveUser(), sysNotice);
    }

    @Override
    public List<SoftItemSoftware> selectTestSoftwareByME(String status, String userCode) {
        return baseMapper.selectTestSoftwareByME(status, userCode);
    }

    @Override
    public List<SoftItemSoftware> selectSoftwareByPlant(String status, String plant) {
        return baseMapper.selectSoftwareByPlant(status, plant);
    }


    @Override
    public JSONObject getReceiveSoftwareDetail(SysUserVo sysUserVo, Integer softwareId) {
        //检查软件状态
        SoftItemSoftware softItemSoftware = softwareService.getById(softwareId);
        if (Objects.isNull(softItemSoftware)) {
            throw new NullPointerException("没有找到软件信息");
        }
        if (!softItemSoftware.getReceiveUser().equals(sysUserVo.getCode())) {
            throw new BusinessException(500, "你不是指定的接收人");
        }
        if (!softItemSoftware.getFlag().equals(SoftItemSoftware.Status.TEST.name())) {
            throw new BusinessException(500, "该软件当前不能接收");
        }

        DataPlant plant = plantService.getById(sysUserVo.getPlant());
        if (Objects.isNull(plant)) {
            throw new NullPointerException("接收人工厂没有配置");
        }
        Date expiration = new Date(new Date().getTime() + 3600 * 1000);
        //生成文件下载地址
        List<FileParam> fileParams = ossFileRecordService.selectOssFileParam(softwareId);
        JSONArray files = new JSONArray();
        for (FileParam fileParam : fileParams) {
            JSONObject fileItem = JSON.parseObject(JSON.toJSONString(fileParam));
            //oss 下载地址
            URL ossUrl = OssClient.initOSS(properties).generatePresignedUrl(properties.getBucket(), softItemSoftware.getBurnAfterItemCode() + '/' + fileParam.getFileName(), expiration);
            //本地下载地址
            fileItem.put("onlineUrl", ossUrl.toString());
//            String localUrl = repositoryProperties.getProtocol() +
//                    "://" +
//                    plant.getFileServerIp() + ":" +
//                    repositoryProperties.getPort() +
//                    "/" +
//                    softItemSoftware.getBurnAfterItemCode() +
//                    "/" +
//                    fileParam.getFileName();
//            fileItem.put("localUrl", localUrl);
            files.add(fileItem);
        }
        JSONObject result = new JSONObject();
        JSONObject softItemSoftwareObj = JSON.parseObject(JSON.toJSONString(softItemSoftware));
        DataProject project = projectService.getById(softItemSoftware.getProjectId());
        softItemSoftwareObj.put("projectName", project.getCode() + "/" + project.getName());

        result.put("software", softItemSoftwareObj);
        result.put("files", files);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approveSoftware(SysUserVo currentUser, ApprovalSoftwareParam param) {
        SoftItemSoftware softItemSoftware = softwareService.getById(param.getSoftwareId());
        if (Objects.isNull(softItemSoftware)) {
            throw new NullPointerException("没有找到软件信息");
        }
        SysItemApproval approval = approvalService.getById(softItemSoftware.getApprovalId());
        if (Objects.isNull(approval)) {
            throw new NullPointerException("审批单不存在");
        }
        if (!StringUtils.isEmpty(param.getRemark())) {
            approval.setComment(param.getRemark());
        }
        if (!StringUtils.isEmpty(param.getTryOutFileName())) {
            approval.setTestReportFileName(param.getTryOutFileName());
        }
        approval.setLastModifyUser(currentUser.getCode());
        approval.setLastModifyDate(LocalDateTime.now());
        if (param.getStatus().equals(SysItemApproval.Status.REJECT.name())) {
            approval.setFlag(SysItemApproval.Status.REJECT.name());
            softItemSoftware.setFlag(SoftItemSoftware.Status.PENDING.name());
            softItemSoftware.setServiceStatus(SoftItemSoftware.WindowsServiceStatus.DELETE.name());
            softItemSoftware.setLastModifyPushDate(null);
            SysNotice notice = new SysNotice();
            notice.setType(SysNotice.Type.B.name());
            notice.setFromUser(currentUser.getCode());
            notice.setFromUsername(currentUser.getName());
            notice.setToUser(softItemSoftware.getPublisher());
            notice.setStatus(SysNotice.Status.CREATE.name());
            notice.setSubject(softItemSoftware.getSoftwareName() + " 审批被退回");
            notice.setMessage("退回原因 : " + param.getRemark());
            notice.setRelationField(softItemSoftware.getSoftwareId().toString());
            notice.setCreateTime(LocalDateTime.now());
            pushMachineService.deleteBySoftwareId(softItemSoftware.getSoftwareId());
            approvalService.updateById(approval);
            softwareService.updateById(softItemSoftware);
            noticeService.save(notice);
            redisService.addNotice(softItemSoftware.getPublisher(), notice);
            WebSocketSession webSocketSession = SocketManager.get(softItemSoftware.getReceiveUser());
            if (webSocketSession != null) {
                /**
                 * 主要防止broken pipe
                 */
                JSONObject noticeResult = new JSONObject();
                noticeResult.put("add", notice);
                template.convertAndSendToUser(softItemSoftware.getUploadFileUser(), "/queue/notice", noticeResult.toJSONString());
            }
        } else if (param.getStatus().equals(SysItemApproval.Status.APPROVE.name())) {
            //审批通过
            if (param.getEffectiveDate().isEmpty()) {
                throw new NullPointerException("发布时间不能为空");
            }
            if (param.getTryOutFileName().isEmpty()) {
                throw new NullPointerException("试装结论不能为空");
            }
            softItemSoftware.setFlag(SoftItemSoftware.Status.PASS.name());
            softItemSoftware.setEffectiveDate(DateUtil.strToLocalDateTime(param.getEffectiveDate()));
            approval.setFlag(SysItemApproval.Status.APPROVE.name());

            approval.setReleaseDate(DateUtil.strToLocalDateTime(param.getEffectiveDate()));
            approval.setTestReportFileName(param.getTryOutFileName());

            SysNotice notice = new SysNotice();
            notice.setType(SysNotice.Type.B.name());
            notice.setFromUser(currentUser.getCode());
            notice.setFromUsername(currentUser.getName());
            notice.setToUser(softItemSoftware.getPublisher());
            notice.setStatus(SysNotice.Status.CREATE.name());
            notice.setSubject(softItemSoftware.getSoftwareName() + " 已被接收");
            notice.setMessage("正式发布时间:" + param.getEffectiveDate());
            notice.setRelationField(softItemSoftware.getSoftwareId().toString());
            notice.setCreateTime(LocalDateTime.now());
            softwareService.updateById(softItemSoftware);
            approvalService.updateById(approval);
            noticeService.save(notice);
            redisService.addNotice(softItemSoftware.getPublisher(), notice);
            WebSocketSession webSocketSession = SocketManager.get(softItemSoftware.getReceiveUser());
            if (webSocketSession != null) {
                /**
                 * 主要防止broken pipe
                 */
                JSONObject noticeResult = new JSONObject();
                noticeResult.put("add", notice);
                template.convertAndSendToUser(softItemSoftware.getUploadFileUser(), "/queue/notice", noticeResult.toJSONString());
            }
        } else {
            throw new BusinessException(500, "状态异常");
        }
    }

    @Override
    public List<SoftwareServiceResultVo> pingServiceMachine(String plant, String windowsStatus, String status) {
        return baseMapper.pingServiceMachine(plant, windowsStatus, status);
    }

    @Override
    public List<SoftwareServiceResultVo> pingServiceMachine(String plant, String status) {
        return getBaseMapper().pingServiceMachineRelease(plant, status);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pushMachine(SysUserVo currentUser, Integer softwareId, Integer[] machineIds) {
        SoftItemSoftware softItemSoftware = softwareService.getById(softwareId);
        if (Objects.isNull(softItemSoftware)) {
            throw new NullPointerException("软件信息不存在");
        }
        softItemSoftware.setSoftwareId(softwareId);
        List<SoftPushMachine> softPushMachines = new ArrayList<>();
        for (Integer machineId : machineIds) {
            SoftPushMachine machine = new SoftPushMachine();
            machine.setMachineId(machineId);
            machine.setSoftwareId(softwareId);
            machine.setPublishDate(LocalDateTime.now());
            machine.setPublishName(currentUser.getName());
            machine.setPublisher(currentUser.getCode());
            machine.setPlant(softItemSoftware.getTargetPlant());
            softPushMachines.add(machine);
        }
        softItemSoftware.setLastModifyPushDate(LocalDateTime.now());
        pushMachineService.deleteBySoftwareId(softwareId);
        pushMachineService.batchInsert(softPushMachines);
        softwareService.updateById(softItemSoftware);

    }

    @Override
    public List<String> selectBurnItemCode() {
        return baseMapper.selectBurnItemCode();
    }

    @Override
    public List<SoftwareServiceResultVo> pingServiceDelete(String plant, String windowsServiceStatus) {
        return baseMapper.pingServiceDelete(plant, windowsServiceStatus);
    }

    @Override
    public List<SoftwareServiceResultVo> pingServiceMachineRelease(String plant, String status) {
        return baseMapper.pingServiceMachineRelease(plant, status);
    }

    @Override
    public SoftItemSoftware selectPreviousVersionSoftware(String plant, String itemCode) {
        return baseMapper.selectPreviousVersionSoftware(plant, itemCode);
    }

    @Override
    public void firstSerialItemCode(Integer softwareId, String firstSerialNumber) {
        SoftItemSoftware softItemSoftware = softwareService.getById(softwareId);
        softItemSoftware.setFirstProductSerial(firstSerialNumber);
        softwareService.updateById(softItemSoftware);
    }


}