whyclxw
2 天以前 cf9a5039e6db9d1d5963e3fe1a37d00169ec2ef7
src/main/java/com/whyc/service/ProductService.java
@@ -3,17 +3,19 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whyc.dto.FileUrlDTO;
import com.whyc.dto.Response;
import com.whyc.mapper.ProductHistoryMapper;
import com.whyc.mapper.ProductMapper;
import com.whyc.pojo.*;
import com.whyc.util.ActionUtil;
import com.whyc.util.CommonUtil;
import com.whyc.util.FileUtil;
import com.whyc.util.Zip4jUtil;
import com.whyc.util.DateUtil;
import com.whyc.util.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -23,12 +25,19 @@
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Service
public class ProductService {
    @Autowired(required = false)
    private ProductMapper mapper;
    @Autowired(required = false)
    private ProductHistoryMapper hisMapper;
    @Autowired
    private ProductHistoryService phService;
@@ -45,10 +54,16 @@
    @Autowired
    private MaterialService mService;
    @Autowired
    private ProductLockLogService productLockLogService;
    @Autowired
    private MaterialHistoryService materialHistoryService;
    //查询出所有的产品信息(分页加模糊查询<产品的编码,型号,名字,定制表编号>
    public Response getAllProduct(String subCode,String parentCode, String parentName, String parentModel, String customCode, int pageCurr, int pageSize) {
        /*PageHelper.startPage(pageCurr,pageSize);
        QueryWrapper wrapper=new QueryWrapper();
    public Response getAllProduct(String subCode,String parentCode, String parentName, String parentModel, String customCode,Integer enabled, int pageCurr, int pageSize) {
        PageHelper.startPage(pageCurr,pageSize);
        /*QueryWrapper wrapper=new QueryWrapper();
        if(parentCode!=null){
            wrapper.like("parent_code",parentCode);
        }
@@ -67,7 +82,15 @@
        }
        wrapper.orderByAsc("id");
        List list=mapper.selectList(wrapper);*/
        List list=mapper.getAllProduct(subCode,parentCode,parentName,parentModel,customCode);
        List<Product> list=mapper.getAllProduct(subCode,parentCode,parentName,parentModel,customCode,enabled);
        /*list.stream().forEach(product -> {
            //1.查询是否存在该记录
            QueryWrapper qwrapper=new QueryWrapper();
            qwrapper.eq("id",product.getId());
            qwrapper.last("limit 1");
            ProductHistory pHis=hisMapper.selectOne(qwrapper);
            product.setEnabled(pHis.getEnabled());
        });*/
        PageInfo pageInfo=new PageInfo(list);
        return new Response().setII(1,list.size()>0,pageInfo,"返回产品信息");
    }
@@ -126,8 +149,11 @@
        File parentFile = new File(filePath);
        String originalFilename = file.getOriginalFilename();
        File zipFile = new File(filePath + File.separator + originalFilename);
        if (!zipFile.exists()) {
        /*if (!zipFile.exists()) {
            zipFile.mkdirs();
        }*/
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        file.transferTo(zipFile);
        //解压文件夹
@@ -142,23 +168,103 @@
            String fileTempUrl = fileList.get(i);
            //查询需上传的bom数据
            //if (fileTempUrl.contains(".xls") && fileTempUrl.contains("(BOM)")) {
            int excelType = 1; //.xls
            if (fileTempUrl.substring(fileTempUrl.lastIndexOf(File.separator)+1).contains("(BOM).xls")) {
                Workbook workbook = null;
                InputStream inputStream = new FileInputStream(new File(fileTempUrl));
                workbook = WorkbookFactory.create(inputStream);
                inputStream.close();
                List<? extends PictureData> allPictures = workbook.getAllPictures();
                //List<? extends PictureData> allPictures = workbook.getAllPictures();
                if(fileTempUrl.substring(fileTempUrl.lastIndexOf(".")+1).equals("xlsx")) {
                    excelType = 2; //.xlsx
                    /*Collections.sort(allPictures, new Comparator<PictureData>() {
                        @Override
                        public int compare(PictureData o1, PictureData o2) {
                            // Name: /xl/media/image1.png - Content Type: image/png
                            String s1 = o1.toString();
                            int contentTypeIndex = s1.indexOf(" - Content Type");
                            String s1Front = s1.substring(0, contentTypeIndex);
                            String imageNumStr1 = s1Front.substring(s1Front.lastIndexOf("/") + 1, s1Front.lastIndexOf(".")).replace("image", "");
                            String s2 = o2.toString();
                            int contentTypeIndex2 = s2.indexOf(" - Content Type");
                            String s2Front = s2.substring(0, contentTypeIndex2);
                            String imageNumStr2 = s2Front.substring(s2Front.lastIndexOf("/") + 1, s2Front.lastIndexOf(".")).replace("image", "");
                            return Integer.parseInt(imageNumStr1) - Integer.parseInt(imageNumStr2);
                        }
                    });*/
                }
                //取第一个sheet表
                Sheet sheet = workbook.getSheetAt(0);
                //存储图片信息及所在分页
                Map<Integer,PictureData> pictureDataMap = new HashMap<>();
                if(excelType == 1){ //.xls
                    HSSFPatriarch drawingPatriarch = ((HSSFSheet) sheet).getDrawingPatriarch();
                    if(drawingPatriarch!=null) {
                        List<HSSFShape> children = drawingPatriarch.getChildren();
                        for (HSSFShape child : children) {
                            HSSFPicture picture = (HSSFPicture) child;
                            HSSFPictureData pictureData = picture.getPictureData();
                            HSSFClientAnchor anchor = (HSSFClientAnchor) child.getAnchor();
                            //行,不能跨行;
                            int row1 = anchor.getRow1();
                            int row2 = anchor.getRow2();
                            if (row1 == row2) {
                                //不跨行,有效
                                pictureDataMap.put(row1, pictureData);
                            }
                        }
                    }
                }
                else if(excelType == 2){ //.xlsx
                    XSSFDrawing drawingPatriarch = ((XSSFSheet) sheet).getDrawingPatriarch();
                    if(drawingPatriarch!=null) {
                        List<XSSFShape> children = drawingPatriarch.getShapes();
                        for (XSSFShape child : children) {
                            XSSFPicture picture = (XSSFPicture) child;
                            XSSFPictureData pictureData = picture.getPictureData();
                            XSSFClientAnchor anchor = (XSSFClientAnchor) child.getAnchor();
                            //行,不能跨行;
                            int row1 = anchor.getRow1();
                            int row2 = anchor.getRow2();
                            if (row1 == row2) {
                                //不跨行,有效
                                pictureDataMap.put(row1, pictureData);
                            }
                        }
                    }
                }
                Set<Integer> pictureRowSet = new HashSet<>();
                if(!pictureDataMap.isEmpty()) {
                    pictureRowSet = pictureDataMap.keySet();
                }
                int lastRowNum = sheet.getLastRowNum();
                //取第三行,并以第三行开始
                Row row2 = sheet.getRow(1);
                //现在规定为17列
                short lastCellNum = row2.getLastCellNum();
                if(lastCellNum !=18){
                    return response.set(1, false, "上传文件的bom清单列数不对");
                }
                for (int k = 2; k < lastRowNum + 1; k++) {
                    if(k==2){
                        product.setParentCode(sheet.getRow(2).getCell(1).getStringCellValue());
                        if(!originalFilename.contains(product.getParentCode())){
                            return response.set(1,false,"上传的产品压缩包必须包含产品编码");
                        }
                        product.setParentName(sheet.getRow(2).getCell(2).getStringCellValue());
                        product.setParentModel(sheet.getRow(2).getCell(3).getStringCellValue());
                        String parentModel = sheet.getRow(2).getCell(3).getStringCellValue();
                        parentModel = parentModel.trim();
                        String regexStr = "[\\/*?\"|:<>\t]";
                        boolean matches = Pattern.compile(regexStr).matcher(parentModel).find();
                        if(!matches) {
                            product.setParentModel(parentModel);
                        }else{
                            return response.set(1,false,"母料型号包含非法字符:\\/*?\"|:<>或前置空格");
                        }
                    }
                    ProductBom bom = new ProductBom();
                    for (int j = 0; j < lastCellNum; j++) {
@@ -166,10 +272,13 @@
                        Cell cell = row.getCell(j);
                        String cellValue = null;
                        Double cellValueInt = 0d;
                        if (j == 9 || j == 0) {
                        if (j == 9 || j == 0) { //1和10列为数值
                            cellValueInt = cell.getNumericCellValue();
                        } else if (j != 15) {
                        } else if (j != 16) { //16列为图片
                            cellValue = cell.getStringCellValue();
                        }
                        if(cellValue!=null) {
                            cellValue = cellValue.trim();
                        }
                        switch (j) {
                            case 0: {
@@ -217,22 +326,27 @@
                            }
                            break;
                            case 11: {
                                bom.setMaterial(cellValue);
                                bom.setProducerSpecification(cellValue);
                            }
                            break;
                            case 12: {
                                bom.setThickness(cellValue);
                                bom.setMaterial(cellValue);
                            }
                            break;
                            case 13: {
                                bom.setSurfaceDetail(cellValue);
                                bom.setThickness(cellValue);
                            }
                            break;
                            case 14: {
                                bom.setNotes(cellValue);
                                bom.setSurfaceDetail(cellValue);
                            }
                            break;
                            case 15: {
                                bom.setNotes(cellValue);
                            }
                            break;
                            case 16: {
                                /* 弃用,不适用于 图片不按顺序摆放情况
                                //图片,从0开始,到图片size为止
                                int m = k - 2;
                                if (m < allPictures.size()) {
@@ -244,8 +358,36 @@
                                        provingFile.mkdirs();
                                    }
                                    String suffix = pictureData.suggestFileExtension();
                                    String picturePath = approvingPath + File.separator + bom.getSubModel() + "." + suffix;
                                    String picturePathFront = "doc_file" + File.separator + "product_submit" + File.separator + user.getName() + File.separator + dateFormat + File.separator + timeStamp + File.separator + bom.getSubModel() + "." + suffix;
                                    String picturePath = approvingPath + File.separator + bom.getSubModel() + "-bom." + suffix;
                                    String picturePathFront = "doc_file" + File.separator + "product_submit" + File.separator + user.getName() + File.separator + dateFormat + File.separator + timeStamp + File.separator + bom.getSubModel() + "-bom." + suffix;
                                    byte[] data = pictureData.getData();
                                    FileOutputStream fileOutputStream = null;
                                    File pictureFile = new File(picturePath);
                                    fileOutputStream = new FileOutputStream(pictureFile);
                                    fileOutputStream.write(data);
                                    bom.setPictureUrl(picturePathFront);
                                }*/
                                if (!pictureRowSet.isEmpty() && pictureRowSet.contains(k)) {
                                    PictureData pictureData = pictureDataMap.get(k);
                                    //判断物料型号是否包含非法字符(图片会转化为路径)
                                    if(bom.getSubModel()!=null) {
                                        String regexStr = "[\\/*?\"|:<>\t]";
                                        boolean matches = Pattern.compile(regexStr).matcher(bom.getSubModel()).find();
                                        if (matches) {
                                            return response.set(1, false, "型号为"+bom.getSubModel()+"的物料包含非法字符:\\/*?\"|:<>或前置空格");
                                        }
                                    }
                                    //图片存储 product_submit/username/2022-07/
                                    String approvingPath = rootFile + File.separator + "product_submit" + File.separator + user.getName() + File.separator + dateFormat + File.separator + timeStamp;
                                    File provingFile = new File(approvingPath);
                                    if (!provingFile.exists()) {
                                        provingFile.mkdirs();
                                    }
                                    String suffix = pictureData.suggestFileExtension();
                                    String picturePath = approvingPath + File.separator + bom.getSubModel() + "-bom." + suffix;
                                    String picturePathFront = "doc_file" + File.separator + "product_submit" + File.separator + user.getName() + File.separator + dateFormat + File.separator + timeStamp + File.separator + bom.getSubModel() + "-bom." + suffix;
                                    byte[] data = pictureData.getData();
                                    FileOutputStream fileOutputStream = null;
                                    File pictureFile = new File(picturePath);
@@ -256,16 +398,40 @@
                                }
                            }
                            break;
                            case 17: {
                                if(cellValue!=null && !cellValue.trim().equals("")) {
                                    if(cellValue.contains(",") || cellValue.contains(",")){
                                        bom.setRelatedMaterialCodes(cellValue);
                                    }else{
                                        return response.set(1, false, "上传文件的bom清单内替料格式不对");
                                    }
                                }
                            }
                            break;
                        }
                    }
                    bomList.add(bom);
                }
                //追加物料规范校验 暂时去除这个功能
                /*List<MaterialCheckDTO> checkList = bomList.stream().map(bom->{
                    MaterialCheckDTO dto = new MaterialCheckDTO();
                    dto.setNum(bom.getId());
                    dto.setSubCode(bom.getSubCode());
                    dto.setSubName(bom.getSubName());
                    dto.setSubModel(bom.getSubModel());
                    return dto;
                }).collect(Collectors.toList());
                List<MaterialCheckDTO> irregularList = CommonUtil.checkFormat(checkList);
                if(irregularList.size()>0){
                    return response.setII(1,false,irregularList,"名称或型号命名不规范");
                }*/
                product.setBomList(bomList);
            }
        }
        //产品bom对比
        Map<String,List> compareMap = pbhService.parseCompare(baseProduct,product);
        return response.setIII(1, true, product,compareMap, filePath);
        //return response.setIII(1, true, product,compareMap, filePath);
        return response.setIII(1, true, product,compareMap, zipFile.toString());
    }
@@ -282,16 +448,32 @@
        return list;
    }
    @Transactional
    /**
     * 这个接口是进行产品新增,产品bom新增的接口.
     * 新增方式有很多,有直接从zip解析新增产品,也可以基于原有产品复制进行定制等.需要注意兼容!
     * @param product 产品新增,bom新增,产品版本更新
     * @return
     * @throws IOException
     */
    @Transactional(rollbackFor = {RuntimeException.class,Exception.class})
    public Response add(Product product) throws IOException {
        String parentCode = product.getParentCode();
        String customCode = product.getCustomCode();
        String parentModel = product.getParentModel();
        List<ProductBom> bomList = product.getBomList();
        String fileUrl = product.getFileUrl();
        String zipFilePath = product.getFileUrl();
        Date date = new Date();
        String dateStr = DateUtil.YYYY_MM_DD_HH_MM_SS_UNION.format(date);
        Long userId = ActionUtil.getUser().getId();
        boolean isCopyCustom = false;
        Product relatedProduct = null;
        //校验凡是有定制表单号的产品,不能使用已上传过的标准产品编码
        if(customCode!=null && !customCode.trim().equals("")){
            ProductHistory standard = phService.getStandard(parentCode);
            if(standard !=null){
                return new Response().set(1,false,"系统存在此次母物料编码的标准产品,拒绝提交");
            }
        }
        //判断是否为依据产品复制定制的产品
        if(bomList == null){
            bomList = pbService.getBomByProductId(product.getId());
@@ -300,6 +482,11 @@
            if(product.getId() != null){ //关联关系从产品id继承
                relatedProduct = getById(product.getId());
            }
        }
        //不是基于产品复制,则必定存在zip包,必然存在路径
        String fileUrl = null;
        if(!isCopyCustom) {
            fileUrl = zipFilePath.substring(0, zipFilePath.lastIndexOf(File.separator));
        }
        //查询新增产品最新的版本号
        ProductHistory latestProduct = phService.getLatestVersion(parentCode, customCode);
@@ -393,6 +580,103 @@
            }
        }
        //查询是否bomList中有替料
        // 有的话,检查关联表中是否已存在或本版本已生效
        List<MaterialProductHistory> newAddedList = new LinkedList<>();
        List<MaterialProductHistory> versionUpdateList = new LinkedList<>();
        List<MaterialProductHistory> mpListInDB = mphService.getListByParentCodeAndCustomCodeAndSubMaterialIdAndVersion(parentCode,customCode,bomList,currentVersion);
        List<String> subMaterialListInDB = mpListInDB.stream().map(mp->mp.getSubMaterial().getSubCode()+"_"+mp.getSubMaterial().getSubModel()).collect(Collectors.toList());
        bomList.forEach(bom->{
            if(bom.getRelatedMaterialCodes()!=null) {
                String relatedMaterialCodes = bom.getRelatedMaterialCodes().trim();
                if (!relatedMaterialCodes.equals("")) {
                    if(subMaterialListInDB!=null&&subMaterialListInDB.size()>0){
                        if (subMaterialListInDB.contains(bom.getSubCode()+"_"+bom.getSubModel())) { //当前物料有替代料
                            String[] relatedList;
                            if (relatedMaterialCodes.contains(",")) {
                                relatedList = relatedMaterialCodes.split(",");
                            } else {
                                relatedList = relatedMaterialCodes.split(",");
                            }
                            for (String related : relatedList) {
                                bom.setRelatedMaterialCodes(related);
                                boolean exists = false;
                                for (MaterialProductHistory mp : mpListInDB) {
                                    //物料相同,替代料相同
                                    if ((mp.getSubMaterial().getSubCode()+"_"+mp.getSubMaterial().getSubModel()).equals(bom.getSubCode()+"_"+bom.getSubModel())
                                            && mp.getRelatedSubMaterial().getSubCode().equals(related)) {
                                        //只可能存在0 和 1 的情况,因为查询的是 >=上个版本
                                        if (nextVersion - mp.getEVersion() == 0) { //已存在,无需添加
                                            //break;
                                        } else if (nextVersion - mp.getEVersion() == 1) {  //更新到当前版本
                                            mp.setEVersion(nextVersion);
                                            versionUpdateList.add(mp);
                                        }
                                        exists = true;
                                    }
                                }
                                if(!exists) { //不存在相邻及相同的记录版本,新增
                                    MaterialProductHistory newTemp = new MaterialProductHistory();
                                    newTemp.setParentCode(parentCode);
                                    newTemp.setCustomCode(customCode);
                                    newTemp.setSubCode(bom.getSubCode());
                                    Material material = mService.getByCodeAndModel(bom.getSubCode(), bom.getSubModel(),true);
                                    newTemp.setSubMaterialId(material.getId());
                                    newTemp.setSVersion(nextVersion);
                                    newTemp.setEVersion(nextVersion);
                                    newTemp.setQuantity(bom.getQuantity());
                                    //2323-09-08 与杨红兰微信确认<就按照我上传清单的时间,系统里最新的是啥型号,就取什么型号>
                                    Material relatedMaterial = mService.getLastByCode(related);
                                    if(relatedMaterial == null){
                                        throw new RuntimeException("当前替料"+related+",编码在平台中不存在,无法关联替代");
                                    }
                                    newTemp.setMaterialId(relatedMaterial.getId());
                                    newTemp.setCreateTime(date);
                                    newAddedList.add(newTemp);
                                }
                            }
                        }
                        else{
                            String[] relatedList;
                            if (relatedMaterialCodes.contains(",")) {
                                relatedList = relatedMaterialCodes.split(",");
                            } else {
                                relatedList = relatedMaterialCodes.split(",");
                            }
                            for (String related : relatedList) {
                                MaterialProductHistory newTemp = new MaterialProductHistory();
                                newTemp.setParentCode(parentCode);
                                newTemp.setCustomCode(customCode);
                                newTemp.setSubCode(bom.getSubCode());
                                Material material = mService.getByCodeAndModel(bom.getSubCode(), bom.getSubModel(),true);
                                newTemp.setSubMaterialId(material.getId());
                                newTemp.setSVersion(nextVersion);
                                newTemp.setEVersion(nextVersion);
                                newTemp.setQuantity(bom.getQuantity());
                                //2323-09-08 与杨红兰微信确认<就按照我上传清单的时间,系统里最新的是啥型号,就取什么型号>
                                Material relatedMaterial = mService.getLastByCode(related);
                                if(relatedMaterial == null){
                                    throw new RuntimeException("当前替料"+related+",编码在平台中不存在,无法关联替代");
                                }
                                newTemp.setMaterialId(relatedMaterial.getId());
                                newTemp.setCreateTime(date);
                                newAddedList.add(newTemp);
                            }
                        }
                    }
                }
            }
        });
        //执行更新
        if(newAddedList.size()!=0) {
            mphService.insertBatch(newAddedList);
        }
        if(versionUpdateList.size()!=0) {
            mphService.updateVersionBatch(versionUpdateList);
        }
        //将产品文件复制至正式路径
        //文件转移,未跟子件挂钩的所有图纸图片转移到产品版本下:doc_file/product/{产品型号}/standard或者{customCode}}/{version}/
        //跟子件挂钩的转移到子件图纸下:doc_file/material/
@@ -414,14 +698,15 @@
            his.setVersionTime(product.getVersionTime());
            his.setVersion(1);
            his.setSubVersionMax(1);
            his.setEnabled(1);
            //上传后的最初始使能状态为-1
            //第一次解锁后,后续的锁定和解锁在0和1之间切换
            his.setEnabled(-1);
            phService.insertAndUpdateEnabled(his);
            //phService.insert(his);
            // -> product
            // -> product 现有产品和产品bom需要插入,version默认为-1,同时要做删除原来的旧版本
            product.setId(his.getId());
            product.setCreateTime(date);
            product.setVersion(1);
            //insert(product);
            product.setVersion(-1);
            deleteAndInsert(product);
            // -> bom
            bomList.forEach(bom-> {
@@ -436,6 +721,13 @@
                bomHistory.setProductId(his.getId());
                bomHistory.setMaterialId(bom.getMaterialId());
                bomHistory.setQuantity(bom.getQuantity());
                bomHistory.setCategory(bom.getCategory());
                bomHistory.setMaterial(bom.getMaterial());
                bomHistory.setNotes(bom.getNotes());
                bomHistory.setProducer(bom.getProducer());
                bomHistory.setProducerSpecification(bom.getProducerSpecification());
                bomHistory.setSurfaceDetail(bom.getSurfaceDetail());
                bomHistory.setThickness(bom.getThickness());
                bomHistory.setSubSVersion(1);
                bomHistory.setSubEVersion(1);
                bomHistoryList.add(bomHistory);
@@ -445,7 +737,7 @@
            File file = new File(fileUrl);
            List<String> fileUrlList = new LinkedList<>();
            List<String> excelExcludeUrlList = null;
            List<String> picUrlList = null;
            List<String> picUrlList = new LinkedList<>();
            //存于物料下,bom内有对应
            List<String> materialUrlList = new LinkedList<>();
            //存于产品下,bom内没对应
@@ -456,21 +748,32 @@
            fileUrlList = FileUtil.getStaticFilePath(file, fileUrlList);
            //图纸dwg 子件/产品
            excelExcludeUrlList = fileUrlList.stream().filter(url -> !(url.contains(".xls") || url.contains(".xlsx"))).collect(Collectors.toList());
            picUrlList = fileUrlList.stream().filter(url -> url.contains(".png") || url.contains(".jpeg")).collect(Collectors.toList());
            //picUrlList = fileUrlList.stream().filter(url -> url.contains(".png") || url.contains(".jpeg")).collect(Collectors.toList());
            List<ProductBom> finalBomList = bomList;
            excelExcludeUrlList.forEach(excelExcludeUr -> {
                boolean existFlag = false;
                for (ProductBom bom : finalBomList) {
                    String filename = excelExcludeUr.substring(excelExcludeUr.lastIndexOf(File.separator) + 1, excelExcludeUr.length() - 4);
                    String filename = excelExcludeUr.substring(excelExcludeUr.lastIndexOf(File.separator) + 1, excelExcludeUr.lastIndexOf("."));
                    String fileFullName = excelExcludeUr.substring(excelExcludeUr.lastIndexOf(File.separator) + 1);
                    String fileSuffix = fileFullName.substring(fileFullName.lastIndexOf("."));
                    if (bom.getSubModel().toUpperCase().equals(filename.toUpperCase()) && excelExcludeUr.substring(excelExcludeUr.lastIndexOf(".")+1).equals("dwg")) {
                        materialUrlList.add(excelExcludeUr);
                        existFlag = true;
                        bom.setDwgUrl("doc_file" + File.separator + "material"
                                + File.separator + fileFullName);
                        bom.setDwgUrl("doc_file" + File.separator + "material" + File.separator + bom.getSubCode() + "-" + bom.getSubModel()
                                + File.separator + filename + "_" + dateStr + fileSuffix);
                        break;
                    }
                    else if((bom.getSubModel().toUpperCase()+"-BOM").equals(filename.toUpperCase()) && (excelExcludeUr.substring(excelExcludeUr.lastIndexOf(".")+1).equals("png") ||excelExcludeUr.substring(excelExcludeUr.lastIndexOf(".")+1).equals("jpeg"))
                    ){
                        picUrlList.add(excelExcludeUr);
                        existFlag = true;
                        bom.setPictureUrl("doc_file" + File.separator + "material" + File.separator + bom.getSubCode() + "-" + bom.getSubModel()
                                + File.separator + filename + "_" + dateStr + fileSuffix);
                        break;
                    }
                }
@@ -479,18 +782,18 @@
                }
            });
            //一定是有对应物料的,从bom内剥离的
            /*//一定是有对应物料的,包含从bom内剥离的(删除掉:上面已经处理)
            picUrlList.forEach(picUrl -> {
                for (ProductBom bom : finalBomList) {
                    String filename = picUrl.substring(picUrl.lastIndexOf(File.separator) + 1, picUrl.lastIndexOf("."));
                    String fileFullName = picUrl.substring(picUrl.lastIndexOf(File.separator) + 1);
                    if (bom.getSubModel().toUpperCase().equals(filename.toUpperCase())) {
                    if ((bom.getSubModel().toUpperCase()+"-BOM").equals(filename.toUpperCase())) {
                        bom.setPictureUrl("doc_file" + File.separator + "material"
                                + File.separator + fileFullName);
                        break;
                    }
                }
            });
            });*/
            //转移路径
            String projectDir = CommonUtil.getProjectDir();
@@ -513,6 +816,10 @@
            if (!materialFile.exists()) {
                materialFile.mkdirs();
            }
            //之前上传的产品bom压缩包,转移到正式版本下留存
            File zipFileNew = new File(productDir + File.separator + zipFilePath.substring(zipFilePath.lastIndexOf(File.separator) + 1));
            FileCopyUtils.copy(new File(zipFilePath), zipFileNew);
            productUrlList.forEach(productUrl -> {
                String fileName = productUrl.substring(productUrl.lastIndexOf(File.separator) + 1);
@@ -523,72 +830,156 @@
                }
            });
            materialUrlList.forEach(materialUrl -> {
                String dwgName = materialUrl.substring(materialUrl.lastIndexOf(File.separator) + 1, materialUrl.length() - 4);
            //物料dwg图纸存到对应的 物料编码+型号 下面
            for (String materialUrl : materialUrlList) {
                try {
                    FileCopyUtils.copy(new File(materialUrl), new File(materialDir + File.separator + dwgName + ".dwg"));
                    String dwgName = materialUrl.substring(materialUrl.lastIndexOf(File.separator) + 1, materialUrl.length() - 4);
                    //确定物料的具体型号
                    String subModel = null;
                    String subCode = null;
                    for (ProductBom bom : bomList) {
                        String bomSubMode = bom.getSubModel();
                        if (bomSubMode.toUpperCase().equals(dwgName.toUpperCase())) {
                            subModel = bomSubMode;
                            subCode = bom.getSubCode();
                            break;
                        }
                    }
                    File dwgFile;
                    if (subModel != null) {
                        dwgFile = new File(materialDir + File.separator + subCode + "-" + subModel + File.separator + dwgName + "_" + dateStr + ".dwg");
                        File dwgDir = new File(materialDir + File.separator + subCode + "-" + subModel);
                        if(!dwgDir.exists()){
                            dwgDir.mkdirs();
                        }
                    } else {
                        dwgFile = new File(materialDir + File.separator + dwgName + "_" + dateStr + ".dwg");
                    }
                    if (!dwgFile.exists()) {
                        FileCopyUtils.copy(new File(materialUrl), dwgFile);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            }
            picUrlList.forEach(picUrl -> {
            for (String picUrl : picUrlList) {
                String picFullName = picUrl.substring(picUrl.lastIndexOf(File.separator) + 1);
                String picSubModel = picFullName.substring(0, picFullName.lastIndexOf("."));
                String picSuffix = picFullName.substring(picFullName.lastIndexOf("."));
                try {
                    FileCopyUtils.copy(new File(picUrl), new File(materialDir + File.separator + picFullName));
                    //确定物料的具体型号和编码
                    String subModel = null;
                    String subCode = null;
                    for (ProductBom bom : bomList) {
                        String bomSubMode = bom.getSubModel();
                        if ((bomSubMode + "-bom").toUpperCase().equals(picSubModel.toUpperCase())) {
                            subModel = bomSubMode;
                            subCode = bom.getSubCode();
                            break;
                        }
                    }
                    File picFile;
                    if (subModel != null) {
                        picFile = new File(materialDir + File.separator + subCode + "-" + subModel + File.separator + picSubModel + "_" + dateStr + picSuffix);
                        File picDir = new File(materialDir + File.separator + subCode + "-" + subModel);
                        if(!picDir.exists()){
                            picDir.mkdirs();
                        }
                    } else {
                        picFile = new File(materialDir + File.separator + picSubModel + "_" + dateStr + picSuffix);
                    }
                    if (!picFile.exists()) {
                        FileCopyUtils.copy(new File(picUrl), picFile);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            }
            //物料表中不存在的(依据:物料编码+物料型号),则添加到物料表中去(包含product这个物料)
            //更新图纸和图片
            List<Material> materialExistList = mService.getListByCodeAndModelList2(bomList);
            //List<String> subCodeList = materialExistList.stream().map(Material::getSubCode).collect(Collectors.toList());
            List<String> subCodeList = materialExistList.stream().map(material -> material.getSubCode()+"/"+material.getSubModel()).collect(Collectors.toList());
            List<Material> materialList = new LinkedList<>();
            bomList.forEach(bom -> {
                if (!subCodeList.contains(bom.getSubCode()+"/"+bom.getSubModel())) {
            //需要更新到物料表中的物料(存在图纸或者图片)
            List<MaterialHistory> materialHistoryList = new LinkedList<>();
            //新物料
            List<Material> newMaterialList = new LinkedList<>();
            //判断物料是否已经存在于物料表中
            List<Material> materialUpdateList = new LinkedList<>();
            for (ProductBom bom : bomList) {
                if (!subCodeList.contains(bom.getSubCode() + "/" + bom.getSubModel())) {
                    Material material = new Material();
                    material.setCategory(bom.getCategory());
                    material.setCreateDate(bom.getCreateDate());
                    material.setCreateDate(date);
                    material.setDwgUrl(bom.getDwgUrl());
                    material.setFileUrl(bom.getFileUrl());
                    material.setMaterial(bom.getMaterial());
                    material.setNotes(bom.getNotes());
                    material.setPictureUrl(bom.getPictureUrl());
                    material.setProducer(bom.getProducer());
                    // TODO 是否要更新同物料编码的老物料状态为0?
                    material.setStatus(1);
                    material.setSubCode(bom.getSubCode());
                    material.setSubModel(bom.getSubModel());
                    material.setSubName(bom.getSubName());
                    material.setSurfaceDetail(bom.getSurfaceDetail());
                    material.setThickness(bom.getThickness());
                    material.setType(bom.getType());
                    material.setUnit(bom.getUnit());
                    material.setUpUserId(userId);
                    materialList.add(material);
                    newMaterialList.add(material);
                } else { //物料已经存在的
                    // 物料历史表是为了存储物料的历史图片和dwg图纸
                    Material material = new Material();
                    if (bom.getPictureUrl() != null) {
                        material.setPictureUrl(bom.getPictureUrl());
                    }
                    if (bom.getDwgUrl() != null) {
                        material.setDwgUrl(bom.getDwgUrl());
                    }
                    if (material.getPictureUrl() != null || material.getDwgUrl() != null) {
                        material.setSubCode(bom.getSubCode());
                        material.setSubModel(bom.getSubModel());
                        materialUpdateList.add(material);
                    }
                }
            });
            }
            //对新增到物料表中的物料,根据 物料编码+物料型号 进行去重处理
            newMaterialList = newMaterialList.stream().filter(distinctByKey(m->m.getSubCode()+"/"+m.getSubModel())).collect(Collectors.toList());
            //母料是否存在
            Material materialDB = mService.getByCodeAndModel(product.getParentCode(), product.getParentModel());
            Material materialDB = mService.getByCodeAndModel(product.getParentCode(), product.getParentModel(),true);
            if (materialDB == null) {
                Material material = new Material();
                material.setSubCode(product.getParentCode());
                material.setSubName(product.getParentName());
                material.setSubModel(product.getParentModel());
                material.setCreateDate(date);
                material.setStatus(1);
                material.setUpUserId(userId);
                materialList.add(material);
                newMaterialList.add(material);
            }
            if(materialList.size()!=0) {
                mService.insertBatch(materialList);
            if(newMaterialList.size()!=0) {
                mService.insertBatch(newMaterialList);
            }
            if(materialUpdateList.size()!=0) {
                mService.updateDwgUrlAndPicUrl(materialUpdateList);
            }
            //更新product_history/product_bom_history/product/product_bom,
            // product的主键沿用对应product_history的
            //根据编码和型号确定物料id并对应quantity,存入数据库.
            //List<Material> bomMaterialList = mService.getListByCodeAndModelList2(bomList);
            List<ProductBom> bomMaterialList = pbService.getListByCodeAndModelList2(bomList);
            //List<ProductBom> bomMaterialList = pbService.getListByCodeAndModelList2(bomList);
            List<Material> existMaterialListWithSameSubCodeAndModel = mService.getSameSubCodeAndModel(bomList);
            List<ProductBom> bomMaterialList;
            bomList.forEach(bom->{
                String codeModelUnionStr = bom.getSubCode() + "/" + bom.getSubModel();
                for (int i = 0; i < existMaterialListWithSameSubCodeAndModel.size(); i++) {
                    Material materialExists = existMaterialListWithSameSubCodeAndModel.get(i);
                    if(codeModelUnionStr.equals(materialExists.getSubCode() + "/" + materialExists.getSubModel())){
                        bom.setId(materialExists.getId());
                        break;
                    }
                }
            });
            bomMaterialList = bomList;
            // -> product_history
            ProductHistory productHistory = new ProductHistory();
            productHistory.setParentCode(product.getParentCode());
@@ -601,12 +992,13 @@
            productHistory.setVersion(nextVersion);
            //版本新增,初始bom子件版本为1
            productHistory.setSubVersionMax(1);
            productHistory.setEnabled(1);
            productHistory.setEnabled(-1);
            phService.insertAndUpdateEnabled(productHistory);
            // -> product
            // -> product 现有产品和产品bom需要插入,version默认为-1,同时要做删除原来的旧版本
            product.setId(productHistory.getId());
            product.setCreateTime(date);
            product.setVersion(nextVersion);
            product.setVersion(-1);
            deleteAndInsert(product);
            // -> product_bom
            List<ProductBom> productBomList = new LinkedList<>();
@@ -615,6 +1007,13 @@
                bom.setProductId(product.getId());
                bom.setMaterialId(bomMaterial.getId());
                bom.setQuantity(bomMaterial.getQuantity());
                bom.setCategory(bomMaterial.getCategory());
                bom.setMaterial(bomMaterial.getMaterial());
                bom.setNotes(bomMaterial.getNotes());
                bom.setProducer(bomMaterial.getProducer());
                bom.setProducerSpecification(bomMaterial.getProducerSpecification());
                bom.setSurfaceDetail(bomMaterial.getSurfaceDetail());
                bom.setThickness(bomMaterial.getThickness());
                bom.setSubVersion(1);
                bom.setCreateDate(date);
@@ -628,6 +1027,13 @@
                bomHistory.setProductId(productHistory.getId());
                bomHistory.setMaterialId(bomMaterial.getId());
                bomHistory.setQuantity(bomMaterial.getQuantity());
                bomHistory.setCategory(bomMaterial.getCategory());
                bomHistory.setMaterial(bomMaterial.getMaterial());
                bomHistory.setNotes(bomMaterial.getNotes());
                bomHistory.setProducer(bomMaterial.getProducer());
                bomHistory.setProducerSpecification(bomMaterial.getProducerSpecification());
                bomHistory.setSurfaceDetail(bomMaterial.getSurfaceDetail());
                bomHistory.setThickness(bomMaterial.getThickness());
                bomHistory.setSubSVersion(1);
                bomHistory.setSubEVersion(1);
                bomHistory.setCreateDate(date);
@@ -635,9 +1041,74 @@
                bomHistoryList.add(bomHistory);
            });
            pbhService.insertBatch(bomHistoryList);
            //插入到物料历史表的,
            // 包含新物料包含图纸图片的,
            // 也包含旧物料包含图纸图片的
            if(newMaterialList.size()>0){
                for (Material material : newMaterialList) {
                    //存在图纸或者图片,就插入历史
                    if(material.getDwgUrl()!=null || material.getPictureUrl()!=null) {
                        MaterialHistory materialHistory = new MaterialHistory();
                        materialHistory.setPictureUrl(material.getPictureUrl());
                        materialHistory.setProductId(productHistory.getId());
                        materialHistory.setDwgUrl(material.getDwgUrl());
                        materialHistory.setUpUserId(userId.intValue());
                        materialHistory.setCreateTime(date);
                        materialHistory.setMaterialId(material.getId());
                        materialHistoryList.add(materialHistory);
                    }
                }
            }
            if(materialUpdateList.size()>0) {
                //更新物料图纸图片的同时,添加新的图纸图片信息到物料历史表中
                for (Material material : materialUpdateList) {
                    MaterialHistory materialHistory = new MaterialHistory();
                    materialHistory.setPictureUrl(material.getPictureUrl());
                    materialHistory.setProductId(productHistory.getId());
                    materialHistory.setDwgUrl(material.getDwgUrl());
                    materialHistory.setUpUserId(userId.intValue());
                    materialHistory.setCreateTime(date);
                    for (Material materialInDB : materialExistList) {
                        if ((material.getSubCode() + "/" + material.getSubModel()).equals(materialInDB.getSubCode() + "/" + materialInDB.getSubModel())) {
                            materialHistory.setMaterialId(materialInDB.getId());
                            break;
                        }
                    }
                    materialHistoryList.add(materialHistory);
                }
            }
            if(materialHistoryList.size()>0) {
                materialHistoryService.addBatch(materialHistoryList);
            }
            //如果新上传的bom中存在0108、0109开头的物料,(肯定会被识别成新物料,之前的操作已经被插入到表中)
            // 在数据库存在相同的物料编码存在且不同的物料型号,则将数据库最新的物料的附件复制一份并状态同步,填充到新的物料表中
            for (Material material : newMaterialList) { //新物料
                String subCode = material.getSubCode();
                String subModel = material.getSubModel();
                if(subCode.startsWith("0108") || subCode.startsWith("0109")){
                    Material materialWithSameCodeLatest = mService.getByCodeAndModel(subCode, subModel, false);
                    if(materialWithSameCodeLatest!=null){
                        //附件转移并设置
                        mService.transferCopiedAttachment(materialWithSameCodeLatest,material);
                    }
                }
            }
        }
        return new Response().setII(1,"新增完成");
        //添加新增日志到tb_product_lock_log表
        ProductLockLog lockLog = new ProductLockLog();
        lockLog.setParentCode(parentCode);
        lockLog.setCustomCode(customCode);
        lockLog.setVersion(nextVersion);
        lockLog.setVersionTime(DateUtil.YYYY_MM_DD_HH_MM_SS.format(product.getVersionTime()));
        lockLog.setReason("产品bom上传");
        lockLog.setOwner(ActionUtil.getUser().getName());
        lockLog.setCreateTime(date);
        //-1代表日志类型为:产品bom上传
        lockLog.setLockFlag(-1);
        productLockLogService.insert(lockLog);
        return new Response().set(1,true,"新增完成");
    }
    private void deleteAndInsert(Product product) {
@@ -647,6 +1118,14 @@
            pbService.deleteByProductId(productDB.getId());
        }
        mapper.insert(product);
    }
    private void delete(Product product) {
        Product productDB = getByProductCodeAndCustomCode(product.getParentCode(), product.getCustomCode());
        if(productDB!=null) {
            mapper.deleteById(productDB.getId());
            pbService.deleteByProductId(productDB.getId());
        }
    }
    private Product getByProductCodeAndCustomCode(String parentCode, String customCode) {
@@ -665,4 +1144,27 @@
        List listProduct=mapper.selectListProduct(productId);
        return new Response().setIII(1,listMaterial.size()>0||listProduct.size()>0,listMaterial,listProduct,"");
    }
    //反馈管理-查询所有的产品
    public Response getFkProduct() {
        //QueryWrapper wrapper=new QueryWrapper();
        //wrapper.ne("version",-1);
        List list=mapper.selectList(null);
        return new Response().setII(1,list.size()>0,list,"反馈管理-查询所有的产品");
    }
    //产品对比下拉选中
    public Response getCompareProduct() {
        List list=mapper.selectList(null);
        return new Response().setII(1,list.size()>0,list,"产品对比下拉选中-查询当前使用的所有的产品");
    }
    public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return object -> seen.putIfAbsent(keyExtractor.apply(object), Boolean.TRUE) == null;
    }
    //验证母料编码是否存在产品中
    public Response judgeParentCode(String parentCode,String customCode) {
        int count = mapper.judgeParentCode(parentCode,customCode);
        return  new Response().set(1,count>0,"验证母料编码是否存在产品中");
    }
}