package com.sw.mes.yb.pad.service.impl;


import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.sw.mes.base.factory.init.entity.Equipment;
import com.sw.mes.base.factory.init.entity.FactoryModel;
import com.sw.mes.base.factory.init.service.EquipmentService;
import com.sw.mes.base.factory.init.service.FactoryModelService;
import com.sw.mes.base.factory.inspect.entity.*;
import com.sw.mes.base.factory.inspect.service.*;
import com.sw.mes.base.factory.product.entity.NewProductModel;
import com.sw.mes.base.factory.product.service.NewProductModelService;
import com.sw.mes.base.global.GlobalSwitch;
import com.sw.mes.base.global.SwitchConfig;
import com.sw.mes.base.system.entity.SysLog;
import com.sw.mes.base.system.service.SysLogService;
import com.sw.mes.base.workinprocess.dao.PlanProcessingOrderDao;
import com.sw.mes.base.workinprocess.service.CrystalLossRecordService;
import com.sw.mes.base.workinprocess.service.PlanProcessingOrderService;
import com.sw.mes.base.workinprocess.service.ProcessLogService;
import com.sw.mes.core.dto.store.WarehouseInputReturnDto;
import com.sw.mes.core.entity.CrystalLossRecord;
import com.sw.mes.core.enums.SeedMassageEnum;
import com.sw.mes.core.utils.DateUtil;
import com.sw.mes.core.utils.IpUtils;
import com.sw.mes.dingTalk.service.DingTalkService;
import com.sw.mes.sap.entity.ReportSapGoodsmvt;
import com.sw.mes.sap.entity.ReportSapWorkinghours;
import com.sw.mes.sap.service.ReportSapGoodsmvtService;
import com.sw.mes.sap.service.ReportSapWorkinghoursService;
import com.sw.mes.wipstorage.service.WipStorageYbService;
import com.sw.mes.yb.pad.dto.*;
import com.sw.mes.yb.pad.entity.*;
import com.sw.mes.yb.pad.service.ProductionPaintingLineHeadTailExceptionService;
import com.sw.mes.yb.plan.service.ProductionScheduleService;
import com.sw.mes.yb.production.entity.InspectionRecord;
import com.sw.mes.yb.production.entity.LoadingTask;
import com.sw.mes.yb.production.entity.ProcessWorkingHours;
import com.sw.mes.yb.production.service.*;
import com.sw.mes.yb.seed.enums.InputBillStatusEnum;
import com.sw.mes.yb.turnstore.dao.ProductionBindingTrayDao;
import com.sw.mes.yb.turnstore.dto.BindingCrystalDto;
import com.sw.mes.yb.turnstore.entity.ProductionBindingTray;
import org.modelmapper.ModelMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sw.mes.base.factory.inspect.dao.PaintingLineDao;
import com.sw.mes.base.factory.inspect.dao.PaintingLineDetailsDao;
import com.sw.mes.base.system.dao.DictionaryItemDao;
import com.sw.mes.base.system.entity.DictionaryItem;
import com.sw.mes.base.system.service.DictionaryItemService;
import com.sw.mes.base.system.service.impl.PrintService;
import com.sw.mes.base.workinprocess.service.WipStorageService;
import com.sw.mes.core.annotation.ServiceLogs;
import com.sw.mes.core.base.BaseServiceImpl;
import com.sw.mes.core.constant.Constants;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.dto.PrintInfoDto;
import com.sw.mes.core.enums.EnumValuesFactory;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultCode;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.NumberUtil;
import com.sw.mes.enumvalue.EnumValuesServer;
import com.sw.mes.utils.RestUtils;
import com.sw.mes.utils.StringUtils;
import com.sw.mes.yb.mcs.dto.HxbsDto;
import com.sw.mes.yb.pad.dao.PieceDetailDao;
import com.sw.mes.yb.pad.dao.ProductionPaintingLineDao;
import com.sw.mes.yb.pad.dao.ProductionPaintingLineDetailDao;
import com.sw.mes.yb.pad.dao.ProductionPaintingLineDetailExceptionDao;
import com.sw.mes.yb.pad.dao.SectionNoDetailDao;
import com.sw.mes.yb.pad.service.ProductionPaintingLineDetailExceptionService;
import com.sw.mes.yb.pad.service.ProductionPaintingLineService;
import com.sw.mes.yb.plan.service.YbProductionOrderService;
import com.sw.mes.yb.production.dao.ProductionWsmReserveDao;
import com.sw.mes.yb.production.entity.LongCrystal;
import com.sw.mes.yb.turnstore.service.ProductionBindingTrayService;

import lombok.extern.slf4j.Slf4j;

import static com.sw.mes.base.global.GlobalSwitchNamespace.CODE_SWITCH;


/**
 * @Author 画线记录表
 * @Description：
 * @Date: Create in
 * @Modified By:
 */
@Slf4j
@Service
@Transactional
public class ProductionPaintingLineServiceImpl extends BaseServiceImpl<ProductionPaintingLine> implements ProductionPaintingLineService {
    ProductionPaintingLineDao dao;

    @Autowired
    public void setDao(ProductionPaintingLineDao dao) {
        super.setBaseDao(dao);
        this.dao = dao;
    }

    @Autowired
    @Qualifier(value = "yBMesThreadPoolTaskExecutor")
    private ThreadPoolTaskExecutor ybMesThreadPoolExecutor;

    @Autowired
    private ProductionWsmReserveDao productionWsmReserveDao;

    @Autowired
    private ProductionPaintingLineDetailDao productionPaintingLineDetailDao;

    @Autowired
    private DictionaryItemDao dictionaryItemDao;

    @Autowired
    private LongCrystalService longCrystalService;

    @Autowired
    private PaintingLineDao paintingLineDao;

    @Autowired
    private PaintingLineService paintingLineService;

    @Autowired
    private PaintingLineDetailsDao paintingLineDetailsDao;

    @Autowired
    private SectionNoDetailDao sectionNoDetailDao;

    @Autowired
    private PieceDetailDao pieceDetailDao;

    @Autowired
    private YbProductionOrderService ybProductionOrderService;

    @Autowired
    private ProductionPaintingLineDetailDao ProductionPaintingLineDetailDao;

    @Autowired
    private ProductionPaintingLineDetailExceptionDao productionPaintingLineDetailExceptionDao;

    @Autowired
    private PrintService printService;

    @Autowired
    private DocumentPrintService documentMouldService;

    @Autowired
    private WipStorageService wipStorageService;

    @Autowired
    private DictionaryItemService dictionaryItemService;

    @Autowired
    private DefaultCrystalAttrService defaultCrystalAttrService;

    @Autowired
    private ProductionPaintingLineDetailExceptionService productionPaintingLineDetailExceptionService;

    @Autowired
    private ProductionBindingTrayService productionBindingTrayService;

    @Autowired
    private RestUtils restUtils;

    @Autowired
    private InspectionRecordService inspectionRecordService;


    @Autowired
    private InspectStickRuleService inspectStickRuleService;

    @Autowired
    private WipStorageYbService wipStorageYbService;

    @Autowired
    private EquipmentService equipmentService;

    @Autowired
    private ReportSapGoodsmvtService reportSapGoodsmvtService;

    @Value("${spring.mcsServiceUrl}")
    private String mcsServiceUrl;

    private static final String DRAWLINELEFTPOSTION = "从头至尾";

    private static final String DRAWLINERIGHTPOSTION = "从尾至头";

    private final String HXBD = "agv/mesToMcsController/updateMaterial";

    @Autowired
    private ProductionPaintingLineHeadTailExceptionService productionPaintingLineHeadTailExceptionService;



    @Autowired
    private NewProductModelService newProductModelService;

    @Autowired
    private ReportSapWorkinghoursService reportSapWorkinghoursService;

    @Autowired
    private SysLogService sysLogService;

    @Autowired
    private ProcessWorkingHoursService processWorkingHoursService;

    @Autowired
    private LoadingTaskService loadingTaskService;

    @Autowired
    private ProductionBindingTrayDao productionBindingTrayDao;

    @Autowired
    private CrystalBatchOperationService crystalBatchOperationService;

    @Autowired
    private CrystalLossRecordService crystalLossRecordService;

    @Autowired
    private DingTalkService dingTalkService;

    @Autowired
    private FactoryModelService factoryModelService;

    // 获取定向画线
    @Override
    public Result getDirectional() {
        String time = this.dictionaryItemDao.findReseceTimeByValue();
        if (time == null || StringUtils.isBlank(time)) {
            return ResultGenerator.fail("未找到对应字典值:停留时间");
        }
        List<Map<String, Object>> directionalListByTime = this.productionWsmReserveDao.findDirectionalListByTime(time);
        List<Map<String, Object>> newMap = new ArrayList<>();
        for (Map<String, Object> stringObjectMap : directionalListByTime) {
            Map<String, Object> map = new HashMap<>();
            //此接口美科项目未用
            String dopant = stringObjectMap.get("crystalNo").toString().substring(2, 3);
            map.put("dopant", dopant);
            map.put("time", time);
            map.put("length", stringObjectMap.get("length"));
            map.put("CrystalNo", stringObjectMap.get("crystalNo"));
            map.put("specs", stringObjectMap.get("spec"));
            String ErrorMassage = this.productionPaintingLineDetailDao.findErrorMessege(stringObjectMap.get("crystalNo").toString());
            map.put("errorMessege", ErrorMassage);
            newMap.add(map);
        }
        return ResultGenerator.success(newMap);
    }

    @Override
    public Result findLineInfo(String crystalNo) {
        return ResultGenerator.success();
    }

    @Autowired
    private PickingRuleService pickingRuleService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Result<LineDetailedResultDto> getLineInfo(LineParamDto lineParamDto) {
        LongCrystal longCrystal = longCrystalService.findByCrystalNo(lineParamDto.getCrystalNo());
        if (longCrystal == null) {
            return ResultGenerator.fail("【" + lineParamDto.getCrystalNo() + "】长棒编号不存在");
        }
        List<DictionaryItem> dictionaryItems = dictionaryItemService.findByThemeValueAndItemName(Constants.WEIGHT_RATIO, longCrystal.getSpecs(), true);
        if (dictionaryItems.size() == 0) {
            throw new BusinessException("请配置【" + longCrystal.getSpecs() + "】规格的理论重量系数");
        }
        BigDecimal weightLossCoefficient = NumberUtil.Object2BigDecimal(dictionaryItems.get(0).getValue());
        if (weightLossCoefficient == null || weightLossCoefficient.compareTo(new BigDecimal("1")) < 1) {
            throw new BusinessException("【" + dictionaryItems.get(0).getValue() + "】理论重量系数格式不正确，只能为大于0的数字类型");
        }

//        // 获取取片规则
        Set<String> pieceRulesSet = pickingRuleService.findBySpecsAndEquipmentAndDopant(longCrystal.getSpecs(), longCrystal.getEquipmentCode(), longCrystal.getDopant(), longCrystal.getAgainNum().toString(), longCrystal.getLength(), longCrystal.getWindUp());
        lineParamDto.setEffectiveLengthService(lineParamDto.getLength());
        List<Integer> startPosns = new ArrayList<>();
        List<Integer> posn = new ArrayList<>();
        Map<Integer, Integer> map = new HashMap<>();
        if (lineParamDto.getHeadLength() < 0) {
            return ResultGenerator.fail("头部排除长度不能小于0");
        }
        if (lineParamDto.getTailLength() < 0) {
            return ResultGenerator.fail("尾部排除长度不能小于0");
        }

        if (lineParamDto.getHeadLength() > 0) {
            List<int[]> listHead = new ArrayList<>();
            listHead.add(new int[]{0, lineParamDto.getHeadLength()});
            //查找并获取 头部排除长度 的开始位置，并且查找异常位置是否重叠
            startPosns.addAll(checkLocation(posn, listHead, map, "头部排除长度", lineParamDto));
        }
        if (lineParamDto.getTailLength() > 0) {
            List<int[]> listTail = new ArrayList<>();
            listTail.add(new int[]{lineParamDto.getLength() - lineParamDto.getTailLength(), lineParamDto.getLength()});
            //查找并获取 尾部排除长度 的开始位置，并且查找异常位置是否重叠
            startPosns.addAll(checkLocation(posn, listTail, map, "尾部排除长度", lineParamDto));
        }

        List<Integer> startPosns1 = new ArrayList<>();
        List<Integer> startPosns2 = new ArrayList<>();
        //查找并获取所有直径异常损失，出现异常的开始位置，并且查找异常位置是否重叠
        startPosns1 = checkLocation(posn, lineParamDto.getUnusualLengths(), map, "直径异常损失", lineParamDto);
        startPosns.addAll(startPosns1);
        // 查找匹配所有孪晶异常损失，出现异常的开始位置，并且查找异常位置是否重叠
        startPosns2 = checkLocation(posn, lineParamDto.getUnusualLength1s(), map, "孪晶异常损失", lineParamDto);
        startPosns.addAll(startPosns2);
        Collections.sort(startPosns);

        //判断出入的有效长度和服务端计算出的有效长度是否重叠
        if (lineParamDto.getEffectiveLength() != lineParamDto.getEffectiveLengthService()) {
            return ResultGenerator.fail("服务端计算出来的有效长度为：" + lineParamDto.getEffectiveLengthService() + "，请确认填写正确");
        }

        // 创建分段详情集合
        List<LineDetailedDto> detaileds = new LinkedList<>();
        //上一次回收料的结束位置，也是本次晶段的开始位置
        int start = 0;
        // 晶段序号
        int index = 0;
        //晶段总长度
        int lengthSum = 0;
        if (startPosns.size() > 0) {
            for (int i = 0; i < startPosns.size(); i++) {
                //本次异常位置的开始位置
                int startPosn = startPosns.get(i);

                if (startPosn > 0) {
                    if ((startPosn - start) > 0) {
                        lengthSum += (startPosn - start);
                        index++;
                        detaileds.addAll(getLineInfos(longCrystal, startPosn - start, index));
                    }
                    if (lengthSum < lineParamDto.getEffectiveLength()) {
                        //第一段回收料
                        LineDetailedDto lineDetailedDto1 = new LineDetailedDto(startPosns1.contains(startPosn) ? EnumValuesServer.LineType.直径异常回收料.getKey() : EnumValuesServer.LineType.孪晶回收料.getKey(), map.get(startPosn) - startPosn);
                        detaileds.add(lineDetailedDto1);
                    }
                }
                //判断最后一次遍历异常长度时，是否存在最后一颗晶段
                if (i == startPosns.size() - 1 && lengthSum < lineParamDto.getEffectiveLength()) {
                    int length = lineParamDto.getEffectiveLength() - lengthSum;
                    lengthSum += (startPosn - start);
                    index++;
                    detaileds.addAll(getLineInfos(longCrystal, length, index));
                }
                start = map.get(startPosn);
            }
        } else {
            index++;
            detaileds.addAll(getLineInfos(longCrystal, lineParamDto.getEffectiveLength(), index));
        }
        generateSegmentNo(detaileds, pieceRulesSet, longCrystal);
        int sequence = 0;
        int samplesCount = 0;
        int crystalCount = 0;
        for (LineDetailedDto lineDetailedDto : detaileds) {
            lineDetailedDto.setSequence(++sequence);
            if (lineDetailedDto.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                crystalCount++;
            }
            if (lineDetailedDto.getType() == EnumValuesServer.LineType.样片.getKey()) {
                samplesCount++;
            }
        }
        System.out.println("画线明细：" + JSON.toJSONString(detaileds));
        LineDetailedResultDto lineDetailedResultDto = new LineDetailedResultDto();
        lineDetailedResultDto.setCrystalCount(crystalCount);
        lineDetailedResultDto.setSamplesCount(samplesCount);
        lineDetailedResultDto.setLineDetailedDtos(detaileds);
        return ResultGenerator.success(lineDetailedResultDto);
    }

    @Override
    public List<PaintingLine> getDrawLineRuleList(String crystalNo) {
        //获取晶体信息
        LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
        //获取划线规则
        List<PaintingLine> paintingLineList = paintingLineService.getPaintingLine("%" + longCrystal.getSpecs() + "%", "%" + longCrystal.getDopant() + "%", "%" + longCrystal.getConductiveType() + "%");

        //调整匹配规则
        List<PaintingLine> resultPaintingLine = new ArrayList<>();
        NewProductModel productModel = null;
        if (null != longCrystal && StringUtils.isNotBlank(longCrystal.getProductCode())){
            productModel = newProductModelService.findByCode(longCrystal.getProductCode());
        }
        for (PaintingLine paintingLine : paintingLineList){
            if (StringUtils.isNotBlank(paintingLine.getAgainNum())){
                String againNum = "," + longCrystal.getAgainNum() + ",";
                if (paintingLine.getAgainNum().contains(againNum) && null != productModel && StringUtils.equals(productModel.getResistanceType(),paintingLine.getResistanceType())){
                    resultPaintingLine.add(paintingLine);
                }
            }
        }
        return resultPaintingLine;
    }

    @Override
    public Result<DrawLineDto> matchDrawLine(DrawLineParamDto drawLineParamDto) {
        //获取晶体信息
        LongCrystal longCrystal = longCrystalService.findByCrystalNo(drawLineParamDto.getCrystalNo());

        //获取送验
        InspectionRecord lastCrystalNoLog = inspectionRecordService.getLastCrystalNoLog(drawLineParamDto.getCrystalNo());

        String inspectionRemark = null;
        if (null != lastCrystalNoLog){
            //送验备注
            //inspectionRemark = lastCrystalNoLog.getEquipmentCode();
        }

        //获取取片规则(规格，系列，掺杂挤，收尾方式（v,w代表完结状态）)
        List<PickingRule> pickingRule=new ArrayList<>();
        if(CollectionUtils.isEmpty(drawLineParamDto.getPickingRule())){
            pickingRule = pickingRuleService.getPickingRule(longCrystal.getSpecs(), longCrystal.getEquipmentCode(), longCrystal.getDopant(), longCrystal.getWindUp(),inspectionRemark);
        }else{
            pickingRule=drawLineParamDto.getPickingRule();
        }
        //校验长度以及配置信息
        verification(drawLineParamDto, longCrystal, pickingRule, drawLineParamDto.getPaintingLine());
        //圆棒画线逻辑
        List<DictionaryItem> paintCrystalUsedLength = dictionaryItemService.findByThemeValueAndEnable("paintCrystalUsedLength", true);
        Map<String, String> collect = paintCrystalUsedLength.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getValue));
        DrawLineDto drawLineDto = null;
        if(collect.containsKey(longCrystal.getSpecs())){
            Integer length = Integer.valueOf(collect.get(longCrystal.getSpecs()));
            drawLineDto = generateDrawLineResult(drawLineParamDto, pickingRule, drawLineParamDto.getPaintingLine(), length);
        } else {
            throw new BusinessException("请前往数据字典配置规格为【" + longCrystal.getSpecs() + "】的划线晶段可用长度控制");
        }
        return ResultGenerator.success(drawLineDto);
    }

    private DrawLineDto generateDrawLineResult(DrawLineParamDto lineParamDto, List<PickingRule> pickingRule, List<PaintingLine> paintingLine, Integer length) {
        DrawLineDto drawLineDto = new DrawLineDto();
        List<DrawLineDetailDto> drawLineDetailDtos = new ArrayList<>();
        Map<String, Integer> pickingRuleMap = new HashMap<>();
        for (int i = 0; i < pickingRule.size(); i++) {
            BigDecimal pieceThickness = pickingRule.get(i).getPieceThickness();
            if (StringUtils.isNotEmpty(pickingRule.get(i).getPieceSite())) {
                Arrays.stream(StringUtils.split(pickingRule.get(i).getPieceSite(), ",")).forEach(t -> {
                    pickingRuleMap.put(t, pieceThickness.intValue());
                });
            }
        }
        //计算有效长度
        int effectiveLen = lineParamDto.getLength() - lineParamDto.getHeadLength() - lineParamDto.getTailLength();
        //异常信息
        Map<Integer, DrawLineExceptionDto> map = lineParamDto.getMidExeceptionLen().stream().collect(Collectors.toMap(t -> t.getStartLen().intValue(), Function.identity(), (k1, k2) -> k1));
        PaintingLine pl = paintingLine.get(0);
        //优先分段长
        Integer preferredSegmentLength = pl.getPreferredSegmentLength();
        //最短分段长
        Integer shortestSegmentLength = pl.getShortestSegmentLength();
        String startLinePosition = pl.getStartLinePosition();
        //画线逻辑
        if (StringUtils.equals(startLinePosition, DRAWLINELEFTPOSTION)) {
            leftDrawLine(lineParamDto, drawLineDetailDtos, pickingRuleMap, effectiveLen, map, preferredSegmentLength, shortestSegmentLength, length);
        } else if (StringUtils.equals(startLinePosition, DRAWLINERIGHTPOSTION)) {
            rightDrawLine(lineParamDto, drawLineDetailDtos, pickingRuleMap, effectiveLen, map, preferredSegmentLength, shortestSegmentLength, length);
            //特殊处理异常段
            drawLineDetailDtos.stream().forEach(t->{
                t.getExceptionDtos().stream().forEach(tt->{
                    BigDecimal len = tt.getLen();
                    BigDecimal startLen = tt.getStartLen();
                    tt.setStartLen(new BigDecimal(effectiveLen).subtract(startLen).add(len));
                });

            });
        }
        //赋单晶编号 type: 1头片 2晶段，3尾片 4 段片 5去头 6 去尾
        long crystalCount = drawLineDetailDtos.stream().filter(t -> t.getType() == 2).count();
        long sampeCount = drawLineDetailDtos.stream().filter(t -> t.getType() == 1 || t.getType() == 3 || t.getType() == 4).count();
        drawLineDetailDtos.stream().forEach(t -> {
            int type = t.getType();
            if (type == 1) {
                t.setSegmentNo(lineParamDto.getCrystalNo() + "TP");
                t.setSegmentNum(1);
            } else if (type == 3) {
                t.setSegmentNo(lineParamDto.getCrystalNo() + "WP");
                t.setSegmentNum((int) sampeCount);
            } else if (type == 2 && StringUtils.equals(t.getPosition(), "l")) {
                t.setSegmentNo(lineParamDto.getCrystalNo() + "WY");
                t.setSegmentNum((int) crystalCount);
            } else if (type == 4) {
                t.setSegmentNo(lineParamDto.getCrystalNo() + t.getPosition() + "P");
                t.setSegmentNum(Integer.parseInt(t.getPosition()));
            } else if (type == 5) {
                t.setSegmentNo(lineParamDto.getCrystalNo() + "TX");
            } else if (type == 6) {
                t.setSegmentNo(lineParamDto.getCrystalNo() + "WX");
            } else {
                t.setSegmentNo(lineParamDto.getCrystalNo() + t.getPosition() + "Y");
                t.setSegmentNum(Integer.parseInt(t.getPosition()));
            }
        });
        drawLineDto.setCrystalNo(lineParamDto.getCrystalNo());
        drawLineDto.setVehicleCode(lineParamDto.getTrayNo());
        drawLineDto.setSamplesCount((int) sampeCount);
        drawLineDto.setCrystalCount((int) crystalCount);
        drawLineDto.setStartLinePostion(startLinePosition);
        //0：晶段，1：样片 2:回收料
        drawLineDetailDtos.stream().forEach(t -> {
            if (t.getType() == 1 || t.getType() == 3 || t.getType() == 4) {
                t.setType(1);
            } else if (t.getType() == 5 || t.getType() == 6) {
                t.setType(2);
            } else if (t.getType() == 2) {
                t.setType(0);
            }
        });
        //排序
        List<DrawLineDetailDto> sortList = drawLineDetailDtos.stream().sorted(Comparator.comparing(DrawLineDetailDto::getSequence)).collect(Collectors.toList());
        drawLineDto.setLineDetailedDtos(sortList);
        return drawLineDto;
    }

    private void rightDrawLine(DrawLineParamDto lineParamDto, List<DrawLineDetailDto> drawLineDetailDtos, Map<String, Integer> pickingRuleMap, int effectiveLen, Map<Integer, DrawLineExceptionDto> map, Integer preferredSegmentLength, Integer shortestSegmentLength, Integer length) {
        //重新处理异常段
        final int newEffectivlen = effectiveLen;
        lineParamDto.getMidExeceptionLen().forEach(t -> {
            t.setStartLen(new BigDecimal(newEffectivlen).subtract(t.getStartLen().subtract(t.getLen())));
        });
        map = lineParamDto.getMidExeceptionLen().stream().collect(Collectors.toMap(t -> t.getStartLen().intValue(), Function.identity(), (k1, k2) -> k1));
        //排序
        int index = 0;
        //是否有去头长度
        int headLength = lineParamDto.getHeadLength();
        int tailLength = lineParamDto.getTailLength();
        //有去尾长度
        if (tailLength > 0) {
            int headStartLen = 0;
            int hadEndLen = tailLength;
            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, tailLength, 6, index++, "");
            drawLineDetailDtos.add(firstSegment);
        }
        //尾片的长度
        Integer firstSegmentLen = 0;
        Integer fregmentLen = 0;
        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())) {
            firstSegmentLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
            int firstStartLen = 0;
            int firstEndLen = firstSegmentLen;
            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, firstSegmentLen, 3, index++, "");
            drawLineDetailDtos.add(firstSegment);
            effectiveLen = effectiveLen - firstSegmentLen;
//            int lastRemaindLen = remaindLen - preferredSegmentLength;
//            if (remaindLen <= preferredSegmentLength) {
//                int sencondStartLen = firstEndLen;
//                int sencondEndLen = sencondStartLen + remaindLen;
//                DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, remaindLen, 2, index++, "l");
//                drawLineDetailDtos.add(secondSegment);
//                //去尾
//                if (headLength > 0) {
//                    int headStartLen = 0;
//                    int hadEndLen = headLength;
//                    DrawLineDetailDto endSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, headLength, 5, index++, "");
//                    drawLineDetailDtos.add(endSegment);
//                }
//                return;
//            } else if (remaindLen > preferredSegmentLength && lastRemaindLen <= shortestSegmentLength) {
//                //平分
//                int avgRemainLen = remaindLen / 2;
//                //余数部分
//                int yx = remaindLen % 2;
//                if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
//                    Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue());
//                    //第一个（尾晶段）
//                    int oneStartLen = firstSegmentLen;
//                    int ondEndLen = oneStartLen + avgRemainLen;
//                    DrawLineDetailDto oneSegment = buildDrawLineDetail(map, oneStartLen, ondEndLen, avgRemainLen, 2, index++, "l");
//                    drawLineDetailDtos.add(oneSegment);
//                    //第二个（晶段）
//                    int twoStartLen = ondEndLen;
//                    int twoEndLen = ondEndLen + avgRemainLen + yx - wpLen;
//                    DrawLineDetailDto secondSegment = buildDrawLineDetail(map, twoStartLen, twoEndLen, avgRemainLen + yx - wpLen, 2, index++, "1");
//                    drawLineDetailDtos.add(secondSegment);
//                    //第四个（头片）
//                    int lastStartLen = twoEndLen;
//                    int lastEndLen = lastStartLen + wpLen;
//                    DrawLineDetailDto wpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 1, index++, "");
//                    drawLineDetailDtos.add(wpSegment);
//                } else {
//                    //第一个（晶段）
//                    int oneStartLen = firstSegmentLen;
//                    int ondEndLen = oneStartLen + avgRemainLen;
//                    DrawLineDetailDto oneSegment = buildDrawLineDetail(map, oneStartLen, ondEndLen, avgRemainLen, 2, index++, "l");
//                    drawLineDetailDtos.add(oneSegment);
//                    //第二个（晶段样片）
//                    int twoStartLen = ondEndLen;
//                    int twoEndLen = ondEndLen + fregmentLen;
//                    DrawLineDetailDto secondSegment = buildDrawLineDetail(map, twoStartLen, twoEndLen, fregmentLen, 4, index++, "1");
//                    drawLineDetailDtos.add(secondSegment);
//                    //第三个（晶段）
//                    int threeWpStartLen = twoEndLen;
//                    int threeWpEndLen = threeWpStartLen + avgRemainLen + yx - fregmentLen;
//                    DrawLineDetailDto lastSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx, 2, index++, "1");
//                    drawLineDetailDtos.add(lastSegment);
//                }
//                //去头
//                if (headLength > 0) {
//                    int headStartLen = 0;
//                    int hadEndLen = headLength;
//                    DrawLineDetailDto endSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, headLength, 5, index++, "");
//                    drawLineDetailDtos.add(endSegment);
//                }
//                return;
//            } else {
//                int sencondStartLen = firstEndLen;
//                int sencondEndLen = sencondStartLen + preferredSegmentLength;
//                DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, preferredSegmentLength, 2, index++, "l");
//                drawLineDetailDtos.add(secondSegment);
//                effectiveLen = effectiveLen - firstSegmentLen - preferredSegmentLength;
//            }
        } else if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue())) {
            firstSegmentLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.尾片.getValue());
            int firstStartLen = 0;
            int firstEndLen = firstSegmentLen;
            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, firstSegmentLen, 3, index++, "");
            drawLineDetailDtos.add(firstSegment);
            effectiveLen = effectiveLen - firstSegmentLen;
        }
//            if (effectiveLen <= preferredSegmentLength) {
//                //如果包含头片
//                if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
//                    Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue());
//                    int sencondStartLen = firstEndLen;
//                    int sencondEndLen = sencondStartLen + effectiveLen;
//                    DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, effectiveLen, 2, index++, "l");
//                    drawLineDetailDtos.add(secondSegment);
//                }else{
//                    int sencondStartLen = firstEndLen;
//                    int sencondEndLen = sencondStartLen + effectiveLen;
//                    DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, effectiveLen, 2, index++, "l");
//                    drawLineDetailDtos.add(secondSegment);
//                }
//                //去尾
//                if (headLength > 0) {
//                    int headStartLen = 0;
//                    int hadEndLen = headLength;
//                    DrawLineDetailDto endSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, headLength, 5, index++, "");
//                    drawLineDetailDtos.add(endSegment);
//                }
//                return;
//            }  else {
//                int sencondStartLen = firstEndLen;
//                int sencondEndLen = sencondStartLen + preferredSegmentLength;
//                DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, preferredSegmentLength, 2, index++, "l");
//                drawLineDetailDtos.add(secondSegment);
//                effectiveLen = effectiveLen  - preferredSegmentLength;
//            }
//        else if (!pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue()) && !pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())) {
//            if (effectiveLen <= preferredSegmentLength) {
//
//                //如果包含头片
//                if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
//                    Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue());
//                    int firstStartLen = 0;
//                    int firstEndLen = firstStartLen + effectiveLen-wpLen;
//                    DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, effectiveLen-wpLen, 2, index++, "l");
//                    drawLineDetailDtos.add(firstSegment);
//                    int sencondStartLen = firstEndLen;
//                    int sencondEndLen = sencondStartLen + wpLen;
//                    DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, wpLen, 1, index++, "");
//                    drawLineDetailDtos.add(secondSegment);
//                }else{
//                    int sencondStartLen = 0;
//                    int sencondEndLen = sencondStartLen + effectiveLen;
//                    DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, effectiveLen, 2, index++, "l");
//                    drawLineDetailDtos.add(secondSegment);
//                }
//                //去尾
//                if (headLength > 0) {
//                    int headStartLen = 0;
//                    int hadEndLen = headLength;
//                    DrawLineDetailDto endSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, headLength, 5, index++, "");
//                    drawLineDetailDtos.add(endSegment);
//                }
//                return;
//
//            }  else {
//                int sencondStartLen = 0;
//                int sencondEndLen = sencondStartLen + preferredSegmentLength;
//                DrawLineDetailDto secondSegment = buildDrawLineDetail(map, sencondStartLen, sencondEndLen, preferredSegmentLength, 2, index++, "l");
//                drawLineDetailDtos.add(secondSegment);
//                effectiveLen = effectiveLen - firstSegmentLen - preferredSegmentLength;
//            }
//        }

        //分段数
        int segmentNum;
        int pickSegmentYPLen = 0;

        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())) {
            //每段画线逻辑
            pickSegmentYPLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
            segmentNum = effectiveLen % (preferredSegmentLength + pickSegmentYPLen) == 0 ? effectiveLen / (preferredSegmentLength + pickSegmentYPLen) : effectiveLen / (preferredSegmentLength + pickSegmentYPLen) + 1;
        } else {
            //只有尾片逻辑
            segmentNum = effectiveLen % preferredSegmentLength == 0 ? effectiveLen / preferredSegmentLength : effectiveLen / preferredSegmentLength + 1;
        }
        int segmentCode = segmentNum;


        //todo 新增逻辑,如果尾段优先段长小于最短段长，走之前逻辑，否则走新逻辑：
        //尾段优先段长
        Integer weiduanPreferredSegment = 0;
        List<DictionaryItem> byThemeValueAndItemName = dictionaryItemService.findByThemeValueAndItemName("weiduanPreferredSegment", "尾段优先段长", true);
        if (!CollectionUtils.isEmpty(byThemeValueAndItemName) && StringUtils.isNotEmpty(byThemeValueAndItemName.get(0).getValue())){
            weiduanPreferredSegment = Integer.valueOf(byThemeValueAndItemName.get(0).getValue());
        }


        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())) {
            for (int i = 1; i <= segmentNum; i++) {
                if (i == segmentNum) {
                    //有效长度减去尾片
                    int realEffectiveLen = effectiveLen - pickSegmentYPLen;
                    //只有一段晶段
                    if (realEffectiveLen <= preferredSegmentLength) {
//                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
                        Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
                        //第一个（晶段）
                        int firstStartLen = firstSegmentLen;
                        int firstEndLen = firstStartLen + effectiveLen - wpLen;
                        if(effectiveLen - wpLen >= length){
                            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, effectiveLen - wpLen, 2, index++, "l");
                            drawLineDetailDtos.add(firstSegment);
                        } else {
                            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, effectiveLen - wpLen, 6, index++, "l");
                            drawLineDetailDtos.add(firstSegment);
                        }
                        //头片
                        int lastStartLen = firstEndLen;
                        int lastEndLen = lastStartLen + wpLen;
                        DrawLineDetailDto wpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 1, index++, "");
                        drawLineDetailDtos.add(wpSegment);
                    }
                    break;
                    //倒数第二段
                } else if (i == segmentNum - 1) {
                    int remainLen = effectiveLen - (preferredSegmentLength + pickSegmentYPLen) * (i - 1);
                    int lastLen = remainLen - (preferredSegmentLength + pickSegmentYPLen);
                    //说明剩余的长度小于最小划线长度，需要和上一段合到一起在平钧分。
                    if (lastLen < shortestSegmentLength) {
                        int avgRemainLen = remainLen / 2;

                        boolean flag = false;
                        Integer last1 = 0;
                        Integer last2 = 0;
                        if (weiduanPreferredSegment > shortestSegmentLength){
                            last1 = weiduanPreferredSegment;
                            last2 = remainLen-weiduanPreferredSegment;
                            flag = true;
                        }

                        //余数部分
                        int yx = remainLen % 2;
//                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
                        Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
                        //第一个（晶段）
                        int firstStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i - 1) + firstSegmentLen;

                        DrawLineDetailDto firstSegment = new DrawLineDetailDto();
                        int firstEndLen = 0;
                        if (flag){
                            firstEndLen = firstStartLen + last1 - pickSegmentYPLen;
//                            DrawLineDetailDto firstSegment;
                            if (segmentCode == segmentNum) {
                                if(last1 - pickSegmentYPLen >= length){
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1 - pickSegmentYPLen, 2, index++, "l");
                                } else {
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1 - pickSegmentYPLen, 6, index++, "l");
                                }
                            } else {
                                if(segmentCode == 1 && last1 - pickSegmentYPLen < length){
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1 - pickSegmentYPLen, 6, index++, String.valueOf(segmentCode));
                                } else {
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1 - pickSegmentYPLen, 2, index++, String.valueOf(segmentCode));
                                }
                            }
                        }else {
                            firstEndLen = firstStartLen + avgRemainLen - pickSegmentYPLen;
//                            DrawLineDetailDto firstSegment;
                            if (segmentCode == segmentNum) {
                                if(avgRemainLen - pickSegmentYPLen >= length){
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 2, index++, "l");
                                } else {
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 6, index++, "l");
                                }
                            } else {
                                if(segmentCode == 1 && avgRemainLen - pickSegmentYPLen < length){
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 6, index++, String.valueOf(segmentCode));
                                } else {
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 2, index++, String.valueOf(segmentCode));
                                }
                            }
                        }


//                        int firstEndLen = firstStartLen + avgRemainLen - pickSegmentYPLen;
//                        DrawLineDetailDto firstSegment;
//                        if (segmentCode == segmentNum) {
//                            if(avgRemainLen - pickSegmentYPLen >= length){
//                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 2, index++, "l");
//                            } else {
//                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 6, index++, "l");
//                            }
//                        } else {
//                            if(segmentCode == 1 && avgRemainLen - pickSegmentYPLen < length){
//                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 6, index++, String.valueOf(segmentCode));
//                            } else {
//                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 2, index++, String.valueOf(segmentCode));
//                            }
//                        }
                        //DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen - pickSegmentYPLen, 2, index++, "l");
                        drawLineDetailDtos.add(firstSegment);
                        //第二个（晶段样片）
                        int secondStartLen = firstEndLen;
                        int secondEndLen = secondStartLen + pickSegmentYPLen;
                        DrawLineDetailDto secondSegment = buildDrawLineDetail(map, secondStartLen, secondEndLen, pickSegmentYPLen, 4, index++, String.valueOf(segmentCode -1));
                        drawLineDetailDtos.add(secondSegment);
                        //第三个（晶段）
                        int threeWpStartLen = secondEndLen;

                        int threeWpEndLen = 0;
                        if (flag){
                            threeWpEndLen = threeWpStartLen + last2 + yx - wpLen;
                            if(segmentCode - 1 == 1 && last2 + yx - wpLen < length){
                                DrawLineDetailDto wpSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, last2 + yx - wpLen, 6, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(wpSegment);
                            } else {
                                DrawLineDetailDto wpSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, last2 + yx - wpLen, 2, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(wpSegment);
                            }
                        } else {
                            threeWpEndLen = threeWpStartLen + avgRemainLen + yx - wpLen;
                            if(segmentCode - 1 == 1 && avgRemainLen + yx - wpLen < length){
                                DrawLineDetailDto wpSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 6, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(wpSegment);
                            } else {
                                DrawLineDetailDto wpSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 2, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(wpSegment);
                            }
                        }

//                        int threeWpEndLen = threeWpStartLen + avgRemainLen + yx - wpLen;
//                        if(segmentCode - 1 == 1 && avgRemainLen + yx - wpLen < length){
//                            DrawLineDetailDto wpSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 6, index++, String.valueOf(segmentCode - 1));
//                            drawLineDetailDtos.add(wpSegment);
//                        } else {
//                            DrawLineDetailDto wpSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 2, index++, String.valueOf(segmentCode - 1));
//                            drawLineDetailDtos.add(wpSegment);
//                        }
                        //（头片）
                        int lastStartLen = threeWpEndLen;
                        int lastEndLen = lastStartLen + wpLen;
                        DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 1, index++, "");
                        drawLineDetailDtos.add(lastSegment);

                    } else {
//                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
                        Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
                        //第一个（晶段）
                        int firstStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i - 1) + firstSegmentLen;
                        int firstEndLen = firstStartLen + preferredSegmentLength;
                        DrawLineDetailDto firstSegment;
                        if (segmentCode == segmentNum) {
                            if(preferredSegmentLength >= length){
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 2, index++, "l");
                            } else {
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 6, index++, "l");
                            }
                        } else {
                            if(segmentCode == 1 && preferredSegmentLength < length){
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 6, index++, String.valueOf(segmentCode));
                            } else {
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentCode));
                            }
                        }
                        //DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 2, index++, "l");
                        drawLineDetailDtos.add(firstSegment);
                        //第二个（晶段样片）
                        int secondStartLen = firstEndLen;
                        int secondEndLen = secondStartLen + pickSegmentYPLen;
                        DrawLineDetailDto secondSegment = buildDrawLineDetail(map, secondStartLen, secondEndLen, pickSegmentYPLen, 4, index++, String.valueOf(segmentCode -1));
                        drawLineDetailDtos.add(secondSegment);
                        //第三个（晶段）
                        int wpStartLen = secondEndLen;
                        int wpEndLen = wpStartLen + lastLen - wpLen;
                        if(segmentCode - 1 == 1 && lastLen - wpLen < length){
                            DrawLineDetailDto wpSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, lastLen - wpLen, 6, index++, String.valueOf(segmentCode - 1));
                            drawLineDetailDtos.add(wpSegment);
                        } else {
                            DrawLineDetailDto wpSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, lastLen - wpLen, 2, index++, String.valueOf(segmentCode - 1));
                            drawLineDetailDtos.add(wpSegment);
                        }

                        //第四个头片
                        int lastStartLen = wpEndLen;
                        int lastEndLen = wpEndLen + wpLen;
                        DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 1, index++, "");
                        drawLineDetailDtos.add(lastSegment);

                    }
                    break;
                    //倒数第三段晶段及以前
                } else {
                    //晶段
                    int segmentYpStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i - 1) + firstSegmentLen;
                    int segmentYpEndLen = segmentYpStartLen + preferredSegmentLength;
                    DrawLineDetailDto segment;
                    if (segmentCode == segmentNum) {
                        if(preferredSegmentLength < length){
                            segment = buildDrawLineDetail(map, segmentYpStartLen, segmentYpEndLen, preferredSegmentLength, 6, index++, "l");
                        } else {
                            segment = buildDrawLineDetail(map, segmentYpStartLen, segmentYpEndLen, preferredSegmentLength, 2, index++, "l");
                        }
                    } else {
                        if(segmentCode == 1 && preferredSegmentLength < length){
                            segment = buildDrawLineDetail(map, segmentYpStartLen, segmentYpEndLen, preferredSegmentLength, 6, index++, String.valueOf(segmentCode));
                        } else {
                            segment = buildDrawLineDetail(map, segmentYpStartLen, segmentYpEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentCode));
                        }
                    }
                    //DrawLineDetailDto segment = buildDrawLineDetail(map, segmentYpStartLen, segmentYpEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentCode));
                    drawLineDetailDtos.add(segment);
                    //每段样片
                    int segmentStartLen = segmentYpEndLen;
                    int segmentEndLen = segmentStartLen + pickSegmentYPLen;
                    DrawLineDetailDto segmentYp = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, pickSegmentYPLen, 4, index++, String.valueOf(segmentCode - 1));
                    drawLineDetailDtos.add(segmentYp);
                    segmentCode--;
                }
            }
        }
        //非每段取片
        else {
            for (int i = 1; i <= segmentNum; i++) {
                if (i == segmentNum) {
                    if (effectiveLen <= preferredSegmentLength) {
                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
                            Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue());
                            //第一个（晶段）
                            int firstStartLen = firstSegmentLen;
                            int firstEndLen = firstStartLen + effectiveLen - wpLen;
                            DrawLineDetailDto firstSegment;
                            if(effectiveLen - wpLen < length){
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, effectiveLen - wpLen, 6, index++, "l");
                                drawLineDetailDtos.add(firstSegment);
                            } else {
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, effectiveLen - wpLen, 2, index++, "l");
                                drawLineDetailDtos.add(firstSegment);
                            }

                            int lastStartLen = firstEndLen;
                            int lastEndLen = lastStartLen + wpLen;
                            DrawLineDetailDto wpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 1, index++, "");
                            drawLineDetailDtos.add(wpSegment);
                        } else {
                            //第一个（晶段）
                            int firstStartLen = firstSegmentLen;
                            int firstEndLen = firstStartLen + effectiveLen;
                            if(effectiveLen < length){
                                DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, effectiveLen, 6, index++, "l");
                                drawLineDetailDtos.add(firstSegment);
                            } else {
                                DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, effectiveLen, 2, index++, "l");
                                drawLineDetailDtos.add(firstSegment);
                            }

                        }
                    }
                    break;
                } else if (i == segmentNum - 1) {
                    int remainLen = effectiveLen - preferredSegmentLength * (i - 1);
                    int lastLen = remainLen - preferredSegmentLength;
                    if (lastLen < shortestSegmentLength) {
                        //平分保留的长度
                        int avgRemainLen = remainLen / 2;

                        boolean flag = false;
                        Integer last1 = 0;
                        Integer last2 = 0;
                        if (weiduanPreferredSegment > shortestSegmentLength){
                            last1 = weiduanPreferredSegment;
                            last2 = remainLen-weiduanPreferredSegment;
                            flag = true;
                        }

                        //余数部分
                        int yx = remainLen % 2;
                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
                            Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue());
                            //第一个（晶段）
                            int firstStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;

                            int firstEndLen = 0;
                            DrawLineDetailDto firstSegment = new DrawLineDetailDto();
                            if (flag){
                                firstEndLen = firstStartLen + last1;
//                                DrawLineDetailDto firstSegment;
                                if (segmentCode == segmentNum) {
                                    if(last1 < length){
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1, 6, index++, "l");
                                    } else {
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1, 2, index++, "l");
                                    }
                                } else {
                                    if(segmentCode == 1 && last1 < length){
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1, 6, index++, String.valueOf(segmentCode));
                                    } else {
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1, 2, index++, String.valueOf(segmentCode));
                                    }
                                }
                            } else {
                                firstEndLen = firstStartLen + avgRemainLen;
//                                DrawLineDetailDto firstSegment;
                                if (segmentCode == segmentNum) {
                                    if(avgRemainLen < length){
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 6, index++, "l");
                                    } else {
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, "l");
                                    }
                                } else {
                                    if(segmentCode == 1 && avgRemainLen < length){
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 6, index++, String.valueOf(segmentCode));
                                    } else {
                                        firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, String.valueOf(segmentCode));
                                    }
                                }
                            }

//                            int firstEndLen = firstStartLen + avgRemainLen;
//                            DrawLineDetailDto firstSegment;
//                            if (segmentCode == segmentNum) {
//                                if(avgRemainLen < length){
//                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 6, index++, "l");
//                                } else {
//                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, "l");
//                                }
//                            } else {
//                                if(segmentCode == 1 && avgRemainLen < length){
//                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 6, index++, String.valueOf(segmentCode));
//                                } else {
//                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, String.valueOf(segmentCode));
//                                }
//                            }
                            //DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, "l");
                            drawLineDetailDtos.add(firstSegment);
                            //第二个（尾晶段）
                            int secondWpStartLen = firstEndLen;


                            int secondWpEndLen = 0;
                            if (flag){
                                secondWpEndLen = secondWpStartLen + last2 - wpLen + yx;
                                if(segmentCode - 1 == 1 && last2 - wpLen + yx < length){
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, last2 - wpLen + yx, 6, index++, String.valueOf(segmentCode - 1));
                                    drawLineDetailDtos.add(secondWpSegment);
                                } else {
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, last2 - wpLen + yx, 2, index++, String.valueOf(segmentCode - 1));
                                    drawLineDetailDtos.add(secondWpSegment);
                                }
                            }else {
                                secondWpEndLen = secondWpStartLen + avgRemainLen - wpLen + yx;
                                if(segmentCode - 1 == 1 && avgRemainLen - wpLen + yx < length){
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen - wpLen + yx, 6, index++, String.valueOf(segmentCode - 1));
                                    drawLineDetailDtos.add(secondWpSegment);
                                } else {
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen - wpLen + yx, 2, index++, String.valueOf(segmentCode - 1));
                                    drawLineDetailDtos.add(secondWpSegment);
                                }
                            }


//                            int secondWpEndLen = secondWpStartLen + avgRemainLen - wpLen + yx;
//                            if(segmentCode - 1 == 1 && avgRemainLen - wpLen + yx < length){
//                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen - wpLen + yx, 6, index++, String.valueOf(segmentCode - 1));
//                                drawLineDetailDtos.add(secondWpSegment);
//                            } else {
//                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen - wpLen + yx, 2, index++, String.valueOf(segmentCode - 1));
//                                drawLineDetailDtos.add(secondWpSegment);
//                            }

                            //第三个（头片）
                            int lastStartLen = secondWpEndLen;
                            int lastEndLen = secondWpEndLen + wpLen;
                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 1, index++, "");
                            drawLineDetailDtos.add(lastSegment);

                        } else {
                            //第一个（晶段）
                            int firstStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;
//                            int firstEndLen = firstStartLen + avgRemainLen;
                            int firstEndLen = firstStartLen + (flag?last1:avgRemainLen);
                            DrawLineDetailDto firstSegment;
                            if (segmentCode == segmentNum) {
                                if((flag?last1:avgRemainLen) < length){
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, (flag?last1:avgRemainLen), 6, index++, "l");
                                } else {
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, (flag?last1:avgRemainLen), 2, index++, "l");
                                }
                            } else {
                                if((flag?last1:avgRemainLen) < length){
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, (flag?last1:avgRemainLen), 6, index++, String.valueOf(segmentCode));
                                } else {
                                    firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, (flag?last1:avgRemainLen), 2, index++, String.valueOf(segmentCode));
                                }
                            }
                            //DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, "l");
                            drawLineDetailDtos.add(firstSegment);
                            //第二个（晶段）
                            int secondWpStartLen = firstEndLen;
                            int secondWpEndLen = secondWpStartLen + (flag?last2:avgRemainLen);
                            if(segmentCode - 1 ==1 && (flag?last2:avgRemainLen) + yx < length){
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, (flag?last2:avgRemainLen) + yx, 6, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(secondWpSegment);
                            } else {
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, (flag?last2:avgRemainLen) + yx, 2, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(secondWpSegment);
                            }
                        }

                    } else {
                        //第一个（晶段）
                        int firstStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;
                        int firstEndLen = firstStartLen + preferredSegmentLength;
                        DrawLineDetailDto firstSegment;
                        if (segmentCode == segmentNum) {
                            if(preferredSegmentLength < length){
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 6, index++, "l");
                            } else {
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 2, index++, "l");
                            }
                        } else {
                            if(preferredSegmentLength < length){
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 6, index++, String.valueOf(segmentCode));
                            } else {
                                firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentCode));
                            }
                        }
                        //DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 2, index++, "l");
                        drawLineDetailDtos.add(firstSegment);
                        //第二个（晶段）
                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
                            Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue());
                            int wpStartLen = firstEndLen;
                            int wpEndLen = wpStartLen + lastLen - wpLen;
                            if(segmentCode - 1 == 1 && lastLen - wpLen < length){
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, lastLen - wpLen, 6, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(secondWpSegment);
                            } else {
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, lastLen - wpLen, 2, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(secondWpSegment);
                            }

                            int lastStartLen = wpEndLen;
                            int lastEndLen = wpEndLen + wpLen;
                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 1, index++, "");
                            drawLineDetailDtos.add(lastSegment);
                        } else {
                            int lastStartLen = preferredSegmentLength * (i) + firstSegmentLen;
                            int lastEndLen = effectiveLen + firstSegmentLen;
                            if(segmentCode - 1 == 1 && lastLen < length){
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, lastLen, 6, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(secondWpSegment);
                            } else {
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, lastLen, 2, index++, String.valueOf(segmentCode - 1));
                                drawLineDetailDtos.add(secondWpSegment);
                            }

                        }
                    }
                    break;
                    //倒数第三个及之前
                } else {
                    int segmentStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;
                    int segmentEndLen = preferredSegmentLength * (i) + firstSegmentLen;
                    DrawLineDetailDto segment;
                    if (segmentCode == segmentNum) {
                        if(preferredSegmentLength < length){
                            segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 6, index++, "l");
                        } else {
                            segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 2, index++, "l");
                        }
                    } else {
                        if(segmentCode == 1 && preferredSegmentLength < length){
                            segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 6, index++, String.valueOf(segmentCode));
                        } else {
                            segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentCode));
                        }
                    }
                    //DrawLineDetailDto segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentCode));
                    drawLineDetailDtos.add(segment);
                    segmentCode--;
                }
            }
        }

        //去头
        if (headLength > 0) {
            int headStartLen = 0;
            int hadEndLen = headLength;
            DrawLineDetailDto endSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, headLength, 5, index++, "");
            drawLineDetailDtos.add(endSegment);
        }

    }


    private void leftDrawLine(DrawLineParamDto lineParamDto, List<DrawLineDetailDto> drawLineDetailDtos, Map<String, Integer> pickingRuleMap, int effectiveLen, Map<Integer, DrawLineExceptionDto> map, Integer preferredSegmentLength, Integer shortestSegmentLength, Integer length) {
        //排序
        int index = 0;
        int segmentIndex = 1;
        //头片的长度
        Integer firstSegmentLen = 0;
        Integer fregmentLen = 0;
        //是否有去头长度
        int headLength = lineParamDto.getHeadLength();
        int tailLength = lineParamDto.getTailLength();
        if (headLength > 0) {
            int headStartLen = 0;
            int hadEndLen = headLength;
            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, headLength, 5, index++, "");
            drawLineDetailDtos.add(firstSegment);
        }
        //头片逻辑
        //每段取片
        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())) {
            fregmentLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
            firstSegmentLen = fregmentLen;
            int firstStartLen = 0;
            int firstEndLen = firstSegmentLen;
            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, firstSegmentLen, 1, index++, "");
            drawLineDetailDtos.add(firstSegment);
            effectiveLen = effectiveLen - firstSegmentLen;

        }
        //取头片，不是每段取片
        else if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue())) {
            firstSegmentLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue());
            int firstStartLen = 0;
            int firstEndLen = firstSegmentLen;
            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, firstSegmentLen, 1, index++, "");
            drawLineDetailDtos.add(firstSegment);
            effectiveLen = effectiveLen - firstSegmentLen;
        }
        //分段数
        int segmentNum = 0;
        //每段取片长度
        int pickSegmentYPLen = 0;
        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())) {
            //每段画线逻辑
            pickSegmentYPLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
            segmentNum = effectiveLen % (preferredSegmentLength + pickSegmentYPLen) == 0 ? effectiveLen / (preferredSegmentLength + pickSegmentYPLen) : effectiveLen / (preferredSegmentLength + pickSegmentYPLen) + 1;
        } else {
            //只有尾片逻辑
            segmentNum = effectiveLen % preferredSegmentLength == 0 ? effectiveLen / preferredSegmentLength : effectiveLen / preferredSegmentLength + 1;
        }

        //todo 新增逻辑,如果尾段优先段长小于最短段长，走之前逻辑，否则走新逻辑：
        //尾段优先段长
        Integer weiduanPreferredSegment = 0;
        List<DictionaryItem> byThemeValueAndItemName = dictionaryItemService.findByThemeValueAndItemName("weiduanPreferredSegment", "尾段优先段长", true);
        if (!CollectionUtils.isEmpty(byThemeValueAndItemName) && StringUtils.isNotEmpty(byThemeValueAndItemName.get(0).getValue())){
            weiduanPreferredSegment = Integer.valueOf(byThemeValueAndItemName.get(0).getValue());
        }

        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())) {
            for (int i = 1; i <= segmentNum; i++) {
                //只有一段
                if (i == segmentNum) {
                    //有效长度减去尾片
                    int realEffectiveLen = effectiveLen - pickSegmentYPLen;
                    if (realEffectiveLen <= preferredSegmentLength) {
                        //第一个（晶段样片）
                        Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
                        //晶段
                        int wpStartLen = firstSegmentLen;
                        int wpEndLen = effectiveLen;
                        if(effectiveLen - pickSegmentYPLen >= length){
                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, effectiveLen - pickSegmentYPLen, 2, index++, "l");
                            drawLineDetailDtos.add(lastSegment);
                        } else {
                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, effectiveLen - pickSegmentYPLen, 6, index++, "l");
                            drawLineDetailDtos.add(lastSegment);
                        }
                        //尾片
                        int lastStartLen = wpEndLen;
                        int lastEndLen = wpEndLen + wpLen;
                        DrawLineDetailDto wpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 3, index++, String.valueOf(segmentIndex + 1));
                        drawLineDetailDtos.add(wpSegment);

                    }
                    break;
                    //倒数第二段
                } else if (i == segmentNum - 1) {
                    int remainLen = effectiveLen - (preferredSegmentLength + pickSegmentYPLen) * (i - 1);
                    int lastLen = remainLen - (preferredSegmentLength + pickSegmentYPLen);
                    //说明剩余的长度小于最小划线长度，需要和上一段合到一起在平钧分。
                    if (lastLen < shortestSegmentLength) {
                        int avgRemainLen = remainLen / 2;

                        boolean flag = false;
                        Integer last1 = 0;
                        Integer last2 = 0;
                        if (weiduanPreferredSegment > shortestSegmentLength){
                            last1 = weiduanPreferredSegment;
                            last2 = remainLen-weiduanPreferredSegment;
                            flag = true;
                        }

                        //余数部分
                        int yx = remainLen % 2;
//                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue())) {
                        Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
                        //第一个（晶段）
                        int secondStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i - 1) + firstSegmentLen;
                        int secondEndLen = 0;
                        DrawLineDetailDto secondSegment = new DrawLineDetailDto();
                        if (flag){
                            secondEndLen = secondStartLen + last1 - pickSegmentYPLen;
                            secondSegment = buildDrawLineDetail(map, secondStartLen, secondEndLen, last1 - pickSegmentYPLen, 2, index++, String.valueOf(segmentIndex));
                        }else {
                            secondEndLen = secondStartLen + avgRemainLen - pickSegmentYPLen;
                            secondSegment = buildDrawLineDetail(map, secondStartLen, secondEndLen, avgRemainLen - pickSegmentYPLen, 2, index++, String.valueOf(segmentIndex));
                        }
                        drawLineDetailDtos.add(secondSegment);
                        //第二个（晶段样片）
                        int firstStartLen = secondEndLen;
                        int firstEndLen = secondEndLen + pickSegmentYPLen;
                        DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, pickSegmentYPLen, 4, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(firstSegment);
                        //第三个（最后一个晶段）
                        int threeWpStartLen = firstEndLen;
                        int threeWpEndLen = 0;
                        if (flag){
                            threeWpEndLen = threeWpStartLen + last2 + yx - wpLen;
                            if(last2 + yx - wpLen >= lastLen){
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, last2 + yx - wpLen, 2, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            } else {
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, last2 + yx - wpLen, 6, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            }
                        }else {
                            threeWpEndLen = threeWpStartLen + avgRemainLen + yx - wpLen;
                            if(avgRemainLen + yx - wpLen >= lastLen){
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 2, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            } else {
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 6, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            }
                        }

//                        if(avgRemainLen + yx - wpLen >= lastLen){
//                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 2, index++, "l");
//                            drawLineDetailDtos.add(lastSegment);
//                        } else {
//                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, threeWpStartLen, threeWpEndLen, avgRemainLen + yx - wpLen, 6, index++, "l");
//                            drawLineDetailDtos.add(lastSegment);
//                        }
                        //第四个（尾片）
                        int lastStartLen = threeWpEndLen;
                        int lastEndLen = threeWpEndLen + pickSegmentYPLen;
                        DrawLineDetailDto wpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 3, index++, String.valueOf(segmentIndex + 1));
                        drawLineDetailDtos.add(wpSegment);
                    } else {
                        //第一个（晶段）
                        int secondStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i - 1) + firstSegmentLen;
                        int secondEndLen = secondStartLen + preferredSegmentLength;
                        DrawLineDetailDto secondSegment = buildDrawLineDetail(map, secondStartLen, secondEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(secondSegment);
                        //第二个（晶段样片）
                        int firstStartLen = secondEndLen;
                        int firstEndLen = firstStartLen + pickSegmentYPLen;
                        DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, pickSegmentYPLen, 4, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(firstSegment);
//                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue())) {
                        Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
                        //最后一个晶段
                        int wpStartLen = (preferredSegmentLength + pickSegmentYPLen) * i + firstSegmentLen;
                        int wpEndLen = wpStartLen + lastLen - wpLen;
                        if(lastLen - wpLen >= length){
                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, lastLen - wpLen, 2, index++, "l");
                            drawLineDetailDtos.add(lastSegment);
                        } else {
                            DrawLineDetailDto lastSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, lastLen - wpLen, 6, index++, "l");
                            drawLineDetailDtos.add(lastSegment);
                        }
                        //尾片
                        int lastStartLen = wpEndLen;
                        int lastEndLen = wpEndLen + pickSegmentYPLen;
                        DrawLineDetailDto wpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, wpLen, 3, index++, String.valueOf(segmentIndex + 1));
                        drawLineDetailDtos.add(wpSegment);
//                        } else {
//                            int lastStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i) + firstSegmentLen;
//                            int lastEndLen = newEffectiveLen + firstSegmentLen;
//                            DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, lastLen, 2, index++, "l");
//                            drawLineDetailDtos.add(secondWpSegment);
//                        }
                    }
                    break;
                } else {
                    //晶段
//                    int segmentStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i - 1) + firstSegmentLen + pickSegmentYPLen;
                    int segmentStartLen = (preferredSegmentLength + pickSegmentYPLen) * (i - 1) + firstSegmentLen;
                    int segmentEndLen = segmentStartLen + preferredSegmentLength;
                    if(segmentIndex == 1 && preferredSegmentLength < length){
                        DrawLineDetailDto segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 6, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(segment);
                    } else {
                        DrawLineDetailDto segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(segment);
                    }
                    //每段样片
                    int segmentYpStartLen = segmentEndLen;
                    int segmentYpEndLen = segmentYpStartLen + pickSegmentYPLen;
                    DrawLineDetailDto segmentYp = buildDrawLineDetail(map, segmentYpStartLen, segmentYpEndLen, pickSegmentYPLen, 4, index++, String.valueOf(segmentIndex));
                    drawLineDetailDtos.add(segmentYp);
                }
                segmentIndex++;
            }
        }
        //非每段取片
        else {
            for (int i = 1; i <= segmentNum; i++) {
                //只有一段
                if (i == segmentNum) {
                    //剩余长度小于等于优先长度
                    if (effectiveLen <= preferredSegmentLength) {
                        //（晶段）
                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue())) {
                            Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.尾片.getValue());
                            int lastStartLen = firstSegmentLen;
                            int lastEndLen = firstSegmentLen + effectiveLen - wpLen;
                            if(effectiveLen - wpLen >= length){
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, effectiveLen - wpLen, 2, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            } else {
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, effectiveLen - wpLen, 6, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            }
                            int wpStartLen = lastEndLen;
                            int wpEndLen = lastEndLen + wpLen;
                            DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, wpLen, 3, index++, String.valueOf(segmentIndex + 1));
                            drawLineDetailDtos.add(secondWpSegment);
                        } else {
                            int lastStartLen = firstSegmentLen;
                            int lastEndLen = effectiveLen + firstSegmentLen;
                            if(effectiveLen >= length){
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, effectiveLen, 2, index++, "l");
                                drawLineDetailDtos.add(secondWpSegment);
                            } else {
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, effectiveLen, 6, index++, "l");
                                drawLineDetailDtos.add(secondWpSegment);
                            }
                        }
                    }
                    break;
                    //倒数第二段
                } else if (i == segmentNum - 1) {
                    //剩下两段的长度
                    int remainLen = effectiveLen - preferredSegmentLength * (i - 1);
                    //最后一段的长度
                    int lastLen = remainLen - preferredSegmentLength;
                    //todo 此处为尾段逻辑处
                    //最后一段长度小于最小长度
                    if (lastLen < shortestSegmentLength) {
                        //平分保留的长度
                        int avgRemainLen = remainLen / 2;

                        boolean flag = false;
                        Integer last1 = 0;
                        Integer last2 = 0;
                        if (weiduanPreferredSegment > shortestSegmentLength){
                            last1 = weiduanPreferredSegment;
                            last2 = remainLen-weiduanPreferredSegment;
                            flag = true;
                        }

                        //余数部分
                        int yx = remainLen % 2;
                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue())) {
                            Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.尾片.getValue());
                            //第一个（晶段）
                            int firstStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;

                            int firstEndLen = 0;
                            if (flag){
                                firstEndLen = firstStartLen + last1;
                                if(segmentIndex == 1 && last1 < length){
                                    DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1, 6, index++, String.valueOf(segmentIndex));
                                    drawLineDetailDtos.add(firstSegment);
                                } else {
                                    DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1, 2, index++, String.valueOf(segmentIndex));
                                    drawLineDetailDtos.add(firstSegment);
                                }
                            }else {
                               firstEndLen = firstStartLen + avgRemainLen;
                                if(segmentIndex == 1 && avgRemainLen < length){
                                    DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 6, index++, String.valueOf(segmentIndex));
                                    drawLineDetailDtos.add(firstSegment);
                                } else {
                                    DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, String.valueOf(segmentIndex));
                                    drawLineDetailDtos.add(firstSegment);
                                }
                            }
//                            int firstEndLen = firstStartLen + avgRemainLen;
//                            if(segmentIndex == 1 && avgRemainLen < length){
//                                DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 6, index++, String.valueOf(segmentIndex));
//                                drawLineDetailDtos.add(firstSegment);
//                            } else {
//                                DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, String.valueOf(segmentIndex));
//                                drawLineDetailDtos.add(firstSegment);
//                            }
                            //第二个（最后一个晶段）
                            int lastStartLen = firstEndLen;
                            int lastEndLen = 0;
                            if (flag){
                                lastEndLen = lastStartLen + last2 - wpLen + yx;
                                if(last2 + yx - wpLen >= length){
                                    DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, last2 + yx - wpLen, 2, index++, "l");
                                    drawLineDetailDtos.add(lastSegment);
                                } else {
                                    DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, last2 + yx - wpLen, 6, index++, "l");
                                    drawLineDetailDtos.add(lastSegment);
                                }
                            }else {
                                lastEndLen = lastStartLen + avgRemainLen - wpLen + yx;
                                if(avgRemainLen + yx - wpLen >= length){
                                    DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, avgRemainLen + yx - wpLen, 2, index++, "l");
                                    drawLineDetailDtos.add(lastSegment);
                                } else {
                                    DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, avgRemainLen + yx - wpLen, 6, index++, "l");
                                    drawLineDetailDtos.add(lastSegment);
                                }
                            }
//                            int lastEndLen = lastStartLen + avgRemainLen - wpLen + yx;
//                            if(avgRemainLen + yx - wpLen >= length){
//                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, avgRemainLen + yx - wpLen, 2, index++, "l");
//                                drawLineDetailDtos.add(lastSegment);
//                            } else {
//                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, avgRemainLen + yx - wpLen, 6, index++, "l");
//                                drawLineDetailDtos.add(lastSegment);
//                            }
                            //第三个（尾片）
                            int secondWpStartLen = lastEndLen;
                            int secondWpEndLen = lastEndLen + wpLen;
                            DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, wpLen, 3, index++, String.valueOf(segmentIndex + 1));
                            drawLineDetailDtos.add(secondWpSegment);

                        } else {
                            //第一个（晶段）
                            int firstStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;
                            int firstEndLen = 0;
                            if (flag){
                                firstEndLen = firstStartLen + last1;
                                DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, last1, 2, index++, String.valueOf(segmentIndex));
                                drawLineDetailDtos.add(firstSegment);
                            }else {
                                firstEndLen = firstStartLen + avgRemainLen;
                                DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, String.valueOf(segmentIndex));
                                drawLineDetailDtos.add(firstSegment);
                            }

//                            int firstEndLen = firstStartLen + avgRemainLen;
//                            DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, avgRemainLen, 2, index++, String.valueOf(segmentIndex));
//                            drawLineDetailDtos.add(firstSegment);
                            //第二个（晶段）
                            int secondWpStartLen = firstEndLen;

                            if (flag){
                                int secondWpEndLen = firstEndLen + last2 + yx;
                                if(last2 + yx >= length){
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, last2 + yx, 2, index++, "l");
                                    drawLineDetailDtos.add(secondWpSegment);
                                } else {
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, last2 + yx, 6, index++, "l");
                                    drawLineDetailDtos.add(secondWpSegment);
                                }
                            } else {
                                int secondWpEndLen = firstEndLen + avgRemainLen + yx;
                                if(avgRemainLen + yx >= length){
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen + yx, 2, index++, "l");
                                    drawLineDetailDtos.add(secondWpSegment);
                                } else {
                                    DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen + yx, 6, index++, "l");
                                    drawLineDetailDtos.add(secondWpSegment);
                                }
                            }


//                            int secondWpEndLen = firstEndLen + avgRemainLen + yx;
//                            if(avgRemainLen + yx >= length){
//                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen + yx, 2, index++, "l");
//                                drawLineDetailDtos.add(secondWpSegment);
//                            } else {
//                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, secondWpStartLen, secondWpEndLen, avgRemainLen + yx, 6, index++, "l");
//                                drawLineDetailDtos.add(secondWpSegment);
//                            }
                        }

                    } else {
                        //第一个（晶段）
                        int firstStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;//倒数第二个晶段开始位置长度
                        int firstEndLen = firstStartLen + preferredSegmentLength;//倒数第二个晶段结束位置长度
                        DrawLineDetailDto firstSegment = buildDrawLineDetail(map, firstStartLen, firstEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(firstSegment);
                        //第二个（晶段）
                        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue())) {
                            Integer wpLen = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.尾片.getValue());
                            int lastStartLen = firstEndLen;
                            int lastEndLen = lastStartLen + lastLen - wpLen;
                            if(lastLen - wpLen >= length){
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, lastLen - wpLen, 2, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            } else {
                                DrawLineDetailDto lastSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, lastLen - wpLen, 6, index++, "l");
                                drawLineDetailDtos.add(lastSegment);
                            }
                            int wpStartLen = lastEndLen;
                            int wpEndLen = wpStartLen + wpLen;
                            DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, wpStartLen, wpEndLen, wpLen, 3, index++, String.valueOf(segmentIndex + 1));
                            drawLineDetailDtos.add(secondWpSegment);

                        } else {
                            int lastStartLen = firstEndLen;
                            int lastEndLen = lastStartLen + lastLen;
                            if(lastLen >= length){
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, lastLen, 2, index++, "l");
                                drawLineDetailDtos.add(secondWpSegment);
                            } else {
                                DrawLineDetailDto secondWpSegment = buildDrawLineDetail(map, lastStartLen, lastEndLen, lastLen, 6, index++, "l");
                                drawLineDetailDtos.add(secondWpSegment);
                            }

                        }
                    }
                    break;
                }
                //倒数第三段之前的
                else {
                    int segmentStartLen = preferredSegmentLength * (i - 1) + firstSegmentLen;
                    int segmentEndLen = segmentStartLen + preferredSegmentLength;
                    if(segmentIndex == 1 && preferredSegmentLength < length){
                        DrawLineDetailDto segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 6, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(segment);
                    } else {
                        DrawLineDetailDto segment = buildDrawLineDetail(map, segmentStartLen, segmentEndLen, preferredSegmentLength, 2, index++, String.valueOf(segmentIndex));
                        drawLineDetailDtos.add(segment);
                    }

                }
                segmentIndex++;
            }
        }

        //去尾
        if (tailLength > 0) {
            int headStartLen = 0;
            int hadEndLen = headLength;
            DrawLineDetailDto endSegment = buildDrawLineDetail(map, headStartLen, hadEndLen, tailLength, 6, index++, "");
            drawLineDetailDtos.add(endSegment);
        }

    }


    /**
     * @param startLen：晶段开始长
     * @param endLen：晶段的结束长
     * @param len：晶段长度
     * @param type:1头片       2晶段 3尾片 4段片
     * @return
     */
    private DrawLineDetailDto buildDrawLineDetail(Map<Integer, DrawLineExceptionDto> map, int startLen, int endLen, int len, int type, int sequence, String position) {
        DrawLineDetailDto drawLineDetailDto = new DrawLineDetailDto();
        drawLineDetailDto.setStartLen(startLen);
        drawLineDetailDto.setEndLen(endLen);
        drawLineDetailDto.setLength(new BigDecimal(len));
        drawLineDetailDto.setType(type);
        drawLineDetailDto.setSequence(sequence);
        drawLineDetailDto.setPosition(position);
        addDrawLineException(map, drawLineDetailDto);
        return drawLineDetailDto;
    }

    private void addDrawLineException(Map<Integer, DrawLineExceptionDto> map, DrawLineDetailDto firstSegment) {
        List<DrawLineExceptionDto> drawLineExceptionDtoList = new ArrayList<>();
        for (Integer key : map.keySet()) {
            DrawLineExceptionDto inputDrawlingException = map.get(key);
            int value = key + inputDrawlingException.getLen().intValue();
            if (firstSegment.getEndLen() > key && firstSegment.getStartLen() < value) {
                DrawLineExceptionDto drawLineExceptionDto = new DrawLineExceptionDto();
                drawLineExceptionDto.setStartLen(new BigDecimal(key));
                drawLineExceptionDto.setLen(inputDrawlingException.getLen());
                drawLineExceptionDto.setDesc(inputDrawlingException.getDesc());
                drawLineExceptionDtoList.add(drawLineExceptionDto);
                firstSegment.setExceptionDtos(drawLineExceptionDtoList);
            }
        }
    }

    private void verification(DrawLineParamDto lineParamDto, LongCrystal longCrystal, List<PickingRule> pickingRule, List<PaintingLine> paintingLine) {
        if (longCrystal == null) {
            new BusinessException("【" + lineParamDto.getCrystalNo() + "】长棒编号不存在");
        }

        if (CollectionUtils.isEmpty(pickingRule)) {
            throw new BusinessException("取片规则不存在!");
        }
        //取片规则是否有重复
        Map<String, Integer> pickingRuleMap = new HashMap<>();
        for (int i = 0; i < pickingRule.size(); i++) {
            BigDecimal pieceThickness = pickingRule.get(i).getPieceThickness();
            if (StringUtils.isNotEmpty(pickingRule.get(i).getPieceSite())) {
                Arrays.stream(StringUtils.split(pickingRule.get(i).getPieceSite(), ",")).forEach(t -> {
                    if (pickingRuleMap.containsKey(t)) {
                        throw new BusinessException("取片规则重复只允许头片，尾片，每段取片，请重新配置取片规则！");
                    }
                    pickingRuleMap.put(t, pieceThickness.intValue());
                });
            }
        }
        if (CollectionUtils.isEmpty(paintingLine) || paintingLine.size() > 1) {
            throw new BusinessException("划线规则不存在或者划线规则大于1条！");
        }
        String startLinePosition = paintingLine.get(0).getStartLinePosition();
        if (StringUtils.isEmpty(startLinePosition)) {
            throw new BusinessException("【划线规则】划线开始位置不能为空！");
        }

        List<Integer> posn = new ArrayList<>();
        Map map = new HashMap();
        if (lineParamDto.getHeadLength() < 0) {
            throw new RuntimeException("头部排除长度不能小于0");
        }
        if (lineParamDto.getTailLength() < 0) {
            throw new RuntimeException("尾部排除长度不能小于0");
        }
        //直径异常
        List<int[]> list = new ArrayList<>();
        lineParamDto.getMidExeceptionLen().stream().forEach(t -> {
            int startLen = t.getStartLen().intValue();
            int endLen = t.getLen().intValue() + startLen;
            int[] segmentLen = {startLen, endLen};
            list.add(segmentLen);
        });
        checkDrawLineLocation(posn, list, map, "中间段异常:", lineParamDto);
    }

    public void checkDrawLineLocation(List<Integer> posn, List<int[]> unusualLengths, Map<Integer, DrawLineExceptionDto> map, String message, DrawLineParamDto lineParamDto) {
        int effectiveLength = lineParamDto.getEffectiveLength();
        if (unusualLengths != null && unusualLengths.size() > 0) {
            for (int[] unusualLength : unusualLengths) {
                if (unusualLength.length != 2) {
                    throw new RuntimeException("【" + message + "】位置的传值不正确");
                }
                if (unusualLength[0] >= unusualLength[1]) {
                    throw new RuntimeException("【" + message + "】位置的传值有误，长度不能为0和负数");
                }

                if (unusualLength[1] > effectiveLength) {
                    throw new RuntimeException("【" + message + "】距头位置+异常长度大于画线的长度");
                }
                for (int i = unusualLength[0] + 1; i <= unusualLength[1]; i++) {
                    if (!posn.contains(i)) {
                        posn.add(i);
                    } else {
                        throw new RuntimeException(message + "的" + i + "位置与其他异常位置，出现重叠，请修改正确");
                    }
                }
            }
        }
    }

    public List<Integer> checkLocation(List<Integer> posn, List<int[]> unusualLengths, Map<Integer, Integer> map, String message, LineParamDto lineParamDto) {
        List<Integer> posnLenths = new ArrayList<>();
        if (unusualLengths != null && unusualLengths.size() > 0) {
            for (int[] unusualLength : unusualLengths) {
                if (unusualLength.length != 2) {
                    throw new RuntimeException("【" + message + "】位置的传值不正确");
                }
                if (unusualLength[0] >= unusualLength[1]) {
                    throw new RuntimeException("【" + message + "】位置的传值有误，长度不能为0和负数");
                }
                for (int i = unusualLength[0] + 1; i <= unusualLength[1]; i++) {
                    if (!posn.contains(i)) {
                        posn.add(i);
                    } else {
                        throw new RuntimeException(message + "的" + i + "位置与其他异常位置，出现重叠，请修改正确");
                    }
                }
                posnLenths.add(unusualLength[0]);
                map.put(unusualLength[0], unusualLength[1]);
                lineParamDto.setEffectiveLengthService(lineParamDto.getEffectiveLengthService() - unusualLength[1] + unusualLength[0]);
            }
        }
        return posnLenths;
    }

    /**
     * 根据长棒信息和有效棒长，匹配画线规则分段
     *
     * @param longCrystal   长棒信息
     * @param surplusLength 有效长度
     * @param index         第几段的有效长度
     * @return
     */
    public List<LineDetailedDto> getLineInfos(LongCrystal longCrystal, Integer surplusLength, int index) {
        PaintingLine idBySpecsAndDopant = paintingLineDao.findIdBySpecsAndDopant("%" + longCrystal.getSpecs() + "%", "%" + longCrystal.getDopant() + "%");
        if (idBySpecsAndDopant == null) {
            throw new RuntimeException("未匹配到画线规则，当前晶棒规格为【" + longCrystal.getSpecs() + "】，掺杂剂为【" + longCrystal.getDopant() + "】");
        }
        List<PaintingLineDetails> lineRules = this.paintingLineDetailsDao.findLengthByLineIdAndCrystalLength(idBySpecsAndDopant.getId(), new BigDecimal(surplusLength));
        if (lineRules == null || lineRules.size() == 0) {
            throw new RuntimeException("【" + idBySpecsAndDopant.getRuleName() + "】在此画线规则中，未匹配到画线规则详情，当前晶棒第" + index + "段有效长度为：" + surplusLength);
        }
        PaintingLineDetails paintingLineDetails = lineRules.get(0);
        String[] lengthArr = paintingLineDetails.getLength().split(",");
        int sumLength = 0;
        Integer surplusLengCount = 0;
        List<Integer> lengths = new LinkedList<>();
        for (String length : lengthArr) {
            if (!"/".equals(length)) {
                Integer lengthInt = NumberUtil.String2Integer(length, null);
                if (lengthInt == null) {
                    throw new RuntimeException(idBySpecsAndDopant.getRuleName() + "在此画线规则中，" + "画线规则详情分段长度配置错误，转换成整数类型失败：" + length);
                }
                if (lengthInt <= 0) {
                    throw new RuntimeException(idBySpecsAndDopant.getRuleName() + "在此画线规则中，" + "画线规则详情分段长度配置错误，不能小于等于0：" + length);
                }
                lengths.add(lengthInt);
                surplusLength -= lengthInt;
                sumLength += lengthInt;
            } else {
                lengths.add(null);
                surplusLengCount++;
            }
        }
        if (surplusLength < 0) {
            throw new RuntimeException(idBySpecsAndDopant.getRuleName() + "在此画线规则中，" + "画线规则详情分段长度配置错误，分段总长度大于，当前晶棒第" + index + "段有效长度：" + longCrystal.getLength() + ">" + sumLength);
        }
        int surplusLengthItem = surplusLength / surplusLengCount;
        int surplusLengthY = surplusLength % surplusLengCount;
        int lengthsSize = lengths.size();
        for (int i = 0; i < lengthsSize; i++) {
            if (lengths.get(i) == null) {
                surplusLengCount--;
                if (surplusLengCount == 0) {
                    lengths.set(i, surplusLengthItem + surplusLengthY);
                } else {
                    lengths.set(i, surplusLengthItem);
                }
            }
        }
        List<LineDetailedDto> list = new LinkedList<>();
        for (int length : lengths) {
            LineDetailedDto lineDetailedDto = new LineDetailedDto(0, length);
            list.add(lineDetailedDto);
        }
        return list;
    }

    //添加y
    public void generateSegmentNo(List<LineDetailedDto> lineDetailedDtos, Set<String> pieceRulesSet, LongCrystal longCrystal) {
        //头片 尾片 头尾片  尾头片
        boolean headSample = false, tailSample = false, headTailSample = false, tailHeadSample = false;
        //每段取片
        boolean middleSample = false;
        if (pieceRulesSet.contains("每段取片")) {
            middleSample = true;
        }
        if (pieceRulesSet.contains("头片")) {
            headSample = true;
        }
        if (pieceRulesSet.contains("尾片")) {
            tailSample = true;
        }
        if (pieceRulesSet.contains("头尾片")) {
            headTailSample = true;
        }
        if (pieceRulesSet.contains("尾头片")) {
            tailHeadSample = true;
        }
        Map<Double, LineDetailedDto> lineDetailedDtoMap = new LinkedHashMap<>();
        int size = lineDetailedDtos.size();
        int crystalCount = 0;
        for (Integer i = 0; i < size; i++) {
            LineDetailedDto lineDetailedDto = lineDetailedDtos.get(i);
            if (lineDetailedDto.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                crystalCount++;
            }
        }
        int xIndex = 1;
        Integer index = 0;
        Integer index1 = 0;
        int sampleCount = 0; //需要减去的样片长度
        for (LineDetailedDto lineDetailedDto : lineDetailedDtos) {
            index1++;
            lineDetailedDto.setSequence(index1);
            if (lineDetailedDto.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                index++;
                StringBuilder crystalNo = new StringBuilder(longCrystal.getCrystalNo());
                crystalNo.append(String.format("%02d", index));
                lineDetailedDto.setSegmentNum(index);
                lineDetailedDtoMap.put(index.doubleValue(), lineDetailedDto);
                if ((middleSample || (crystalCount == 1 & tailHeadSample) || headSample) && index == 1) { //头片
                    LineDetailedDto headSampleLineDetailedDto = new LineDetailedDto(EnumValuesServer.LineType.样片.getKey(), 3);
                    headSampleLineDetailedDto.setSegmentNo(crystalNo + "T1");
                    headSampleLineDetailedDto.setSampleType(EnumValuesServer.SampleType.头片.getKey());
                    headSampleLineDetailedDto.setSegmentNum(index);
                    lineDetailedDtoMap.put(index.doubleValue() - 0.1, headSampleLineDetailedDto); //插入晶段数据
                }
                if (index == crystalCount) { //只有一段
                    crystalNo.append("W");
                    if (tailSample || (crystalCount == 1 && headTailSample) || middleSample) { //尾片，头片
                        LineDetailedDto headSampleLineDetailedDto = new LineDetailedDto(EnumValuesServer.LineType.样片.getKey(), 3);
                        headSampleLineDetailedDto.setSampleType(EnumValuesServer.SampleType.尾片.getKey());
                        headSampleLineDetailedDto.setSegmentNum(index);
                        headSampleLineDetailedDto.setSegmentNo(crystalNo + "W1");
                        lineDetailedDtoMap.put(index.doubleValue() + 0.1, headSampleLineDetailedDto); //插入晶段数据
                    }
                    lineDetailedDto.setLength(lineDetailedDto.getLength() - sampleCount * 3);
                } else if (index < crystalCount) {
                    if (index == 1 || index == (crystalCount - 1)) { //尾头片
                        if (index == (crystalCount - 1) && ("W".equals(longCrystal.getWindUp()) || "V".equals(longCrystal.getWindUp()))) {
                            crystalNo.append("V");
                        }
                        if ((((tailHeadSample || middleSample) && index == (crystalCount - 1)) || ((headTailSample || middleSample) && index == 1))) {
                            LineDetailedDto tailHeadSampleLineDetailedDto = new LineDetailedDto(EnumValuesServer.LineType.样片.getKey(), 3);
                            tailHeadSampleLineDetailedDto.setSegmentNo(crystalNo + "W1");
                            tailHeadSampleLineDetailedDto.setSegmentNum(index);
                            lineDetailedDtoMap.put(index.doubleValue() + 0.1, tailHeadSampleLineDetailedDto); //插入晶段数据
                            if (index == 1 && index == (crystalCount - 1)) { //头尾尾头片
                                tailHeadSampleLineDetailedDto.setSampleType(EnumValuesServer.SampleType.头尾尾头片.getKey());
                            } else if (index == 1) {
                                tailHeadSampleLineDetailedDto.setSampleType(EnumValuesServer.SampleType.头尾片.getKey());
                                tailHeadSampleLineDetailedDto.setSegmentNum(index);
                            } else {
                                tailHeadSampleLineDetailedDto.setSampleType(EnumValuesServer.SampleType.尾头片.getKey());
                            }
                            //计算当前样片是否可以从回收料取
                            sampleCount = getSampleCount(lineDetailedDtos, index1, sampleCount);
                        }
                    }
                    if (middleSample && index < (crystalCount - 1)) { // 中间段尾片
                        LineDetailedDto tailHeadSampleLineDetailedDto = new LineDetailedDto(EnumValuesServer.LineType.样片.getKey(), 3);
                        tailHeadSampleLineDetailedDto.setSegmentNo(crystalNo + "W1");
                        tailHeadSampleLineDetailedDto.setSampleType(EnumValuesServer.SampleType.中间片.getKey());
                        tailHeadSampleLineDetailedDto.setSegmentNum(index);
                        lineDetailedDtoMap.put(index.doubleValue() + 0.1, tailHeadSampleLineDetailedDto); //插入晶段数据

                        //计算当前样片是否可以从回收料取
                        sampleCount = getSampleCount(lineDetailedDtos, index1, sampleCount);
                    }
                }
//                else if (index == 1) { //第一段
//                    if (middleSample || headTailSample) { //头尾片
//                        LineDetailedDto headSampleLineDetailedDto = new LineDetailedDto(EnumValuesServer.LineType.样片.getKey(), 3);
//                        headSampleLineDetailedDto.setSampleType(EnumValuesServer.SampleType.头尾片.getKey());
//                        headSampleLineDetailedDto.setSegmentNo(crystalNo + "W1");
//                        lineDetailedDtoMap.put(index.doubleValue() + 0.1, headSampleLineDetailedDto); //插入晶段数据
//
//                        //计算当前样片是否可以从回收料取
//                        sampleCount = getSampleCount(lineDetailedDtos, index1, sampleCount);
//                    }
//                }
                lineDetailedDto.setSegmentNo(crystalNo.toString());
            } else {
                lineDetailedDto.setSegmentNo(longCrystal.getCrystalNo() + "X" + xIndex);
                lineDetailedDto.setSegmentNum(index);
                lineDetailedDtoMap.put(index.doubleValue() + (0.2 + (xIndex * 0.01)), lineDetailedDto); //插入回收料数据
                xIndex++;
            }
        }
        Map<Double, LineDetailedDto> mapData = lineDetailedDtoMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new));
        lineDetailedDtos.clear();
        for (Map.Entry<Double, LineDetailedDto> entry : mapData.entrySet()) {
            lineDetailedDtos.add(entry.getValue());
        }
        System.out.println("画线明细：" + JSON.toJSONString(mapData));
    }

    private int getSampleCount(List<LineDetailedDto> lineDetailedDtos, Integer index1, int sampleCount) {
        LineDetailedDto nextDto = getLineDetailedInfo(lineDetailedDtos, index1);
        sampleCount = getSampleCount(sampleCount, nextDto);
        return sampleCount;
    }

    private int getSampleCount(int sampleCount, LineDetailedDto nextDto) {
        if (nextDto != null && (nextDto.getType() != EnumValuesServer.LineType.直径异常回收料.getKey() && nextDto.getType() != EnumValuesServer.LineType.孪晶回收料.getKey() && nextDto.getType() != EnumValuesServer.LineType.回收料.getKey())) {
            sampleCount++;
        } else if (nextDto != null) {
            nextDto.setLength(nextDto.getLength() - 3);
        }
        return sampleCount;
    }

    public LineDetailedDto getLineDetailedInfo(List<LineDetailedDto> lineDetailedDtos, int index) {
        if (index == -1 || lineDetailedDtos.size() <= index) {
            return null;
        } else {
            return lineDetailedDtos.get(index);
        }
    }

    @Override
    public Result createAll(LineDetailedParamDto lineDetailedParamDto, LongCrystal longCrystal, BigDecimal weightLossCoefficient, LineParamDataDto lineParamDto) {
        if (lineDetailedParamDto.getPrintNum() == null) {
            lineDetailedParamDto.setPrintNum(1);
        }
        // region 初始化，并保存长棒信息
        ProductionPaintingLine productionPaintingLine = new ProductionPaintingLine();
        setProductionPaintingLine(lineDetailedParamDto, longCrystal, productionPaintingLine);
        if (null == longCrystal.getWeight() || (null != productionPaintingLine.getTheoryWeight()
                && productionPaintingLine.getTheoryWeight().compareTo(longCrystal.getWeight()) > 0)){
            throw new BusinessException(" 单晶编号："+ lineDetailedParamDto.getCrystalNo() + ",划线理论重量为:" + productionPaintingLine.getTheoryWeight() + "，长晶棒产出重量为：" + longCrystal.getWeight() + "，不符合逻辑校验规则，请重新确认划线长度或联系生产确认产出重量!");
        }
        //处理SAP上报
        this.handleSapInfo(lineParamDto);
        // endregion 初始化，并保存长棒信息
        //补全长晶棒产出的订单号
        try {
            //保存划线头信息
            dao.save(productionPaintingLine);
            this.handleLongCrystalInfo(longCrystal,lineDetailedParamDto);
//            longCrystalService.completionLongCrystalOrder(longCrystal.getLotNo(), longCrystal.getCrystalNo(), lineDetailedParamDto.getStartTime(),lineDetailedParamDto.getMaxDiam(),lineDetailedParamDto.getMinDiam(), false);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("更新长晶棒产出状态出错："+e.getMessage());
        }
        BigDecimal totalLength = BigDecimal.ZERO;
        StringBuffer reason = new StringBuffer();
        //region 初始化头回收料数据
        List<ProductionPaintingLineDetail> productionPaintingLineDetails = new ArrayList<>();
        List<ProductionPaintingLineDetailException> productionPaintingLineDetailExceptions = new ArrayList<>();
        //装载头尾，样片的打印信息
        List<Map<String, String>> keyvaluess = new LinkedList<>();
        //装载单晶的打印信息
        List<Map<String, String>> keyvaluessDj = new LinkedList<>();

        List<String> lengths = new ArrayList<>();
        int index = 0;
        Integer segmentNum = 0;
        List<LineDetailedDto> lineDetailedDtos = lineDetailedParamDto.getLineDetailedDtos();
     /*   List<DictionaryItem> paintCrystalUsedLength = dictionaryItemService.findByThemeValueAndEnable("paintCrystalUsedLength", true);
        Map<String, String> collect = paintCrystalUsedLength.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getValue));
        if(!collect.containsKey(longCrystal.getSpecs())){
            throw new BusinessException("请前往数据字典配置规格为【" + longCrystal.getSpecs() + "】的划线晶段可用长度控制");
        }
        Integer length = Integer.valueOf(collect.get(longCrystal.getSpecs()));*/

        DictionaryItem weightRatio = null;
        //圆棒理论折算系数
        if (StringUtils.isNotBlank(longCrystal.getSpecs())){
            weightRatio = dictionaryItemService.findByThemeValueAndNameAndEnable("WeightRatio", longCrystal.getSpecs(), true);
        }
        for (int i = 0; i < lineDetailedDtos.size(); i++) {
            LineDetailedDto lineDetailedDto = lineDetailedDtos.get(i);
            String segmentNo = lineDetailedDto.getSegmentNo();
            List<DrawLineExceptionDto> exceptionDtos = lineDetailedDto.getExceptionDtos();

            //region 初始化中间段数据
            index = lineDetailedDtos.get(i).getSequence();
            // 段数
            segmentNum = lineDetailedDtos.get(i).getSegmentNum();
          /*  if(lineDetailedDtos.get(i).getType() == Integer.valueOf(EnumValuesServer.LineType.晶段.getKey()) && lineDetailedDtos.get(i).getLength() < length){
                throw new RuntimeException("晶段长度小于有效长度" + length);
            }*/
            ProductionPaintingLineDetail productionPaintingLineDetail = new ProductionPaintingLineDetail();
            productionPaintingLineDetail.setOperateReversecutDrawId(null);
            productionPaintingLineDetail.setOperateDrawId(productionPaintingLine.getId());
            productionPaintingLineDetail.setType(lineDetailedDtos.get(i).getType());
            productionPaintingLineDetail.setLength(new BigDecimal(lineDetailedDtos.get(i).getLength()));
            productionPaintingLineDetail.setWeight(null);
            productionPaintingLineDetail.setStatus(0);
            if (null != weightRatio && StringUtils.isNotBlank(weightRatio.getValue()) && null != productionPaintingLineDetail.getLength()){
                productionPaintingLineDetail.setWeight(productionPaintingLineDetail.getLength().divide(new BigDecimal(weightRatio.getValue()), 2, BigDecimal.ROUND_HALF_UP));
            }
            productionPaintingLineDetail.setDiameter(longCrystal.getSpecs());
            productionPaintingLineDetail.setRemark(lineDetailedDtos.get(i).getRemark());
            if (exceptionDtos.size() > 0) {
                productionPaintingLineDetail.setIsCut(0);
            } else {
                productionPaintingLineDetail.setIsCut(1);
            }
            productionPaintingLineDetail.setNo(lineDetailedDtos.get(i).getSegmentNo());
            productionPaintingLineDetail.setCreateTime(new Date());
            productionPaintingLineDetail.setCrystalId(longCrystal.getId());
            productionPaintingLineDetail.setParentId(0);
            productionPaintingLineDetail.setIsJoin(0);
            productionPaintingLineDetail.setCrystalType(0);
            if (lineDetailedDto.getSequence() <= 0){
                productionPaintingLineDetail.setSequence(i);
            }else {
                productionPaintingLineDetail.setSequence(lineDetailedDto.getSequence());
            }
            productionPaintingLineDetail.setSegmentNum(lineDetailedDto.getSegmentNum());
            productionPaintingLineDetail.setSampleType(lineDetailedDto.getSampleType());
            productionPaintingLineDetail.setColorful(lineDetailedDto.getColorful());
            productionPaintingLineDetails.add(productionPaintingLineDetail);
            //endregion 初始化中间段数据
            //中间段异常数据
            if (!CollectionUtils.isEmpty(exceptionDtos)) {
                exceptionDtos.stream().forEach(tt -> {
                    ProductionPaintingLineDetailException pple = new ProductionPaintingLineDetailException();
                    pple.setSegmentNo(segmentNo);
                    pple.setStartLen(tt.getStartLen());
                    pple.setLen(tt.getLen());
                    pple.setRemark(tt.getDesc());
                    productionPaintingLineDetailExceptions.add(pple);
                });
            }

            if (productionPaintingLineDetail.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                lengths.add(productionPaintingLineDetail.getLength().toString());
            }

            //region 装载中间段打印数据
            if (null == lineDetailedParamDto.getPrintType() || lineDetailedParamDto.getPrintType().contains("晶段") && productionPaintingLineDetail.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                Map<String, String> mapData = new HashMap<>();
                mapData.put("no", productionPaintingLineDetail.getNo());
                mapData.put("dopant", longCrystal.getDopant());
                mapData.put("specification", longCrystal.getSpecs());
                mapData.put("length", productionPaintingLineDetail.getLength().toString());
                mapData.put("remarks1", "");
                mapData.put("remarks2", "第" + lineDetailedDtos.get(i).getSegmentNum() + "共" + productionPaintingLine.getLineNum());
                mapData.put("colorful", lineDetailedDtos.get(i).getColorful() ? "带彩" : "");
                keyvaluessDj.add(mapData);
            }
            //装载样片
            if (null == lineDetailedParamDto.getPrintType() || lineDetailedParamDto.getPrintType().contains("样片") && productionPaintingLineDetail.getType() == EnumValuesServer.LineType.样片.getKey()) {
                Map<String, String> mapData = new HashMap<>();
                mapData.put("no", productionPaintingLineDetail.getNo());
                mapData.put("dopant", longCrystal.getDopant());
                mapData.put("specification", longCrystal.getSpecs());
                mapData.put("length", productionPaintingLineDetail.getLength().toString());
                mapData.put("remarks1", EnumValuesServer.SampleType.getText(productionPaintingLineDetail.getSampleType()));
                mapData.put("remarks2", "");
                mapData.put("colorful", "");
                keyvaluess.add(mapData);
            }
            //状态回收料
            if (null == lineDetailedParamDto.getPrintType() || lineDetailedParamDto.getPrintType().contains("回收料") && (productionPaintingLineDetail.getType() == EnumValuesServer.LineType.直径异常回收料.getKey() || productionPaintingLineDetail.getType() == EnumValuesServer.LineType.孪晶回收料.getKey() || productionPaintingLineDetail.getType() == EnumValuesServer.LineType.回收料.getKey())) {
                Map<String, String> mapData = new HashMap<>();
                mapData.put("no", productionPaintingLineDetail.getNo());
                mapData.put("dopant", longCrystal.getDopant());
                mapData.put("specification", longCrystal.getSpecs());
                mapData.put("length", productionPaintingLineDetail.getLength().toString());
                mapData.put("remarks1", "回收料");
                mapData.put("remarks2", "");
                mapData.put("colorful", "");
                keyvaluess.add(mapData);
            }
            if(productionPaintingLineDetail.getType() == EnumValuesServer.LineType.回收料.getKey()){
                totalLength = totalLength.add(productionPaintingLineDetail.getLength());
            }
            //endregion 装载中间段打印数据
        }
        //保存划线明细信息
        ProductionPaintingLineDetailDao.saveAll(productionPaintingLineDetails);
        //保存划线异常信息
        productionPaintingLineDetailExceptionDao.saveAll(productionPaintingLineDetailExceptions);
        //计算头尾样片
        this.saveSegmentAndPiece(lineDetailedParamDto, longCrystal, weightLossCoefficient, productionPaintingLine);

        Result result = wipStorageService.outStation(longCrystal.getCrystalNo(), null, null);
        if (result.getCode() != ResultCode.SUCCESS.getCode()) {
            throw new RuntimeException(result.getMessage());
        }
        List<String> imgArr = new LinkedList<>();
        try {
            //查询长棒打印模版配置信息
            DocumentPrint documentPrint = documentMouldService.findByDocumentMould(DocumentPrint.LONG_CRYSTAL_DOCUMENT_MOULD);
            if (documentPrint != null && lineDetailedParamDto.getPrintNum() != null && lineDetailedParamDto.getPrintNum() > 0) {
                List<Map<String, String>> keyvaluessA = new ArrayList<>();
                Map<String, String> mapData = new HashMap<>();
                //单晶编号
                mapData.put("crystalNo", longCrystal.getCrystalNo());
                //掺杂剂
                mapData.put("dopant", longCrystal.getDopant());
                //规格
                mapData.put("specification", longCrystal.getSpecs());
                mapData.put("pieceNum", productionPaintingLine.getPieceNum() + "P");
                mapData.put("lengths", StringUtils.join(lengths, " ") + "");
                keyvaluessA.add(mapData);
                //打印长棒编码
                Result result1 = printCrystalNo(keyvaluessA, documentPrint, lineDetailedParamDto.getPrintNum());
                if (result1.getCode() == ResultCode.SUCCESS.getCode()) {
                    if (result1.getData().toString().contains("[")) {
                        imgArr.addAll(JSON.parseArray(result1.getData().toString(), String.class));
                    }
                }
            }
        } catch (Exception e) {
        }
        try {
            //查询短棒打印模版配置信息
            //综合打印信息
            keyvaluess.addAll(keyvaluessDj);
            DocumentPrint documentPrintCrystal = documentMouldService.findByDocumentMould(DocumentPrint.CRYSTAL_DOCUMENT_MOULD);
            if (documentPrintCrystal != null && keyvaluess.size() > 0 && lineDetailedParamDto.getPrintNum() != null && lineDetailedParamDto.getPrintNum() > 0) {
                //打印短棒编码
                Result result2 = printCrystalNo(keyvaluess, documentPrintCrystal, lineDetailedParamDto.getPrintNum());
                if (result2.getData().toString().contains("[")) {
                    imgArr.addAll(JSON.parseArray(result2.getData().toString(), String.class));
                }
            }
        } catch (Exception e) {
        }

        lineDetailedParamDto.setTotalLength(totalLength);

        if (StringUtils.isNotBlank(productionPaintingLine.getEndCause())){
            reason.append(productionPaintingLine.getEndCause());
        }else {
            if (null != productionPaintingLine.getHeadLen() && productionPaintingLine.getHeadLen().compareTo(BigDecimal.ZERO) > 0){
                reason.append("头长度: " ).append(productionPaintingLine.getHeadLen()).append(";");
            }
        }
        if (StringUtils.isNotBlank(productionPaintingLine.getTopCause())){
            reason.append(productionPaintingLine.getTopCause());
        }else {
            if (null != productionPaintingLine.getTailLen() && productionPaintingLine.getTailLen().compareTo(BigDecimal.ZERO) > 0){
                reason.append("尾长度: " ).append(productionPaintingLine.getTailLen()).append(";");
            }
        }
        if (StringUtils.isNotBlank(productionPaintingLine.getMiddleAbnormalReasonShow())){
            reason.append(productionPaintingLine.getMiddleAbnormalReasonShow());
        }
        lineDetailedParamDto.setMiddleAbnormalReason(reason.toString());
        return ResultGenerator.success(imgArr);
    }

    /**
     * 处理划线 反填长晶棒信息，用于SAP回写数据问题
     * @param longCrystal
     */
    private void handleLongCrystalInfo(LongCrystal longCrystal,LineDetailedParamDto lineDetailedParamDto){
        if (null != longCrystal){
            longCrystal.setLineStartTime(lineDetailedParamDto.getStartTime());
            longCrystal.setCrystalStatus(EnumValuesFactory.CrystalStatus.已划线.getKey());
            longCrystal.setMinDiam(lineDetailedParamDto.getMinDiam());
            longCrystal.setMaxDiam(lineDetailedParamDto.getMaxDiam());
            longCrystal.setReportStatus(EnumValuesFactory.ReportStatusSap.REPORTED.getKey());
            longCrystalService.saveOrUpdate(longCrystal);
        }
    }

    /**
     * 填充划线信息
     *
     * @param lineDetailedParamDto
     * @param longCrystal
     * @param productionPaintingLine
     */
    private void setProductionPaintingLine(LineDetailedParamDto lineDetailedParamDto, LongCrystal longCrystal, ProductionPaintingLine productionPaintingLine) {
        productionPaintingLine.setLotNo(longCrystal.getLotNo());
        productionPaintingLine.setCrystalNo(longCrystal.getCrystalNo());
        productionPaintingLine.setUserName(lineDetailedParamDto.getOperatorUser());
        if (StringUtils.isNotBlank(longCrystal.getClosureIdentification())) {
            if ("W".equalsIgnoreCase(longCrystal.getClosureIdentification())) {
                productionPaintingLine.setIsSeeBottom(1);
            } else {
                productionPaintingLine.setIsSeeBottom(0);
            }
        }
        productionPaintingLine.setTemperature(lineDetailedParamDto.getTemperature());
        productionPaintingLine.setResistivity(lineDetailedParamDto.getResistivity());
        productionPaintingLine.setDopant(longCrystal.getDopant());
        productionPaintingLine.setMinDiam(lineDetailedParamDto.getMinDiam());
        productionPaintingLine.setMaxDiam(lineDetailedParamDto.getMaxDiam());
        productionPaintingLine.setIsWindUp(("W".equalsIgnoreCase(longCrystal.getWindUp()) || "Y".equalsIgnoreCase(longCrystal.getWindUp())) ? 1 : 0);
        if (StringUtils.isNotBlank(lineDetailedParamDto.getAssessment())){
            productionPaintingLine.setAssessment(lineDetailedParamDto.getAssessment());
            if (null != longCrystal.getIsCrystal() && longCrystal.getIsCrystal() == 0 && !StringUtils.equals(lineDetailedParamDto.getAssessment(),"吊多晶")){
                throw new BusinessException(" 单晶编号："+ lineDetailedParamDto.getCrystalNo() + ",划线结果判定为:" + lineDetailedParamDto.getAssessment() + "，长晶棒产出为：吊多晶,请先核对数据!");
            }
        }else {
            if (null != longCrystal.getIsCrystal() && longCrystal.getIsCrystal() == 0){
                productionPaintingLine.setAssessment("吊多晶");
            }
            //完结
            if (StringUtils.equals(longCrystal.getClosureIdentification(),"V") || StringUtils.equals(longCrystal.getClosureIdentification(),"W")){
                productionPaintingLine.setAssessment("完结");
            }
        }
        productionPaintingLine.setArea(longCrystal.getArea());
        productionPaintingLine.setSeries(longCrystal.getSeries());
        productionPaintingLine.setSubmitLength(longCrystal.getLength());
        productionPaintingLine.setValidLength(new BigDecimal(lineDetailedParamDto.getEffectiveLength()));
        productionPaintingLine.setNoTopLength(lineDetailedParamDto.getNoTopLength());
        productionPaintingLine.setPieceNum(lineDetailedParamDto.getSamplesCount());
        productionPaintingLine.setLineNum(lineDetailedParamDto.getCrystalCount());
        productionPaintingLine.setClassNo(lineDetailedParamDto.getClassNo());
        productionPaintingLine.setTeamGroup(lineDetailedParamDto.getTeamGroup());
        productionPaintingLine.setMaterialCount(null);
        //productionPaintingLine.setTopCause(lineDetailedParamDto.getTopCause());
        productionPaintingLine.setEndCause(lineDetailedParamDto.getEndCause());
        productionPaintingLine.setStartTime(lineDetailedParamDto.getStartTime());
        productionPaintingLine.setEndTime(lineDetailedParamDto.getEndTime());
        productionPaintingLine.setUnEndLength(null);
        productionPaintingLine.setBractLength(null);
        productionPaintingLine.setOtherDiam(null);
        productionPaintingLine.setLossLength(null);
        productionPaintingLine.setExperRemark(null);
        productionPaintingLine.setVehicleCode(StringUtils.isNotBlank(lineDetailedParamDto.getVehicleCode())? lineDetailedParamDto.getVehicleCode().toUpperCase() : "");
        productionPaintingLine.setLineTailLength(lineDetailedParamDto.getLineTailLength());
        productionPaintingLine.setIsTwinCrystal(0);
        productionPaintingLine.setTwinCrystalSite(null);
        productionPaintingLine.setTwinCrystalLength(null);
        productionPaintingLine.setDrawLine(lineDetailedParamDto.getDrawLine());
        productionPaintingLine.setIsometricLength(new BigDecimal(lineDetailedParamDto.getLength()));
        productionPaintingLine.setRemark(lineDetailedParamDto.getRemarks());
        productionPaintingLine.setProgram(lineDetailedParamDto.getProgram());
        productionPaintingLine.setPrintNum(lineDetailedParamDto.getPrintNum());
        productionPaintingLine.setOxidize(lineDetailedParamDto.getOxidize());
        if (StringUtils.equals(lineDetailedParamDto.getOxidize(),"是")){
            productionPaintingLine.setOxidate(1);
        }
        productionPaintingLine.setHeadResistance(lineDetailedParamDto.getHeadResistance());
        productionPaintingLine.setTailResistance(lineDetailedParamDto.getTailResistance());
        productionPaintingLine.setWeight(longCrystal.getWeight());
        productionPaintingLine.setConductiveType(longCrystal.getConductiveType());
        productionPaintingLine.setHeadLen(lineDetailedParamDto.getHeadLen());
        productionPaintingLine.setTailLen(lineDetailedParamDto.getTailLen());
        productionPaintingLine.setHighOxygen(lineDetailedParamDto.getHighOxygen());
        //圆棒理论折算系数
        if (StringUtils.isNotBlank(longCrystal.getSpecs())){
            DictionaryItem weightRatio = dictionaryItemService.findByThemeValueAndNameAndEnable("WeightRatio", longCrystal.getSpecs(), true);
            if (null != weightRatio && StringUtils.isNotBlank(weightRatio.getValue())){
                productionPaintingLine.setTheoryWeight(productionPaintingLine.getValidLength().divide(new BigDecimal(weightRatio.getValue()), 2, BigDecimal.ROUND_HALF_UP));
            }
        }

        //详细去尾信息
        if (null != lineDetailedParamDto.getLineCutTails() && ! lineDetailedParamDto.getLineCutTails().isEmpty()){
            List<LineCutTail> lineCutTails = lineDetailedParamDto.getLineCutTails();
            lineCutTails.stream().forEach(lineCutTail -> {
                if (lineCutTail.getCutTailCouse().equals("位错")){
                    productionPaintingLine.setPositionStaggered("位错");
                    productionPaintingLine.setPositionStaggeredLength(lineCutTail.getCutTailLength());
                }
                if (lineCutTail.getCutTailCouse().equals("晶裂")){
                    productionPaintingLine.setCrystalSplitting("晶裂");
                    productionPaintingLine.setCrystalSplittingLength(lineCutTail.getCutTailLength());
                }
                if (lineCutTail.getCutTailCouse().equals("多晶")){
                    productionPaintingLine.setMultipleCrystals("多晶");
                    productionPaintingLine.setMultipleCrystalsLength(lineCutTail.getCutTailLength());
                }
            });
        }
        //缺陷异常长度、原因
        productionPaintingLine.setDefectReason(lineDetailedParamDto.getDefectReason());
        productionPaintingLine.setDefectLength(lineDetailedParamDto.getDefectLength());
        //试加工字段添加
        //InspectStickRule bySpecsAndDopant = inspectStickRuleService.findBySpecsAndDopant(longCrystal.getSpecs(), longCrystal.getDopant());
        productionPaintingLine.setTrialProcess(0);
       /* if (null != bySpecsAndDopant && StringUtils.isNotBlank(bySpecsAndDopant.getStandard())){
            String[] standardArr = bySpecsAndDopant.getStandard().split("-");
            if (null != productionPaintingLine.getMinDiam() && null != productionPaintingLine.getMaxDiam() && productionPaintingLine.getMinDiam().compareTo(new BigDecimal(standardArr[0])) >= 0 && productionPaintingLine.getMaxDiam().compareTo(new BigDecimal(standardArr[0])) <= 0){
                productionPaintingLine.setTrialProcess(1);
            }
        }*/
        if (null != lineDetailedParamDto.getTrialProcess()){
            productionPaintingLine.setTrialProcess(lineDetailedParamDto.getTrialProcess());
        }

        String crystalNo = longCrystal.getCrystalNo();
        Boolean deleteFlag = false;
         List<ProductionPaintingLineHeadTailException> saveInfo = new ArrayList<>();

        //重新处理异常记录数据
        if (null != lineDetailedParamDto.getLineCutHeads()){
            //先清空记录
            productionPaintingLineHeadTailExceptionService.deleteByCrystalNo(crystalNo);
            deleteFlag = true;
            StringBuilder lineHeadInfo = new StringBuilder();
            for (LineCutTail lineCutHead : lineDetailedParamDto.getLineCutHeads()){
                if (StringUtils.isBlank(lineCutHead.getCutTailCouse()) || StringUtils.equals("null",lineCutHead.getCutTailCouse())){
                    continue;
                }
                lineHeadInfo.append(lineCutHead.getCutTailCouse()) .append(" : ").append(lineCutHead.getCutTailLength()).append(";");
                this.handleProductionPaintingLineHeadTailException(saveInfo,lineCutHead.getCutTailLength(),lineCutHead.getCutTailCouse(),0,crystalNo);
            }
            productionPaintingLine.setTopCause(lineHeadInfo.toString());
        }
        if (null != lineDetailedParamDto.getLineCutTails()){
            if (!deleteFlag){
                //先清空记录
                productionPaintingLineHeadTailExceptionService.deleteByCrystalNo(crystalNo);
            }
            StringBuilder lineTailInfo = new StringBuilder();
            for (LineCutTail lineCutTail : lineDetailedParamDto.getLineCutTails()){
                if (StringUtils.isBlank(lineCutTail.getCutTailCouse())){
                    continue;
                }
                lineTailInfo.append(lineCutTail.getCutTailCouse()) .append(" : ").append(lineCutTail.getCutTailLength()).append(";");
                this.handleProductionPaintingLineHeadTailException(saveInfo,lineCutTail.getCutTailLength(),lineCutTail.getCutTailCouse(),1,crystalNo);
            }
            productionPaintingLine.setEndCause(lineTailInfo.toString());
        }
        if (null != lineDetailedParamDto.getLineCutMiddles()){
            if (!deleteFlag){
                //先清空记录
                productionPaintingLineHeadTailExceptionService.deleteByCrystalNo(crystalNo);
            }
            StringBuilder lineMiddleInfo = new StringBuilder();
            StringBuilder lineMiddleInfoShow = new StringBuilder();
            BigDecimal totalMiddleLen = BigDecimal.ZERO;
            for (DrawLineExceptionDto lineCutMiddle : lineDetailedParamDto.getLineCutMiddles()){
                if (StringUtils.isBlank(lineCutMiddle.getDesc())){
                    continue;
                }
                lineMiddleInfo.append(lineCutMiddle.getDesc()) .append(" : ").append(lineCutMiddle.getLen()).append(" 距头位置：").append(lineCutMiddle.getStartLen()).append(";");
                lineMiddleInfoShow.append(lineCutMiddle.getDesc()) .append(" : ").append(lineCutMiddle.getLen()).append(";");
               if (null != lineCutMiddle.getLen()){
                   totalMiddleLen = totalMiddleLen.add(lineCutMiddle.getLen());
               }
                this.handleProductionPaintingLineHeadTailException(saveInfo,lineCutMiddle.getLen(),lineCutMiddle.getDesc(),2,crystalNo);
            }
            productionPaintingLine.setMiddleAbnormalReason(lineMiddleInfo.toString());
            productionPaintingLine.setMiddleAbnormalReasonShow(lineMiddleInfoShow.toString());
            productionPaintingLine.setMiddleAbnormalLength(totalMiddleLen.intValue() + "");
        }
        if (saveInfo.size() != 0){
            productionPaintingLineHeadTailExceptionService.saveAll(saveInfo);
        }

    }

    private void handleProductionPaintingLineHeadTailException(List<ProductionPaintingLineHeadTailException> saveInfo,BigDecimal len,String reason,Integer location,String crystalNo){
        if (null != saveInfo){
            ProductionPaintingLineHeadTailException productionPaintingLineHeadTailException = new ProductionPaintingLineHeadTailException();
            productionPaintingLineHeadTailException.setCrystalNo(crystalNo);
            productionPaintingLineHeadTailException.setLen(len);
            productionPaintingLineHeadTailException.setReason(reason);
            productionPaintingLineHeadTailException.setLocation(location);
            saveInfo.add(productionPaintingLineHeadTailException);
        }
    }

    private void setTailPrintInfo(LongCrystal longCrystal, List<Map<String, String>> keyvaluess, ProductionPaintingLineDetail productionPaintingLineDetailW1) {
        Map<String, String> mapDataW1 = new HashMap<>();
        mapDataW1.put("no", productionPaintingLineDetailW1.getNo());
        mapDataW1.put("dopant", longCrystal.getDopant());
        mapDataW1.put("specification", longCrystal.getSpecs());
        mapDataW1.put("length", "");
        mapDataW1.put("remarks1", "单晶尾");
        mapDataW1.put("remarks2", "");
        mapDataW1.put("colorful", "");
        keyvaluess.add(mapDataW1);
    }


    /**
     * 初始化头，尾回收料数据公用数据
     */
    private ProductionPaintingLineDetail setLineData(LongCrystal longCrystal, ProductionPaintingLine productionPaintingLine) {
        ProductionPaintingLineDetail productionPaintingLineDetailT = new ProductionPaintingLineDetail();
        productionPaintingLineDetailT.setOperateReversecutDrawId(null);
        productionPaintingLineDetailT.setOperateDrawId(productionPaintingLine.getId());
        productionPaintingLineDetailT.setType(EnumValuesServer.LineType.回收料.getKey());
        productionPaintingLineDetailT.setLength(new BigDecimal(0));
        productionPaintingLineDetailT.setWeight(null);
        productionPaintingLineDetailT.setStatus(0);
        productionPaintingLineDetailT.setDiameter(longCrystal.getSpecs());
        productionPaintingLineDetailT.setRemark(null);
        productionPaintingLineDetailT.setIsCut(0);
        productionPaintingLineDetailT.setCreateTime(new Date());
        productionPaintingLineDetailT.setCrystalId(longCrystal.getId());
        productionPaintingLineDetailT.setParentId(0);
        productionPaintingLineDetailT.setIsJoin(0);
        productionPaintingLineDetailT.setCrystalType(0);
        productionPaintingLineDetailT.setSampleType(null);
        return productionPaintingLineDetailT;
    }

    /**
     * 打印晶段编号
     *
     * @param keyvaluess
     * @param documentPrintCrystal
     */
    public Result printCrystalNo(List<Map<String, String>> keyvaluess, DocumentPrint documentPrintCrystal, int printNum) {
        PrintInfoDto printInfoDto = new PrintInfoDto();
        printInfoDto.setPrinterName(documentPrintCrystal.getPrintName());
        printInfoDto.setTemplateAddress(documentPrintCrystal.getDocumentPath());
        printInfoDto.setDocIp(documentPrintCrystal.getPrintIp());
        printInfoDto.setData(JSON.toJSONString(keyvaluess));
        printInfoDto.setPrintNum(printNum);
        if (StringUtils.isNotBlank(documentPrintCrystal.getPrintName())) {
            printService.printAsync(printInfoDto);
        }
        return printService.printShow(printInfoDto);
    }

    /**
     * 计算头尾样片
     *
     * @param lineDetailedParamDto
     * @param longCrystal
     * @param weightLossCoefficient
     * @param productionPaintingLine
     */
    public void saveSegmentAndPiece(LineDetailedParamDto lineDetailedParamDto, LongCrystal longCrystal, BigDecimal weightLossCoefficient, ProductionPaintingLine productionPaintingLine) {
        List<LineDetailedDto> list = lineDetailedParamDto.getLineDetailedDtos();
       /* // 集合排序
        Collections.sort(list);*/
        // 晶段集合
        List<SectionNoDetail> segmentNoList = new ArrayList<>();
        // 样片集合
        List<PieceDetail> pieceDetails = new ArrayList<>();
        //获取
        DefaultCrystalAttrs defaultCrystalAttrList = defaultCrystalAttrService.getDefaultCrystalAttrs(longCrystal.getDopant(), longCrystal.getSpecs(), null);
        Date date = new Date();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getType() == EnumValuesServer.LineType.晶段.getKey()) {
                SectionNoDetail segment = new SectionNoDetail();
                segment.setSectionPosiotion(list.get(i).getSegmentNum());
                segment.setLength(new BigDecimal(list.get(i).getLength()));
                segment.setWeight(new BigDecimal(list.get(i).getLength()).divide(weightLossCoefficient, 3, RoundingMode.HALF_UP));
                segment.setConductiveType(longCrystal.getConductiveType());
                segment.setDopant(longCrystal.getDopant());
                segment.setSpecs(longCrystal.getSpecs());
                segment.setCrystalNo(longCrystal.getCrystalNo());
                segment.setCrystalId(longCrystal.getId());
                segment.setLotNo(longCrystal.getLotNo());
                segment.setEquipmentCode(longCrystal.getEquipmentCode());
                segment.setProductType(longCrystal.getProductType());
                segment.setProductCode(longCrystal.getProductCode());
                segment.setProductGrade(longCrystal.getProductGrade());
                segment.setSectionNo(list.get(i).getSegmentNo());
                segment.setCreateDate(date);
                segment.setCreateUser(BaseContextHandler.getUsername());
                segment.setSegmentNum(list.get(i).getSegmentNum());
                segment.setParentId(0L);
                segment.setRetCutSegmentNum(0);
                segment.setHeadPieceNum(0);
                segment.setTailPieceNum(0);
                segment.setMaterialNum(0);
                segment.setIsFork(list.get(i).getIsFork());
                segment.setDistortion(list.get(i).getDistortion());
                segment.setColorful(list.get(i).getColorful());
                segment.setOxygenCarbonMark(EnumValuesFactory.OxygenCarbonMarkStatus.MIDDLE_SEGMENT.getKey());
                // 头回收料
                if (list.get(i).getSequence() == 0) {
                    segment.setMaterial(longCrystal.getCrystalNo() + "T");
                }
                // 尾回收料
                if (list.get(i).getSequence() == list.size()) {
                    segment.setMaterial(longCrystal.getCrystalNo() + "W");
                }
                for (int z = i - 1; z >= 0; z--) {
                    if (list.get(z).getType() == EnumValuesServer.LineType.样片.getKey()) {
                        segment.setPieceNoHead(list.get(z).getSegmentNo());
                        segment.setTailPieceNum(1);
                        segment.setOxygenCarbonMark(EnumValuesFactory.OxygenCarbonMarkStatus.HEAD_DEPEND.getKey());
                        break;
                    }
                    if (list.get(z).getType() == EnumValuesServer.LineType.孪晶回收料.getKey() || list.get(z).getType() == EnumValuesServer.LineType.直径异常回收料.getKey()) {
                        segment.setMaterial(list.get(z).getSegmentNo());
                        System.out.println("找到晶段" + list.get(i).getSegmentNo() + "对应回收料信息:" + list.get(z).getSegmentNo());
                        break;
                    } else if (list.get(z).getType() == EnumValuesServer.LineType.晶段.getKey()) {
                        break;
                    }
                }

                for (int n = i + 1; n < list.size(); n++) {
                    if (list.get(n).getType() == EnumValuesServer.LineType.样片.getKey()) {
                        segment.setHeadPieceNum(1);
                        segment.setPieceNoEnd(list.get(n).getSegmentNo());
                        segment.setOxygenCarbonMark(EnumValuesFactory.OxygenCarbonMarkStatus.TAIL_DEPEND.getKey());
                        break;
                    }
                    if (list.get(n).getType() == EnumValuesServer.LineType.孪晶回收料.getKey() || list.get(n).getType() == EnumValuesServer.LineType.直径异常回收料.getKey()) {
                        segment.setMaterial(list.get(n).getSegmentNo());
                        System.out.println("找到晶段" + list.get(i).getSegmentNo() + "对应回收料信息:" + list.get(n).getSegmentNo());
                        break;
                    } else if (list.get(n).getType() == EnumValuesServer.LineType.晶段.getKey()) {
                        break;
                    }
                }
                String type = defaultCrystalAttrService.getDefaultCrystalAttrManyTimes(defaultCrystalAttrList, segment.getLength());
                segment.setSectionType(type);
                segmentNoList.add(segment);
            }

            // 样片信息录入
            if (list.get(i).getType() == EnumValuesServer.LineType.样片.getKey()) {
                PieceDetail pieceDetail = new PieceDetail();
                pieceDetail.setPieceNo(list.get(i).getSegmentNo());
                pieceDetail.setConductiveType(longCrystal.getConductiveType());
                pieceDetail.setDopant(longCrystal.getDopant());
                pieceDetail.setSpecs(longCrystal.getSpecs());
                pieceDetail.setCrystalId(longCrystal.getId());
                pieceDetail.setCrystalNo(longCrystal.getCrystalNo());
                pieceDetail.setLotNo(longCrystal.getLotNo());
                pieceDetail.setEquipmentCode(longCrystal.getEquipmentCode());
                pieceDetail.setProductType(longCrystal.getProductType());
                pieceDetail.setProductCode(longCrystal.getProductCode());
                pieceDetail.setProductGrade(longCrystal.getProductGrade());
                pieceDetail.setBackCut(EnumValuesFactory.ConfirmIdentification.NO.getValue());
                pieceDetail.setCreateDate(date);
                pieceDetails.add(pieceDetail);
            }
        }

        // 插入样片信息表
        this.pieceDetailDao.saveAll(pieceDetails);
        // 插入晶段信息表
      /*  //针对美科三期MES，从尾到头画线，需要把piece_no_end 和 piece_no_head互换一下
        String startLinePostion = lineDetailedParamDto.getStartLinePostion();
        if (StringUtils.equals(startLinePostion, DRAWLINERIGHTPOSTION)) {
            segmentNoList.stream().forEach(t -> {
                String temp = t.getPieceNoHead();
                t.setPieceNoHead(t.getPieceNoEnd());
                t.setPieceNoEnd(temp);
            });
        }*/
        this.sectionNoDetailDao.saveAll(segmentNoList);
    }


    @Override
    public void getCrystalNoInfos(LineDetailedParamDto lineDetailedParamDto, LongCrystal longCrystal) {
        //直径开始，结束位置
        List<int[]> unusualLengths = new LinkedList<>();
        //鸾晶开始，结束位置
        List<int[]> unusualLength1s = new LinkedList<>();
        lineDetailedParamDto.getLineDetailedDtos().sort(Comparator.comparing(LineDetailedDto::getSequence));
        int index = 0, count = 1, lastType = -1;
        int crystalLength = 0, effectiveLength = 0;
        int samplesCount = 0, crystalCount = 0;
        int segmentCount = 0;
        int xIndex = 1;
        for (LineDetailedDto lineDetailedDto : lineDetailedParamDto.getLineDetailedDtos()) {
            if (lineDetailedDto.getLength() < 0) {
                throw new RuntimeException("分段的长度不能为负数：" + lineDetailedDto.getLength());
            }
            if (lineDetailedDto.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                segmentCount++;
            }
        }
        for (LineDetailedDto lineDetailedDto : lineDetailedParamDto.getLineDetailedDtos()) {
            String crystalNo = lineDetailedParamDto.getCrystalNo() + String.format("%02d", index + 1);
            lineDetailedDto.setSegmentNum(index + 1);
            if (segmentCount - 2 == index) {
                if ("W".equals(longCrystal.getWindUp()) || "V".equals(longCrystal.getWindUp())) {
                    crystalNo += "V";
                }
            }
            if (segmentCount - 1 == index) {//最后一段
                crystalNo += "W";
            }
            if (lastType == -1 || (lastType != lineDetailedDto.getType()) || !(lastType == EnumValuesServer.LineType.孪晶回收料.getKey() || lineDetailedDto.getType() == EnumValuesServer.LineType.孪晶回收料.getKey()) || !(lineDetailedDto.getType() == EnumValuesServer.LineType.直径异常回收料.getKey() || lastType == EnumValuesServer.LineType.直径异常回收料.getKey())) {
                lastType = lineDetailedDto.getType();
                count = 1;
            } else {
                count++;
            }
            if (lineDetailedDto.getType() == EnumValuesServer.LineType.样片.getKey()) {
                lineDetailedDto.setSampleType(EnumValuesServer.SampleType.中间片.getKey());
                if (index == 0) {
                    lineDetailedDto.setSegmentNo(crystalNo + "T" + count);
                    lineDetailedDto.setSampleType(EnumValuesServer.SampleType.头片.getKey());
                } else {
                    // 头尾片，尾头片
                    if (index == 1 || segmentCount - 1 == index) {
                        if (index == 1 && segmentCount - 1 == index) {
                            lineDetailedDto.setSampleType(EnumValuesServer.SampleType.头尾尾头片.getKey());
                            lineDetailedDto.setSegmentNo(lineDetailedParamDto.getCrystalNo() + String.format("%02d", index) + "W" + count);
                        } else if (index == 1) {
                            lineDetailedDto.setSampleType(EnumValuesServer.SampleType.头尾片.getKey());
                            lineDetailedDto.setSegmentNo(lineDetailedParamDto.getCrystalNo() + String.format("%02d", index) + "W" + count);
                        }
                        //尾头片
                        else {
                            if ("W".equals(longCrystal.getWindUp()) || "V".equals(longCrystal.getWindUp())) {
                                lineDetailedDto.setSegmentNo(lineDetailedParamDto.getCrystalNo() + String.format("%02d", index) + "V" + "W" + count);
                            } else {
                                lineDetailedDto.setSegmentNo(lineDetailedParamDto.getCrystalNo() + String.format("%02d", index) + "W" + count);
                            }
                            lineDetailedDto.setSampleType(EnumValuesServer.SampleType.尾头片.getKey());
                        }
                    }
                    //尾片
                    else {
                        StringBuilder sectionNo = new StringBuilder(lineDetailedParamDto.getCrystalNo());
                        sectionNo.append(String.format("%02d", index));
                        if (segmentCount == index) {
                            sectionNo.append("W");
                        }
                        sectionNo.append("W").append(count);
                        lineDetailedDto.setSegmentNo(sectionNo.toString());
                        lineDetailedDto.setSampleType(EnumValuesServer.SampleType.尾片.getKey());
                    }
                    if (index > 0 && index < segmentCount) {
                        effectiveLength += lineDetailedDto.getLength();
                    }
                }
                samplesCount++;
            } else if (lineDetailedDto.getType() == EnumValuesServer.LineType.孪晶回收料.getKey()) {
                int[] arr = new int[2];
                arr[0] = crystalLength;
                arr[1] = lineDetailedDto.getLength();
                unusualLength1s.add(arr);
                lineDetailedDto.setSegmentNo(lineDetailedParamDto.getCrystalNo() + "X" + xIndex);
                xIndex++;
                lineDetailedParamDto.setUnusualLength1s(unusualLength1s);
            } else if (lineDetailedDto.getType() == EnumValuesServer.LineType.直径异常回收料.getKey()) {
                int[] arr = new int[2];
                arr[0] = crystalLength;
                arr[1] = lineDetailedDto.getLength();
                unusualLengths.add(arr);
                lineDetailedDto.setSegmentNo(lineDetailedParamDto.getCrystalNo() + "X" + xIndex);
                xIndex++;
                lineDetailedParamDto.setUnusualLengths(unusualLengths);
            } else if (lineDetailedDto.getType() == EnumValuesServer.LineType.回收料.getKey()) {
                lineDetailedDto.setSegmentNo(lineDetailedParamDto.getCrystalNo() + "X" + xIndex);
                xIndex++;
                effectiveLength += lineDetailedDto.getLength();
            } else if (lineDetailedDto.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                lineDetailedDto.setSegmentNo(crystalNo);
                crystalCount++;
                index++;
                effectiveLength += lineDetailedDto.getLength();
            }
            if (index > 0) {
                crystalLength += lineDetailedDto.getLength();
            }
        }
        lineDetailedParamDto.setCrystalCount(crystalCount);
        lineDetailedParamDto.setSamplesCount(samplesCount);
        lineDetailedParamDto.setEffectiveLength(effectiveLength);
    }


    @Override
    public void getDrawlinginfos(DrawLineDto drawLineDto, LongCrystal longCrystal) {
        String startLinePostion = drawLineDto.getStartLinePostion();
        String crystalNo = drawLineDto.getCrystalNo();
        if (StringUtils.isEmpty(startLinePostion)) {
            throw new BusinessException("请确定划线开始位置");
        }
        int effectiveLength = 0;
        int segmentCount = 0;
        int drawlinedetailLen = 0;
        for (DrawLineDetailDto line : drawLineDto.getLineDetailedDtos()) {
            if (line.getLength().compareTo(BigDecimal.ZERO) < 0) {
                throw new RuntimeException("晶段的长度不能为负数：" + line.getLength());
            }
            if (line.getType() == EnumValuesServer.LineType.晶段.getKey()) {
                segmentCount++;
            }
            drawlinedetailLen += line.getLength().intValue();
        }
        //校验画线长度和明细长度是否一致
        if (drawlinedetailLen != drawLineDto.getLength()) {
            throw new BusinessException(" 明细总长 " + drawlinedetailLen + "！=总长 " + drawLineDto.getLength());
        }
        List<DictionaryItem> paintCrystalUsedLength = dictionaryItemService.findByThemeValueAndEnable("paintCrystalUsedLength", true);
        Map<String, String> collect = paintCrystalUsedLength.stream().collect(Collectors.toMap(DictionaryItem::getName, DictionaryItem::getValue));
        if(!collect.containsKey(longCrystal.getSpecs())){
            throw new BusinessException("请前往数据字典配置规格为【" + longCrystal.getSpecs() + "】的划线晶段可用长度控制");
        }
        Integer length = Integer.valueOf(collect.get(longCrystal.getSpecs()));
        if (StringUtils.equals(startLinePostion, DRAWLINELEFTPOSTION)) {
            startLeftDrawLine(drawLineDto, effectiveLength, segmentCount, crystalNo, length);
        } else if (StringUtils.equals(startLinePostion, DRAWLINERIGHTPOSTION)) {
            startRightDrawLine(drawLineDto, effectiveLength, segmentCount, crystalNo, length);
        }
    }


    private void startRightDrawLine(DrawLineDto drawLineDto, int effectiveLength, int segmentCount, String crystalNo, Integer length) {
        int preType = 0;
        int preSequence = 0;
        //赋给晶段的编号
        int segmentIndex = segmentCount;
        //晶段的索引
        int inputSegmentIndex = segmentCount;
        //判断是否有中间段样片，主要用于后面在赋晶段的编号时用到。
        int count = (int) drawLineDto.getLineDetailedDtos().stream().filter(t -> t.getType() == 1).count();
        boolean tpFlag = false;
        if (count > 3) {
            tpFlag = true;
        }

        for (int i = 0; i < drawLineDto.getLineDetailedDtos().size(); i++) {
            DrawLineDetailDto lineDetailedDto = drawLineDto.getLineDetailedDtos().get(i);
            Integer cureentSequence = lineDetailedDto.getSequence();
            int curType = lineDetailedDto.getType();
            int curesequence = cureentSequence;
            //第二个位置开始，连续的位置不能是样片
            if (curesequence > 0 && preType == curType && preType == 1 && curType == 1) {
                throw new RuntimeException("连续的位置不能都是样片");
            } else {
                preType = curType;
            }
            preSequence = i;
            if (cureentSequence == 0) {
                if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "WP");
                    lineDetailedDto.setSegmentNum(segmentCount);
                } else if (lineDetailedDto.getType() == 2) {
                    lineDetailedDto.setSegmentNo(crystalNo + "WX");
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + "WY");
                    lineDetailedDto.setSegmentNum(segmentCount);
                    segmentIndex--;
                    inputSegmentIndex--;
                }
            } else if (cureentSequence == 1) {
                if (lineDetailedDto.getType() == 0 && inputSegmentIndex == segmentCount) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + "WY");
                    lineDetailedDto.setSegmentNum(segmentCount);
                    segmentIndex--;
                    inputSegmentIndex--;
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "Y");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    if (!tpFlag) {
                        segmentIndex--;
                    }
                    effectiveLength = effectiveLength + lineDetailedDto.getLength().intValue();
                } else if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "WP");
                    lineDetailedDto.setSegmentNum(segmentCount);
                }
            } else if (cureentSequence > 1 && cureentSequence + 1 != drawLineDto.getLineDetailedDtos().size()) {
                if (lineDetailedDto.getType() == 0 && inputSegmentIndex == segmentCount) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + "WY");
                    lineDetailedDto.setSegmentNum(segmentCount);
                    segmentIndex--;
                    inputSegmentIndex--;
                } else if (lineDetailedDto.getType() == 1 && cureentSequence + 1 == drawLineDto.getLineDetailedDtos().size() - 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "TP");
                    lineDetailedDto.setSegmentNum(1);
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "Y");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    if (!tpFlag) {
                        segmentIndex--;
                    }
                    effectiveLength = effectiveLength + lineDetailedDto.getLength().intValue();
                } else if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "P");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    if (tpFlag) {
                        segmentIndex--;
                    }
                    inputSegmentIndex--;
                }
            } else if (cureentSequence + 1 == drawLineDto.getLineDetailedDtos().size()) {
                if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "TP");
                    lineDetailedDto.setSegmentNum(1);
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "Y");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    effectiveLength = effectiveLength + lineDetailedDto.getLength().intValue();
                } else if (lineDetailedDto.getType() == 2) {
                    lineDetailedDto.setSegmentNo(crystalNo + "TX");
                }
            }
        }
        drawLineDto.setCrystalCount(segmentCount);
        drawLineDto.setSamplesCount((int) drawLineDto.getLineDetailedDtos().stream().filter(t -> {
            return t.getType() == 1;
        }).count());
        drawLineDto.setEffectiveLength(effectiveLength);
    }


    private void startLeftDrawLine(DrawLineDto drawLineDto, int effectiveLength, int segmentCount, String crystalNo, Integer length) {
        int preType = 0;
        int preSequence = 0;
        int segmentIndex = 1;
        //传入的晶段
        int inputSegmentIndex = 0;
        //判断是否有中间段样片，主要用于后面在赋晶段的编号时用到。
        int count = (int) drawLineDto.getLineDetailedDtos().stream().filter(t -> t.getType() == 1).count();
        boolean tpFlag = false;
        if (count > 3) {
            tpFlag = true;
        }
        for (int i = 0; i < drawLineDto.getLineDetailedDtos().size(); i++) {
            DrawLineDetailDto lineDetailedDto = drawLineDto.getLineDetailedDtos().get(i);
            Integer cureentSequence = lineDetailedDto.getSequence();
            int curType = lineDetailedDto.getType();
            int curesequence = cureentSequence;
            //第二个位置开始，连续的位置不能是样片
            if (curesequence > 0 && preType == curType && preType == 1 && curType == 1) {
                throw new RuntimeException("连续的位置不能都是样片");
            } else {
                preType = curType;
            }
            preSequence = i;
            if (cureentSequence == 0) {
                if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "TP");
                    lineDetailedDto.setSegmentNum(1);
                } else if (lineDetailedDto.getType() == 2) {
                    lineDetailedDto.setSegmentNo(crystalNo + "TX");
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "Y");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    segmentIndex++;
                    inputSegmentIndex++;
                    effectiveLength = effectiveLength + lineDetailedDto.getLength().intValue();
                }
            } else if (cureentSequence == 1) {
                if (lineDetailedDto.getType() == 0 && inputSegmentIndex == segmentCount - 1) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + "WY");
                    lineDetailedDto.setSegmentNum(segmentCount);
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "Y");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    effectiveLength = effectiveLength + lineDetailedDto.getLength().intValue();
                    segmentIndex++;
                    inputSegmentIndex++;
                } else if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "TP");
                    lineDetailedDto.setSegmentNum(1);
                }
            } else if (cureentSequence > 1 && cureentSequence + 1 != drawLineDto.getLineDetailedDtos().size()) {
                if (lineDetailedDto.getType() == 0 && inputSegmentIndex == segmentCount - 1) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + "WY");
                    lineDetailedDto.setSegmentNum(segmentCount);
                } else if (lineDetailedDto.getType() == 1 && cureentSequence + 1 == drawLineDto.getLineDetailedDtos().size() - 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "WP");
                    lineDetailedDto.setSegmentNum(segmentCount);
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "Y");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    effectiveLength = effectiveLength + lineDetailedDto.getLength().intValue();
                    if (!tpFlag) {
                        segmentIndex++;
                    }
                    inputSegmentIndex++;
                } else if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + segmentIndex + "P");
                    lineDetailedDto.setSegmentNum(segmentIndex);
                    if (tpFlag) {
                        segmentIndex++;
                    }
                }

            } else if (cureentSequence + 1 == drawLineDto.getLineDetailedDtos().size()) {
                if (lineDetailedDto.getType() == 1) {
                    lineDetailedDto.setSegmentNo(crystalNo + "WP");
                    lineDetailedDto.setSegmentNum(segmentCount);
                } else if (lineDetailedDto.getType() == 0) {
                    if(lineDetailedDto.getLength().compareTo(new BigDecimal(length)) < 0){
                        throw new RuntimeException("晶段长度小于有效长度" + length);
                    }
                    lineDetailedDto.setSegmentNo(crystalNo + "WY");
                    lineDetailedDto.setSegmentNum(segmentCount);
                    effectiveLength = effectiveLength + lineDetailedDto.getLength().intValue();
                } else if (lineDetailedDto.getType() == 2) {
                    lineDetailedDto.setSegmentNo(crystalNo + "WX");
                }

            }
        }
        drawLineDto.setCrystalCount(segmentCount);
        drawLineDto.setSamplesCount((int) drawLineDto.getLineDetailedDtos().stream().filter(t -> {
            return t.getType() == 1;
        }).count());
        drawLineDto.setEffectiveLength(effectiveLength);
    }

    @Override
    public void deleteInfo(Long id) {
        ProductionPaintingLine entity = get(id);
        if (entity == null) {
            throw new RuntimeException("原信息不存在");
        }
        LongCrystal byCrystalNo = longCrystalService.findByCrystalNo(entity.getCrystalNo());
        if(null != byCrystalNo.getRodPulled() && byCrystalNo.getRodPulled() == 1){
            throw new BusinessException("长晶棒信息已被拉取，无法删除");
        }
        //将划线删除时间记录到长晶棒，用于SAP 上报记录
        byCrystalNo.setDeleteTime(new Date());
        longCrystalService.saveOrUpdate(byCrystalNo);
        wipStorageService.selectWipStorage(entity.getCrystalNo(), EnumValuesFactory.WipStorageCode.毛棒截断.getKey(), false);
        wipStorageService.exitStation(entity.getCrystalNo());
        dao.deleteById(id);

        // 找到所有划线的晶段样片编号
        List<String> nos = this.productionPaintingLineDetailDao.findByOperateDrawId(id);

        // 删除样片
        List<PieceDetail> PieceNo = this.pieceDetailDao.findByPieceNo(nos);
        if (PieceNo != null && PieceNo.size() > 0) {
            this.pieceDetailDao.deleteInBatch(PieceNo);
        }

        // 删除晶段
        List<SectionNoDetail> SectionNos = this.sectionNoDetailDao.findBySectionNos(nos);
        if (SectionNos != null && SectionNos.size() > 0) {
            this.sectionNoDetailDao.deleteInBatch(SectionNos);
        }

//        this.productionPaintingLineDetailDao.deleteByOperateDrawId(id);
        // 删除划线记录时，删除所有划线详情
        this.productionPaintingLineDetailDao.deleteByCrystalId(byCrystalNo.getId());

        //根据晶段编号，删除异常明细信息
        if (!CollectionUtils.isEmpty(nos)) {
            productionPaintingLineDetailExceptionService.deleteBySegmentNo(nos);
        }

        /*//删除划线记录时，发送划线完结标志到MCS
        if (null != entity.getVehicleCode() && !StringUtils.isEmpty(entity.getVehicleCode())){
            sendWjbzToMcsForDeletePaintngLine(entity.getVehicleCode());
        }*/


    }

    @Override
    public ProductionPaintingLine findByCrystalNo(String crystalNo) {
        return dao.findByCrystalNo(crystalNo);
    }




    @ServiceLogs(description = "删除划线记录或者划线失败时，发送划线完结标志到MCS")
    @Override
    public void sendWjbzToMcsForDeletePaintngLine(String vehicleCode) {
        ybMesThreadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("发送划线完结标志到MCS -> " + vehicleCode);
                //送验车绑定的单晶
                List<String> productionBindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(vehicleCode);
                List<ProductionPaintingLine> vehicleCodeList = dao.findByVehicleCodes(vehicleCode);

                int index = 0;

                /**
                 * a的段数比b多， 下发a的段数
                 */
                Integer lineNum = 0;
                for (String productionBinding : productionBindingTrays) {
                    for (ProductionPaintingLine productionPaintingLine : vehicleCodeList) {
                        if (productionBinding.equals(productionPaintingLine.getCrystalNo())) {
                            index++;
                            if (lineNum < productionPaintingLine.getLineNum()) {
                                // a的段数比b多， 下发a的段数
                                lineNum = productionPaintingLine.getLineNum();
                            }
                            break;
                        }
                    }
                }
                String data = "";
                String send = "";
                try {
                    if (index != productionBindingTrays.size()) {
                        JSONObject materialDetailInfoJson = new JSONObject(3);
                        materialDetailInfoJson.put("isDrew", 0);
                        materialDetailInfoJson.put("isWeight", 0);
                        materialDetailInfoJson.put("drewCount", lineNum);
                        materialDetailInfoJson.put("indexNum", productionBindingTrays.size());
                        HxbsDto hxbsDto = new HxbsDto();
                        hxbsDto.setFrockCode(vehicleCode);
                        hxbsDto.setMaterialDetailInfo(materialDetailInfoJson.toJSONString());
                        hxbsDto.setMaterialNo(StringUtils.join(productionBindingTrays.toArray(), "|"));
                        data = JSONObject.toJSONString(hxbsDto);

                        String url = mcsServiceUrl + "/" + HXBD;
                        ResponseEntity<String> responseEntity = restUtils.send(data, url, "");
                        send = responseEntity.getBody();
                        JSONObject jsonObject = JSONObject.parseObject(send);
                        String code = jsonObject.getString("status");
                        if (!"Success".equals(code)) {
                            throw new BusinessException("划线标识下发MCS失败：" + send + " - " + data);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("划线标识下发MCS失败", e);
                } finally {
                    log.info("划线标识下发MCS： " + data +
                            " index： " + index +
                            " send： " + send +
                            " productionBindingTrays.size()： " + productionBindingTrays.size() +
                            " vehicleCodeList： " + Arrays.toString(vehicleCodeList.toArray()));
                }
            }
        });
    }




    @Override
    @ServiceLogs(description = "发送划线完结标志到MCS")
    public void sendWjbzToMcs(String vehicleCode) {
        ybMesThreadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("发送划线完结标志到MCS -> " + vehicleCode);
                //送验车绑定的单晶
                List<String> productionBindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(vehicleCode);
                //划线的单晶
//        List<String> vehicleCodeList = dao.findByVehicleCode(vehicleCode);
                List<ProductionPaintingLine> vehicleCodeList = dao.findByVehicleCodes(vehicleCode);

                int index = 0;

                /**
                 * a的段数比b多， 下发a的段数
                 */
                Integer lineNum = 0;
                for (String productionBinding : productionBindingTrays) {
                    for (ProductionPaintingLine productionPaintingLine : vehicleCodeList) {
                        if (productionBinding.equals(productionPaintingLine.getCrystalNo())) {
                            index++;
                            if (lineNum < productionPaintingLine.getLineNum()) {
                                // a的段数比b多， 下发a的段数
                                lineNum = productionPaintingLine.getLineNum();
                            }
                            break;
                        }
                    }
                }
                String data = "";
                String send = "";
                try {

                    if (index == productionBindingTrays.size()) {
                        JSONObject materialDetailInfoJson = new JSONObject(3);
                        materialDetailInfoJson.put("isDrew", 1);
                        materialDetailInfoJson.put("isWeight", 1);
                        materialDetailInfoJson.put("drewCount", lineNum);
                        materialDetailInfoJson.put("indexNum", productionBindingTrays.size());
                        HxbsDto hxbsDto = new HxbsDto();
                        hxbsDto.setFrockCode(vehicleCode);
                        hxbsDto.setMaterialDetailInfo(materialDetailInfoJson.toJSONString());
                        hxbsDto.setMaterialNo(StringUtils.join(productionBindingTrays.toArray(), "|"));
                        data = JSONObject.toJSONString(hxbsDto);

                        String url = mcsServiceUrl + "/" + HXBD;
//                        String url = "http://10.141.0.130:8806/agv/mesToMcsController/updateMaterial";
                        ResponseEntity<String> responseEntity = restUtils.send(data, url, "");
                        send = responseEntity.getBody();
                        JSONObject jsonObject = JSONObject.parseObject(send);
                        String code = jsonObject.getString("status");
                        if (!"Success".equals(code)) {
                            throw new BusinessException("划线标识下发MCS失败：" + send + " - " + data);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("划线标识下发MCS失败", e);
                } finally {
                    log.info("划线标识下发MCS： " + data +
                            " index： " + index +
                            " send： " + send +
                            " productionBindingTrays.size()： " + productionBindingTrays.size() +
                            " vehicleCodeList： " + Arrays.toString(vehicleCodeList.toArray()));
                }
            }
        });
    }

    @Override
    public Result<DrawLineDto> matchDrawLineNew(DrawLineParamDto drawLineParamDto) {

        String crystalNo = drawLineParamDto.getCrystalNo();
        //获取晶体信息
        LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
        if (null == longCrystal){
            throw new RuntimeException("长晶棒产出记录，已不存在");
        }
        //新添加逻辑
        if (StringUtils.isBlank(drawLineParamDto.getAssessment())){
            if (null != longCrystal.getIsCrystal() && longCrystal.getIsCrystal() == 0){
                drawLineParamDto.setAssessment("吊多晶");
            }
            //完结
            if (StringUtils.equals(longCrystal.getClosureIdentification(),"V") || StringUtils.equals(longCrystal.getClosureIdentification(),"W")){
                drawLineParamDto.setAssessment("完结");
            }
        }

        String specs = longCrystal.getSpecs();
        if (StringUtils.isBlank(specs)){
            throw new RuntimeException("长晶棒产出记录规格为空！");
        }
        String dopant = longCrystal.getDopant();
        if (StringUtils.isBlank(dopant)){
            throw new RuntimeException("长晶棒产出记录掺杂剂为空！");
        }
        if (CollectionUtils.isEmpty(drawLineParamDto.getPaintingLine())){
            throw new RuntimeException("划线规则不存在！！");
        }

        //获取送验
        InspectionRecord lastCrystalNoLog = inspectionRecordService.getLastCrystalNoLog(crystalNo);

        String inspectionRemark = null;
        if (null != lastCrystalNoLog){
            //送验备注
            inspectionRemark = lastCrystalNoLog.getAbnormal();
        }

        //获取划线规则
        PaintingLine paintingLine = drawLineParamDto.getPaintingLine().get(0);

        //异常分段最大长度
        Integer abnormalSegmenteLength = paintingLine.getAbnormalSegmenteLength();

        //获取取片规则
        List<PickingRule> pickingRuleList = drawLineParamDto.getPickingRule();
        if (CollectionUtils.isEmpty(pickingRuleList)){
            pickingRuleList = pickingRuleService.getPickingRule(longCrystal.getSpecs(), longCrystal.getEquipmentCode(), longCrystal.getDopant(), longCrystal.getWindUp(),inspectionRemark);
        }
        //取片规则是否有重复
        Map<String, Integer> pickingRuleMap = new HashMap<>();
        for (PickingRule pickingRule : pickingRuleList){
            BigDecimal pieceThickness = pickingRule.getPieceThickness();
            if (StringUtils.isNotEmpty(pickingRule.getPieceSite())) {
                Arrays.stream(StringUtils.split(pickingRule.getPieceSite(), ",")).forEach(position -> {
                    if (pickingRuleMap.containsKey(position)) {
                        throw new BusinessException("取片规则重复只允许头片，尾片，每段取片，请重新配置取片规则！");
                    }
                    pickingRuleMap.put(position, pieceThickness.intValue());
                });
            }
        }

        Integer thicknessSample = 0;
        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue()) && null != pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())){
            thicknessSample = pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.每段取片.getValue());
        }

        //去头总长度
        Integer headTotalLength = drawLineParamDto.getHeadLength() + (null != paintingLine.getHeadDefaultLength() ? paintingLine.getHeadDefaultLength() : 0);
        if (null == headTotalLength || headTotalLength <= 0 && null != paintingLine.getHeadDefaultLength()){
            headTotalLength = paintingLine.getHeadDefaultLength();
        }

        /*if (drawLineParamDto.getHeadLength() > 0){
            headTotalLength += drawLineParamDto.getHeadLength();
        }*/

        //去尾总长度
        Integer tailTotalLength = drawLineParamDto.getTailLength();
       /* if (null != drawLineParamDto.getTailLen()){
            tailTotalLength += drawLineParamDto.getTailLen().intValue();
        }*/

        //异常总长度
        Integer abnormalTotalLength = 0;

        List<DrawLineExceptionDto> midExeceptionLen = drawLineParamDto.getMidExeceptionLen();
        //计算有效长度 划线长度一(头异常长度+中间段异常长度+尾异常长)
        Integer effectiveLength = 0;

        Integer recycledFlow = 1;

        Integer sampleCount = 0;
        Integer inspectCount = 0;
        //划线长度
        Integer length = drawLineParamDto.getLength();
        Map<Integer,Integer> rollIndexMap = new LinkedHashMap<>();
        Map<Integer,DrawLineDetailDto> resultMap = new LinkedHashMap<>();
        Integer deleteLength = 0;
        Boolean materialRecycledFlag = false;
        //添加氧高生成全部回收料
        if ((StringUtils.isNotBlank(drawLineParamDto.getAssessment()) && Constants.MATERIAL_RECYCLED_ASSESSMENT_LIST.contains(drawLineParamDto.getAssessment()))
                || (null != drawLineParamDto.getHighOxygen() && drawLineParamDto.getHighOxygen() == 1)){
            materialRecycledFlag = true;
            recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,length,crystalNo,recycledFlow,true);
        }else {

            Integer startPosition = headTotalLength;
            if (!CollectionUtils.isEmpty(midExeceptionLen)){
                //新逻辑，划线处理中间段重叠问题
                midExeceptionLen = this.handleMidExeception(midExeceptionLen, longCrystal, headTotalLength);
                DrawLineExceptionDto drawLineExceptionDtoNew = midExeceptionLen.get(0);
                if (drawLineExceptionDtoNew.getStartLen().compareTo(BigDecimal.ZERO) == 0){
                    headTotalLength = drawLineExceptionDtoNew.getLen().intValue();
                    startPosition = headTotalLength;
                    deleteLength = headTotalLength;
                }
                //先处理发白
                for (DrawLineExceptionDto drawLineExceptionDto : midExeceptionLen){
                    abnormalTotalLength += drawLineExceptionDto.getLen().intValue();
                    // 去掉发白临段晶段类型为回收料  需求修改 4.8
                    if (StringUtils.isNotBlank(drawLineExceptionDto.getDesc()) && drawLineExceptionDto.getDesc().contains("发 白")){
                        abnormalTotalLength = 0;
                        headTotalLength = drawLineExceptionDto.getStartLen().intValue() + 400;
                        startPosition = headTotalLength;
                    }
                    rollIndexMap.put(drawLineExceptionDto.getStartLen().intValue(),drawLineExceptionDto.getLen().intValue());
                }

                recycledFlow = handHeadR(resultMap,abnormalSegmenteLength,null != drawLineParamDto.getHeadLen() ? headTotalLength + drawLineParamDto.getHeadLen().intValue() : headTotalLength ,crystalNo,recycledFlow,true,pickingRuleMap);
                for(Map.Entry<Integer,Integer> entry:rollIndexMap.entrySet()) {
                    Integer rollIndexPosition = entry.getKey();
                    Integer lengthException = entry.getValue();
                    if (rollIndexPosition > startPosition){
                        effectiveLength = rollIndexPosition - startPosition;
                        handleInspectSegmente(resultMap, paintingLine, effectiveLength, thicknessSample);
                        startPosition = rollIndexPosition + lengthException;
                        //生成回收料编号
                        if (null != lengthException && lengthException != 0){
                            recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,lengthException,crystalNo,recycledFlow,false);
                        }
                    }
                }
                //处理最后段数
                effectiveLength = length - tailTotalLength - startPosition;
                handleInspectSegmente(resultMap, paintingLine, effectiveLength, thicknessSample);

            }else {
           /* if (null != headTotalLength && headTotalLength != 0){
                recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,headTotalLength,crystalNo,recycledFlow,true);
            }
            if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue()) && !pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())){
                DrawLineDetailDto drawLineDetailDtoSample = new DrawLineDetailDto();
                //样片
                drawLineDetailDtoSample.setType(1);
                drawLineDetailDtoSample.setLength(new BigDecimal(pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue())));
                resultMap.put(resultMap.size(),drawLineDetailDtoSample);
            }*/
                recycledFlow = handHeadR(resultMap,abnormalSegmenteLength,null != drawLineParamDto.getHeadLen() ? headTotalLength + drawLineParamDto.getHeadLen().intValue() : headTotalLength,crystalNo,recycledFlow,true,pickingRuleMap);
                //计算有效长度 划线长度一(头异常长度+中间段异常长度+尾异常长)
                effectiveLength = length - headTotalLength - abnormalTotalLength - tailTotalLength;
                handleInspectSegmente(resultMap, paintingLine, effectiveLength, thicknessSample);
            }

            if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.尾片.getValue())){
                DrawLineDetailDto drawLineDetailDtoSample = new DrawLineDetailDto();
                //样片
                drawLineDetailDtoSample.setType(1);
                drawLineDetailDtoSample.setLength(new BigDecimal(pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.尾片.getValue())));
                resultMap.put(resultMap.size(),drawLineDetailDtoSample);
            }
            if (null != tailTotalLength && tailTotalLength != 0 || (null != drawLineParamDto.getTailLen() && drawLineParamDto.getTailLen().compareTo(BigDecimal.ZERO) > 0)){
                recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,null != drawLineParamDto.getTailLen() ? drawLineParamDto.getTailLen().intValue() + tailTotalLength : tailTotalLength,crystalNo,recycledFlow,false);
            }


            for(Map.Entry<Integer,DrawLineDetailDto> entry:resultMap.entrySet()) {
                DrawLineDetailDto drawLineDetailDto = entry.getValue();
                if (drawLineDetailDto.getType() == 0){
                    inspectCount++;
                }else if (drawLineDetailDto.getType() == 1){
                    sampleCount++;
                }
            }

            //处理单晶编号
            handeCrystalNo(resultMap,inspectCount,crystalNo,null != drawLineParamDto.getTurnPale() && drawLineParamDto.getTurnPale() == 1);
            //处理样片编号
            handeSampleNo(resultMap,sampleCount,crystalNo);
        }
        DrawLineDto drawLineDto = new DrawLineDto();
        drawLineDto.setCrystalNo(crystalNo);
        drawLineDto.setEffectiveLength(materialRecycledFlag ? 0 : (length - headTotalLength - abnormalTotalLength - tailTotalLength + deleteLength));
        List<DrawLineDetailDto> lineDetailedDtos = new ArrayList<>();
        Integer index = 0;
        for(Map.Entry<Integer,DrawLineDetailDto> entry:resultMap.entrySet()) {
            DrawLineDetailDto drawLineDetailDto = entry.getValue();
            //最后一段回收料添加W
            index++;
            if (index == resultMap.size() && drawLineDetailDto.getType() == 2 ){
                drawLineDetailDto.setSegmentNo(drawLineDetailDto.getSegmentNo() + "W");
            }

            lineDetailedDtos.add(drawLineDetailDto);
        }
        drawLineDto.setSamplesCount(sampleCount);
        drawLineDto.setCrystalCount(inspectCount);
        drawLineDto.setLineDetailedDtos(lineDetailedDtos);
        drawLineDto.setLength(length);
        if (StringUtils.isNotBlank(drawLineParamDto.getAssessment())){
            drawLineDto.setAssessment(drawLineParamDto.getAssessment());
        }
        if(materialRecycledFlag){
            drawLineDto.setScrapIdentification(true);
        }else {
            drawLineDto.setScrapIdentification(false);
        }
        return ResultGenerator.success(drawLineDto);
    }

    private List<DrawLineExceptionDto> handleMidExeception(List<DrawLineExceptionDto> midExeceptionLen,LongCrystal longCrystal,Integer headTotalLength){
        if (null == longCrystal || CollectionUtils.isEmpty(midExeceptionLen)){
            return midExeceptionLen;
        }
        //查询默认值中该规则回收料最大值
        List<DefaultCrystalAttr> byCrystaTypeAndDopantAndSpecifications = defaultCrystalAttrService.findByCrystaTypeAndDopantAndSpecifications(Constants.RECYCLED_MATERIAL_Y, longCrystal.getDopant(), longCrystal.getSpecs());
        if (CollectionUtils.isEmpty(byCrystaTypeAndDopantAndSpecifications)){
            return midExeceptionLen;
        }
        Integer recycledMaxLength = 0;
        for (DefaultCrystalAttr defaultCrystalAttr : byCrystaTypeAndDopantAndSpecifications){
            if (StringUtils.isNotBlank(defaultCrystalAttr.getLength())){
                String[] lengthArr = defaultCrystalAttr.getLength().split("-");
                if (lengthArr.length == 2 && NumberUtil.isInteger(lengthArr[1])){
                    if (Integer.valueOf(lengthArr[1]) > recycledMaxLength){
                        recycledMaxLength = Integer.valueOf(lengthArr[1]);
                    }
                }
            }
        }
        if (recycledMaxLength == 0) {
            return midExeceptionLen;
        }
        Integer positionLength = headTotalLength;
        List<DrawLineExceptionDto> midExeceptionLenNew = new ArrayList<>();
        for (int index = 0; index < midExeceptionLen.size(); index++){
            DrawLineExceptionDto drawLineExceptionDto = midExeceptionLen.get(index);
            Integer startLen = drawLineExceptionDto.getStartLen().intValue();
            Integer length = drawLineExceptionDto.getLen().intValue();
            //判断第一段是否重叠
            if (index == 0){
                if (startLen < headTotalLength){
                    drawLineExceptionDto.setStartLen(BigDecimal.ZERO);
                    length += (headTotalLength - startLen);
                    drawLineExceptionDto.setLen(new BigDecimal(length));
                    positionLength = (drawLineExceptionDto.getStartLen().add(drawLineExceptionDto.getLen())).intValue();
                    midExeceptionLenNew.add(drawLineExceptionDto);
                }else if ((startLen - positionLength) <= recycledMaxLength){
                    drawLineExceptionDto.setStartLen(BigDecimal.ZERO);
                    length += startLen;
                    drawLineExceptionDto.setLen(new BigDecimal(length));
                    positionLength = (drawLineExceptionDto.getStartLen().add(drawLineExceptionDto.getLen())).intValue();
                    midExeceptionLenNew.add(drawLineExceptionDto);
                }else {
                    midExeceptionLenNew.add(drawLineExceptionDto);
                }
            }else {
                //判断中间段能否合并前一段
                if (startLen < positionLength){
                    DrawLineExceptionDto drawLineExceptionDto1 = midExeceptionLenNew.get(midExeceptionLenNew.size() - 1);
                    length += (headTotalLength - startLen + drawLineExceptionDto1.getLen().intValue());
                    positionLength = (drawLineExceptionDto.getStartLen().add(drawLineExceptionDto.getLen())).intValue();
                    drawLineExceptionDto1.setLen(new BigDecimal(length));
                }else if ((startLen - positionLength) <= recycledMaxLength){
                    DrawLineExceptionDto drawLineExceptionDto2 = midExeceptionLenNew.get(midExeceptionLenNew.size() - 1);
                    length += (startLen - positionLength + drawLineExceptionDto2.getLen().intValue());
                    drawLineExceptionDto2.setLen(new BigDecimal(length));
                }else {
                    midExeceptionLenNew.add(drawLineExceptionDto);
                }
            }
        }
        return midExeceptionLenNew;
    }


    @Override
    public void getDrawlinginfosNew(DrawLineDto drawLineDto) {


        Integer inspectCount = 0;
        Integer sampleCount = 0;
        String crystalNo = drawLineDto.getCrystalNo();
        List<DrawLineDetailDto> lineDetailedDtos = drawLineDto.getLineDetailedDtos();
        if (CollectionUtils.isEmpty(lineDetailedDtos)){
            throw new RuntimeException("画线明细为空！");
        }
        List<DrawLineDetailDto> result = new ArrayList<>();
        //去头长度
        Integer headLen = 0;
        Integer recycledFlow = 1;
        Map<Integer,DrawLineDetailDto> resultMap = new LinkedHashMap<>();

        //人工分段长度
        Integer abnormalSegmenteLength = 1000;
        /*if (null != drawLineDto.getNoTopLength()){
            headLen = drawLineDto.getNoTopLength().intValue();
            recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,headLen,crystalNo,recycledFlow,true);
            for(Map.Entry<Integer,DrawLineDetailDto> entry:resultMap.entrySet()) {
                result.add(entry.getValue());
            }
        }*/
        //有效长度
        BigDecimal effectiveLength = BigDecimal.ZERO;
        Integer index = 0;
        for (DrawLineDetailDto drawLineDetailDto : lineDetailedDtos){
            resultMap.put(resultMap.size(),drawLineDetailDto);
            if (drawLineDetailDto.getType() == 0){
                inspectCount++;
                effectiveLength = effectiveLength.add(drawLineDetailDto.getLength());
            }else if(drawLineDetailDto.getType() == 1){
                sampleCount++;
                effectiveLength = effectiveLength.add(drawLineDetailDto.getLength());
            }else if (drawLineDetailDto.getType() == 2){
                if (index == 0){
                    drawLineDetailDto.setSegmentNo(crystalNo + String.format("%02d", recycledFlow) + "T");
                }else if (index == (lineDetailedDtos.size() -1)){
                    drawLineDetailDto.setSegmentNo(crystalNo + String.format("%02d", recycledFlow) + "W");
                }else {
                    drawLineDetailDto.setSegmentNo(crystalNo + String.format("%02d", recycledFlow));
                }
                recycledFlow++;
            }
            index++;
        }
      /*  //去尾长度
        Integer tailTotalLength = 0;
        if (null != drawLineDto.getLineTailLength()){
            tailTotalLength = drawLineDto.getLineTailLength().intValue();
            recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,tailTotalLength,crystalNo,recycledFlow,false);
        }*/
        //处理单晶编号
        handeCrystalNo(resultMap,inspectCount,crystalNo,null != drawLineDto.getTurnPale() && drawLineDto.getTurnPale() == 1);
        //处理样片编号
        handeSampleNo(resultMap,sampleCount,crystalNo);

        for(Map.Entry<Integer,DrawLineDetailDto> entry:resultMap.entrySet()) {
            DrawLineDetailDto drawLineDetailDto = entry.getValue();
            result.add(drawLineDetailDto);
        }
      /*  int length = drawLineDto.getLength();
        if ((length - headLen - tailTotalLength) != effectiveLength.intValue()){
            throw new RuntimeException("划线有效长度不匹配！");
        }*/

//        drawLineDto.setEffectiveLength(effectiveLength.intValue());
        drawLineDto.setLineDetailedDtos(result);

        drawLineDto.setSamplesCount(sampleCount);
        drawLineDto.setCrystalCount(inspectCount);


    }


    private Integer handHeadR(Map<Integer,DrawLineDetailDto> resultMap,Integer abnormalSegmenteLength,Integer headTotalLength, String crystalNo,Integer recycledFlow,Boolean isHead,Map<String, Integer> pickingRuleMap){
        if (null != headTotalLength && headTotalLength != 0){
            recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,headTotalLength,crystalNo,recycledFlow,true);
        }
        if (pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.头片.getValue()) && !pickingRuleMap.containsKey(EnumValuesFactory.PickingRuleEnum.每段取片.getValue())){
            DrawLineDetailDto drawLineDetailDtoSample = new DrawLineDetailDto();
            //样片
            drawLineDetailDtoSample.setType(1);
            drawLineDetailDtoSample.setLength(new BigDecimal(pickingRuleMap.get(EnumValuesFactory.PickingRuleEnum.头片.getValue())));
            resultMap.put(resultMap.size(),drawLineDetailDtoSample);
        }
        return recycledFlow;
    }

    private void handeSampleNo(Map<Integer,DrawLineDetailDto> resultMap,Integer sampleCount,String crystalNo){
        Date date = new Date();
        String base = crystalNo.substring(0, 1);
        String dopant = crystalNo.substring(2, 3);
        String workshop = crystalNo.substring(6, 7);
        SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd");
        String formatDate = formatter.format(date);
        String years = formatDate.substring(3, 4);
        Integer month = Integer.valueOf(formatDate.substring(5, 7));
        String monthStr = "";
        if (month < 10){
            monthStr = formatDate.substring(6, 7);
        }else if (month == 10){
            monthStr = "A";
        }else if (month == 11){
            monthStr = "B";
        }else if (month == 12){
            monthStr = "C";
        }
        String day = formatDate.substring(8);
        String redisKey = "sampleNo:"+ formatDate;
        Integer count = 0;
        Integer index = 1;
        if (redisTemplate.hasKey(redisKey)){
            count = Integer.valueOf(redisTemplate.opsForValue().get(redisKey).toString());
        }
        redisTemplate.opsForValue().set(redisKey, count + sampleCount, 24, TimeUnit.HOURS);

        for(Map.Entry<Integer,DrawLineDetailDto> entry:resultMap.entrySet()) {
            DrawLineDetailDto lineDetailDto = entry.getValue();
            if (entry.getValue().getType() == 1) {

                StringBuilder sampleNo = new StringBuilder();
                sampleNo.append(base).append(dopant);

                if (index == sampleCount){
                    sampleNo.append("T");
                }else {
                    sampleNo.append("Y");
                }
                sampleNo.append(years).append(monthStr).append(day).append(workshop).append(String.format("%04d", count+index));
                lineDetailDto.setSegmentNo(sampleNo.toString());
                index++;
                if (index > sampleCount){
                    return;
                }
            }
        }

    }

    private void handeCrystalNo(Map<Integer,DrawLineDetailDto> resultMap,Integer inspectCount,String crystalNo,Boolean markWhitening){
        Boolean isFirstCrystalNoFalge = false;
        if (null != resultMap && resultMap.size() != 0){

            int value = Integer.valueOf('A');
            Integer segmentNum = 1;
            Integer entryKey = 0;
            for(Map.Entry<Integer,DrawLineDetailDto> entry:resultMap.entrySet()){
                DrawLineDetailDto lineDetailDto = entry.getValue();
                if (entry.getValue().getType() == 0){
                    if (isFirstCrystalNoFalge){
                        lineDetailDto.setSegmentNo(crystalNo + (char)value);
                        value--;
                    }else {
                        isFirstCrystalNoFalge = true;
                        lineDetailDto.setSegmentNo(crystalNo + "T");
                        value = value + inspectCount -2;
                        if (markWhitening){
                            lineDetailDto.setType(EnumValuesServer.LineType.回收料.getKey());
                        }
                    }
                    lineDetailDto.setSegmentNum(segmentNum);
                    segmentNum++;
                    entryKey = entry.getKey();
                }
            }

            //只有一段
            if (segmentNum == 2){
                DrawLineDetailDto drawLineDetailDto = resultMap.get(entryKey);
                drawLineDetailDto.setSegmentNo(crystalNo + "R");
                if (markWhitening){
                    drawLineDetailDto.setType(EnumValuesServer.LineType.回收料.getKey());
                }
            }
        }
    }

    private Integer handleAbnormalSegmente(Map<Integer,DrawLineDetailDto> resultMap,Integer abnormalSegmenteLength,Integer headTotalLength, String crystalNo,Integer recycledFlow,Boolean isHead){
        if (null != abnormalSegmenteLength && abnormalSegmenteLength != 0 && headTotalLength > abnormalSegmenteLength ){
            DrawLineDetailDto drawLineDetailDto = new DrawLineDetailDto();
            if (recycledFlow == 1){
                drawLineDetailDto.setSegmentNo(crystalNo + String.format("%02d", recycledFlow) + "T");
            }else {
                drawLineDetailDto.setSegmentNo(crystalNo + String.format("%02d", recycledFlow));
            }
            drawLineDetailDto.setLength(new BigDecimal(abnormalSegmenteLength));
            recycledFlow ++;
            int size = resultMap.size();
            //回收料
            drawLineDetailDto.setType(2);
            resultMap.put(size,drawLineDetailDto);
            recycledFlow = this.handleAbnormalSegmente(resultMap,abnormalSegmenteLength,headTotalLength - abnormalSegmenteLength,crystalNo,recycledFlow,isHead);
        }else {
            DrawLineDetailDto drawLineDetailDto = new DrawLineDetailDto();
            //回收料
            drawLineDetailDto.setType(2);
            if (isHead && recycledFlow == 1){
                drawLineDetailDto.setSegmentNo(crystalNo + String.format("%02d", recycledFlow) + "T");
            }else {
                drawLineDetailDto.setSegmentNo(crystalNo + String.format("%02d", recycledFlow));
            }

            drawLineDetailDto.setLength(new BigDecimal(headTotalLength));
            recycledFlow ++;
            int size = resultMap.size();
            resultMap.put(size,drawLineDetailDto);
        }
        return recycledFlow;
    }

    private void handleInspectSegmente(Map<Integer,DrawLineDetailDto> resultMap,PaintingLine paintingLine,Integer effectiveLength,Integer thicknessSample){
        //优先分段长
        Integer preferredSegmentLength = paintingLine.getPreferredSegmentLength();

        //尾段定长
        Integer tailFixedLength = null;
        if (null != paintingLine.getTailFixedLength()){
            tailFixedLength = paintingLine.getTailFixedLength().intValue();
        }

        //最短分段长
        Integer shortestSegmentLength = paintingLine.getShortestSegmentLength();

        if (tailFixedLength > preferredSegmentLength){
            throw new RuntimeException("尾段定长比最优分段长度长！");
        }

        if (tailFixedLength < shortestSegmentLength){
            throw new RuntimeException("尾段定长比最短分段长度短！");
        }

        Integer doubleThicknessSample = thicknessSample + thicknessSample;

        if (effectiveLength >=  preferredSegmentLength + shortestSegmentLength + doubleThicknessSample){
            handleInfo(resultMap,1,effectiveLength,thicknessSample,null,preferredSegmentLength);
            handleInspectSegmente(resultMap,paintingLine,effectiveLength - preferredSegmentLength - thicknessSample,thicknessSample);
        }else {
            if (effectiveLength > preferredSegmentLength){
                if (effectiveLength < shortestSegmentLength + preferredSegmentLength + doubleThicknessSample){
                    handleInfo(resultMap,1,effectiveLength,thicknessSample,null,tailFixedLength);
                    handleInfo(resultMap,1,effectiveLength,thicknessSample,null,effectiveLength - tailFixedLength - doubleThicknessSample);
                }else {
                    handleInfo(resultMap,1,effectiveLength,thicknessSample,null,preferredSegmentLength);
                    handleInfo(resultMap,1,effectiveLength,thicknessSample,null,effectiveLength - preferredSegmentLength - doubleThicknessSample);
                }
            }else {
                handleInfo(resultMap,1,effectiveLength,thicknessSample,null,effectiveLength - doubleThicknessSample);
            }
        }
/*需求修改调整
        if (effectiveLength - preferredSegmentLength - thicknessSample > tailFixedLength){
            handleInfo(resultMap,1,effectiveLength,thicknessSample,null,preferredSegmentLength);
            handleInspectSegmente(resultMap,paintingLine,effectiveLength - preferredSegmentLength - thicknessSample,thicknessSample);
        }else {
            if (effectiveLength < tailFixedLength || effectiveLength == (preferredSegmentLength + thicknessSample)){
                handleInfo(resultMap,1,effectiveLength,thicknessSample,null,effectiveLength - thicknessSample);
            }else {
                for (int index = 0; index < 2; index++){
                    handleInfo(resultMap,index,effectiveLength,thicknessSample,tailFixedLength,preferredSegmentLength);
                }
            }

        }*/
    }

    private void handleInfo(Map<Integer,DrawLineDetailDto> resultMap,int index,Integer effectiveLength, Integer thicknessSample, Integer tailFixedLength,
                            Integer preferredSegmentLength){
        //每段取片
        if (null != thicknessSample && thicknessSample != 0){
            DrawLineDetailDto drawLineDetailDtoSample = new DrawLineDetailDto();
            //样片
            drawLineDetailDtoSample.setType(1);
            drawLineDetailDtoSample.setLength(new BigDecimal(thicknessSample));
            resultMap.put(resultMap.size(),drawLineDetailDtoSample);
        }
        DrawLineDetailDto drawLineDetailDto = new DrawLineDetailDto();
        //晶段
        drawLineDetailDto.setType(0);
        if (index == 0){
            //需求修改
            //drawLineDetailDto.setLength(new BigDecimal(effectiveLength - tailFixedLength - thicknessSample - thicknessSample));
            drawLineDetailDto.setLength(new BigDecimal(tailFixedLength));
        }else {
            if (null == tailFixedLength){
                drawLineDetailDto.setLength(new BigDecimal(preferredSegmentLength));
            }else {
                drawLineDetailDto.setLength(new BigDecimal(effectiveLength - tailFixedLength - thicknessSample - thicknessSample));
            }
        }
        resultMap.put(resultMap.size(),drawLineDetailDto);
    }


    /**
     * SAP 产品上报
     * @param lineParamDto
     */
    private void handleSapInfo(LineParamDataDto lineParamDto){
        if (null == lineParamDto || null == lineParamDto.getLongCrystal()){
            throw new RuntimeException("传入参数为空！");
        }
        LongCrystal longCrystal = lineParamDto.getLongCrystal();
        String crystalNo = longCrystal.getCrystalNo();
        if (null == longCrystal.getWeight()){
            throw new RuntimeException("长晶棒产出重量为空！");
        }

        if (null != longCrystal && null != longCrystal.getReportStatus() && longCrystal.getReportStatus().equals(EnumValuesFactory.ReportStatusSap.REPORTED.getKey())){
            log.info("该单晶上报过，不在上报，单晶编号为：{}",crystalNo);
            return;
        }
        //添加判断
        ReportSapGoodsmvt byCrystalNoAndBwart = reportSapGoodsmvtService.findByCrystalNoAndBwart(crystalNo, "101");
        if (null != byCrystalNoAndBwart){
            log.info("该单晶上报过，不在上报，单晶编号为：{}",crystalNo);
            return;
        }
        String umlgo = null;
        String warehouseCode = "";
        if (StringUtils.isNotBlank(longCrystal.getEquipmentCode())){
            Equipment byCode = equipmentService.findByCode(longCrystal.getEquipmentCode());
            if (null != byCode){
                DictionaryItem  warehouseLocation = dictionaryItemService.findByThemeValueAndNameAndValueAndEnable("WarehouseLocation",byCode.getArea(),byCode.getSeries(), true);
                if (null != warehouseLocation){
                    umlgo = warehouseLocation.getExtendValue2();
                    warehouseCode = warehouseLocation.getExtendValue1();
                }
            }
            Result resultStore = wipStorageYbService.sendWarehouseInputBillBo(longCrystal, longCrystal.getWeight(), InputBillStatusEnum.毛棒入库.getValue(),umlgo,warehouseCode,null,null);
            if (resultStore.getCode() != ResultCode.SUCCESS.getCode()){
                log.info("线边仓入库调拨失败:{}",resultStore.getMessage());
                throw new RuntimeException("线边仓入库调拨失败！异常为：" + resultStore.getMessage());
            }
            String batchNo = longCrystal.getBatchNo();
            if (StringUtils.isNotBlank(batchNo) && batchNo.startsWith("TCN") && batchNo.length() >= 10){
                batchNo =  batchNo.substring(0,1)+ "J" + batchNo.substring(2,10);
            }

            wipStorageYbService.sendReportSapGoodsmvt("101",byCode.getSeries(),longCrystal.getOrderNo(),longCrystal.getProductCode(),batchNo,longCrystal.getWeight().toString(),"KG","5041",warehouseCode,crystalNo,umlgo,"划线",longCrystal.getEquipmentCode(),null != longCrystal.getAgainNum() ? String.valueOf(longCrystal.getAgainNum()) : "");
        }
    }

    @Override
    public  List<Map<String, Object>>  capacityInputData() {
        return dao.getCapacityInputData();
    }

    /**
     * 上报SAP单晶工时消耗-New
     * @param longCrystal
     */
    @Override
    public void newReportSapLongCrystalHours(LongCrystal longCrystal){

        ReportSapWorkinghours reportSap = new ReportSapWorkinghours();
        // 设置保留两位小数
        DecimalFormat decimalFormat = new DecimalFormat("#.##");
        // 生产订单
        reportSap.setProductionOrderId(longCrystal.getOrderNo());
        // 工厂
        reportSap.setPlant("5041");
        // 订单工作中心
        reportSap.setWorkcenterId(longCrystal.getSeries());
        reportSap.setCnfTimeUom("H");
        reportSap.setStatus(false);
        reportSap.setCrystalNo(longCrystal.getCrystalNo());
        Long startTime = null;
        reportSap.setProcName("单晶工时");
        reportSap.setCnfDate(new Date());
        reportSap.setRemark(longCrystal.getCrystalNo());

        List<LongCrystal> crystalList = longCrystalService.findByLotNo(longCrystal.getLotNo());
        log.info("单晶工时报工当前炉次产生的编号：{}", crystalList);
        if(null != crystalList && crystalList.size() > 0){
            LongCrystal longCrystal1 = crystalList.get(crystalList.size() - 1);
            //首棒
            if(longCrystal.getId().equals(longCrystal1.getId())){
                // 查询
                startTime = gettimeLong(longCrystal, startTime);
                log.info("单晶工时首棒开始时间：{}，编号{}", startTime, longCrystal.getCrystalNo());
                if(null == startTime){
                    throw new RuntimeException("编号" + longCrystal.getCrystalNo() + "未查询到抽空、熔料及确认投料时间");
                }
                double result = (double) (longCrystal.getGmtCreate().getTime() - startTime)/ 3600000;
                String formattedResult = decimalFormat.format(result);
                log.info("单晶工时首棒工时：{}，编号{}", formattedResult, longCrystal.getCrystalNo());
                reportSap.setCnfTime(formattedResult);
                reportSapWorkinghoursService.saveOrUpdate(reportSap);
                return;
            }

            //非首棒
            LongCrystal longCrystal2 = null;
            for (int i = 0; i < crystalList.size(); i++) {
                if(crystalList.get(i).getCrystalNo().equals(longCrystal.getCrystalNo())){
                    longCrystal2 = crystalList.get(i + 1);
                    break;
                }
            }
            if(null == longCrystal2){
                throw new RuntimeException("编号" + longCrystal.getCrystalNo() + "未查询到上上一颗晶棒");
            }
            double result = (double) (longCrystal.getGmtCreate().getTime() - longCrystal2.getGmtCreate().getTime()) / 3600000;
            String formattedResult = decimalFormat.format(result);
            log.info("单晶工时非首棒工时：{}，编号{}", formattedResult, longCrystal.getCrystalNo());
            reportSap.setCnfTime(formattedResult);
            ReportSapWorkinghours byCrystalNoAndBwart = reportSapWorkinghoursService.findByRemarkAndProcName(longCrystal.getCrystalNo(), "单晶工时");
            if (null != byCrystalNoAndBwart) {
                SysLog syslog = new SysLog();
                syslog.setCreateTime(new Date());
                syslog.setType("info");
                syslog.setCreateUserName("SYSTEM");
                syslog.setContent(JSON.toJSONString(reportSap));
                syslog.setResult("单晶工时：晶棒【" + longCrystal.getCrystalNo() + "】已经报过工时");
                syslog.setMethodName("handleReportConsumption()");
                syslog.setServerAddr("");
                syslog.setReqType("HTTP");
                syslog.setReqIp(IpUtils.getLocalIP());
                sysLogService.save(syslog);
                return;
            } else {
                reportSapWorkinghoursService.saveOrUpdate(reportSap);
            }
        }
    }

    private Long gettimeLong(LongCrystal longCrystal, Long startTime) {
        ProcessWorkingHours hours;
        hours = processWorkingHoursService.findByLotNoAndStep(longCrystal.getLotNo(), "抽真空");
        if(null == hours){
            hours = processWorkingHoursService.findByLotNoAndStep(longCrystal.getLotNo(), "熔料工时");
        }
        if(null == hours){
            LoadingTask byLotNo = loadingTaskService.findSuccessByLotNo(longCrystal.getLotNo());
            if(null != byLotNo){
                startTime = byLotNo.getConfirmTime().getTime();
            }
        }
        if (hours != null){
            startTime = hours.getStartTime().getTime();
        }
        return startTime;
    }


    @Override
    public Result<String> create(DrawLineDto drawLineDto) {
        //划线开始时间取当前系统时间
        drawLineDto.setStartTime(new Date());

        //根据长棒编号获取长棒信息，并且进行划线前的一些验证
        LineParamDataDto lineParamDto = getLongCrystal(drawLineDto.getCrystalNo());
        LineDetailedParamDto lineDetailedParamDto = new LineDetailedParamDto();
        int drawlinedetailLen = 0;

        BigDecimal effectiveLength = BigDecimal.ZERO;
        int count = 0;
        //正常晶段计数
        int segmentCount = 0;

        //头段位置
        Integer headIndex = null;

        //for (DrawLineDetailDto line : drawLineDto.getLineDetailedDtos()) {
        if (!CollectionUtils.isEmpty(drawLineDto.getLineDetailedDtos())) {
            List<DrawLineDetailDto> lineDetailedDtos = drawLineDto.getLineDetailedDtos();
            int size = lineDetailedDtos.size();
            for (int index = 0; index < size; index++) {
                DrawLineDetailDto line = lineDetailedDtos.get(index);
                if (line.getLength().compareTo(BigDecimal.ZERO) < 0) {
                    throw new RuntimeException("晶段的长度不能为负数：" + line.getLength());
                }
                drawlinedetailLen += line.getLength().intValue();

                if (line.getType() == 0 && line.getLength().compareTo(BigDecimal.ZERO) > 0) {
                    segmentCount++;
                    if (line.getSegmentNo().endsWith("T") || line.getSegmentNo().endsWith("R")) {
                        headIndex = index;
                    }
                }
                if (line.getType() == 0 || line.getType() == 1) {
                    effectiveLength = effectiveLength.add(line.getLength());
                }



          /*  //判断是否存在头片信息
            if(line.getSegmentNo().contains("TP") || line.getSegmentNo().substring(SectionIndexRangeEnum.炉区号.getEndIndex()).contains("1P")){
                count++;
            }*/
                //剔除尾片长度计算
                if (line.getType() == 1 && com.sw.mes.core.utils.StringUtils.isNotBlank(line.getSegmentNo()) && com.sw.mes.core.utils.StringUtils.equals("T", line.getSegmentNo().substring(2, 3))) {
                    drawlinedetailLen -= line.getLength().intValue();

                    effectiveLength = effectiveLength.subtract(line.getLength());
                }
            }
            if (null != headIndex && headIndex - 1 >= 0) {
                DrawLineDetailDto drawLineDetailDto = lineDetailedDtos.get(headIndex - 1);
                if (drawLineDetailDto.getType() == 1) {
                    drawlinedetailLen -= drawLineDetailDto.getLength().intValue();
                    effectiveLength = effectiveLength.subtract(drawLineDetailDto.getLength());
                }
            }
        }
        if (0 == drawLineDto.getEffectiveLength()) {
            lineParamDto.setEffectiveLength(effectiveLength);
        }

        //有正常晶段
        if (segmentCount > 0) {

            /*if(count == 0){
                throw new RuntimeException("缺少头片划线信息");
            }*/
            //需要扣除去头尾回收料
            if (null != drawLineDto.getHeadLen() && drawLineDto.getHeadLen().compareTo(BigDecimal.ZERO) > 0) {
                drawlinedetailLen -= drawLineDto.getHeadLen().intValue();
            }
            if (null != drawLineDto.getTailLen() && drawLineDto.getTailLen().compareTo(BigDecimal.ZERO) > 0) {
                drawlinedetailLen -= drawLineDto.getTailLen().intValue();
            }

            //校验画线长度和明细长度是否一致
            if (drawlinedetailLen != drawLineDto.getLength()) {
                throw new BusinessException(" 明细总长 " + drawlinedetailLen + "！=总长 " + drawLineDto.getLength());
            }
            BeanUtils.copyProperties(drawLineDto, lineDetailedParamDto);
            lineDetailedParamDto.getLineDetailedDtos().stream().forEach(t -> {
                t.setSampleType(t.getType());
            });
            try {
                this.createAll(lineDetailedParamDto, lineParamDto.getLongCrystal(), lineParamDto.getWeightLossCoefficient(), lineParamDto);
            }catch (Exception e){
                log.info("划线异常日志：{}",e.getMessage());
                return ResultGenerator.fail(e.getMessage());
            }
            if (null != lineDetailedParamDto && lineDetailedParamDto.getTotalLength().compareTo(BigDecimal.ZERO) > 0){

              /*  StringBuffer lossReason = new StringBuffer();
                if (StringUtils.isNotBlank(drawLineDto.getTopCause())){
                    lossReason.append(drawLineDto.getTopCause()).append(":").append(drawLineDto.getNoTopLength()).append(";");
                }
                if (StringUtils.isNotBlank(drawLineDto.getEndCause())){
                    lossReason.append(drawLineDto.getEndCause()).append(":").append(drawLineDto.getLineTailLength()).append(";");
                }
                if (StringUtils.isNotBlank(lineDetailedParamDto.getMiddleAbnormalReason())){
                    lossReason.append(lineDetailedParamDto.getMiddleAbnormalReason()).append(";");
                }*/
                //处理数据
                try {
                    this.handleLossInfo(lineParamDto.getLongCrystal(),drawLineDto,lineDetailedParamDto.getTotalLength(),lineDetailedParamDto.getMiddleAbnormalReason());
                }catch (Exception e){
                    log.info("损耗上报异常：{}",e.getMessage());
                }
            }

        } else {

            //校验画线长度和明细长度是否一致
            if (drawlinedetailLen != drawLineDto.getLength()) {
                throw new BusinessException(" 明细总长 " + drawlinedetailLen + "！=总长 " + drawLineDto.getLength());
            }
            // 解绑
            List<ProductionBindingTray> bindingTrays = productionBindingTrayDao.findByCrystalNo(drawLineDto.getCrystalNo());
            if (null != bindingTrays && !CollectionUtils.isEmpty(bindingTrays) && !bindingTrays.get(0).getTrayNo().isEmpty()) {
                BindingCrystalDto bindingCrystalDto = new BindingCrystalDto();
                bindingCrystalDto.setCrystalNo(drawLineDto.getCrystalNo());
                bindingCrystalDto.setTrayNo(bindingTrays.get(0).getTrayNo());
                bindingCrystalDto.setReason("送验车解绑");
                try {
                    productionBindingTrayService.unbundlingCrystal(bindingCrystalDto);
                } catch (Exception e) {
                    log.info("划线异常日志：{}",e.getMessage());
                    return ResultGenerator.fail(e.getMessage());
                }
            }
            //回收料将有效长度清零
            lineParamDto.setEffectiveLength(BigDecimal.ZERO);
            /*if (null == drawLineDto.getScrapIdentification() || !drawLineDto.getScrapIdentification()){
                //工单废除
                List<PlanProcessingOrder> planProcessingOrders = planProcessingOrderDao.findByCodeOrderByIdDesc(drawLineDto.getCrystalNo());
                if (planProcessingOrders.size() == 0) {
                    throw new BusinessException("工单号【" + drawLineDto.getCrystalNo() + "】不存在");
                }
                PlanProcessingOrder planProcessingOrder = planProcessingOrders.get(0);
                planProcessingOrder.setStatus(EnumValuesFactory.PlanProcessingOrderStatus.已作废.getKey());
                planProcessingOrder.setRemarks("划线明细全是回收料，工单" + EnumValuesFactory.PlanProcessingOrderStatus.已作废.getValue());

                //创建报废履历
                processLogService.createProcessLog(planProcessingOrder.getId(), planProcessingOrder.getCode(), null, null, null, null, "【毛棒检验】：" + planProcessingOrder.getCode() + "->作废");
                planProcessingOrderService.saveOrUpdate(planProcessingOrder);
            }*/
            BeanUtils.copyProperties(drawLineDto, lineDetailedParamDto);
            lineDetailedParamDto.getLineDetailedDtos().stream().forEach(t -> {
                t.setSampleType(t.getType());
            });
            lineDetailedParamDto.setEffectiveLength(0);
            try {
                this.createAll(lineDetailedParamDto, lineParamDto.getLongCrystal(), lineParamDto.getWeightLossCoefficient(), lineParamDto);
            }catch (Exception e){
                log.info("划线回收料异常日志：{}",e.getMessage());
                return ResultGenerator.fail(e.getMessage());
            }

            //处理数据
            try {
                this.handleLossInfo(lineParamDto.getLongCrystal(),drawLineDto,null,null);
            }catch (Exception e){
                log.info("损耗上报异常：{}",e.getMessage());
            }
        }
/*
        ThreadManager.getThreadPollProxy().execute(() ->{
            try {
                this.handleSapInfo(lineParamDto);
            }catch (Exception e){
                e.printStackTrace();
            }
        });*/

        try {
            SwitchConfig config = GlobalSwitch.switchConfig(CODE_SWITCH, "crystalWorkHour", false);
            if(config.isEnable()){
                LongCrystal longCrystal = longCrystalService.findByCrystalNo(drawLineDto.getCrystalNo());
                log.info("单晶工时报工编号：{}", drawLineDto.getCrystalNo());
                this.newReportSapLongCrystalHours(longCrystal);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("单晶工时：" + e.getMessage());
        }
        return ResultGenerator.success();
    }

    private void handleLossInfo(LongCrystal longCrystal,DrawLineDto drawLineDto,BigDecimal lossLength,String lossReason){
        if (null != longCrystal && null != drawLineDto){
            CrystalLossRecord crystalLossRecord = new CrystalLossRecord();
            crystalLossRecord.setSectionNo(drawLineDto.getCrystalNo());
            crystalLossRecord.setCrystalNo(drawLineDto.getCrystalNo());
            crystalLossRecord.setLossProcessName(EnumValuesFactory.WipStorageCode.划线.getValue());
            crystalLossRecord.setMajorCategories(EnumValuesFactory.CrystalLossType.SINGLE_CRYSTAL_LOSS.getValue());
            if (null != lossLength){
                crystalLossRecord.setLossLength(lossLength);
                crystalLossRecord.setRodLength(new BigDecimal(drawLineDto.getLength()));
                crystalLossRecord.setRemainLength(crystalLossRecord.getRodLength().subtract(lossLength));
                crystalLossRecord.setLossType(lossReason);
            }else {
                crystalLossRecord.setLossLength(new BigDecimal(drawLineDto.getLength()));
                crystalLossRecord.setRodLength(crystalLossRecord.getLossLength());
                crystalLossRecord.setRemainLength(BigDecimal.ZERO);
                crystalLossRecord.setRemainWeight(BigDecimal.ZERO);
                crystalLossRecord.setLossType(drawLineDto.getAssessment());
            }
            if (null != crystalLossRecord.getLossLength()){
                //圆棒理论折算系数
                if (com.sw.mes.core.utils.StringUtils.isNotBlank(longCrystal.getSpecs())){
                    DictionaryItem weightRatio = dictionaryItemService.findByThemeValueAndNameAndEnable("WeightRatio", longCrystal.getSpecs(), true);
                    if (null != weightRatio && com.sw.mes.core.utils.StringUtils.isNotBlank(weightRatio.getValue())){
                        crystalLossRecord.setLossWeight(crystalLossRecord.getLossLength().divide(new BigDecimal(weightRatio.getValue()), 3, BigDecimal.ROUND_HALF_UP));
                        if (null != lossLength){
                            crystalLossRecord.setRemainWeight(crystalLossRecord.getRemainLength().divide(new BigDecimal(weightRatio.getValue()), 3, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }
            crystalLossRecord.setCreateName(drawLineDto.getOperatorUser());
            crystalLossRecord.setArea(longCrystal.getSeries());
            FactoryModel factoryModel = factoryModelService.findByCode(longCrystal.getArea());
            if (null != factoryModel){
                crystalLossRecord.setWorkshop(factoryModel.getName());
            }

            if (null != drawLineDto.getEndTime()){
                crystalLossRecord.setCreateTime(drawLineDto.getEndTime());
            }else {
                crystalLossRecord.setCreateTime(new Date());
            }
            crystalLossRecord.setOperateRemark(drawLineDto.getRemarks());
            crystalLossRecord.setMaterialCode(longCrystal.getProductCode());
            crystalLossRecord.setMaterialName(longCrystal.getProductName());
            crystalLossRecord.setOrderNo(longCrystal.getOrderNo());
            crystalLossRecord.setSimpleName(longCrystal.getSimpleName());
            crystalLossRecord.setRodTime(crystalLossRecord.getCreateTime());
            crystalLossRecord.setRodInspector(drawLineDto.getOperatorUser());
            crystalLossRecordService.saveOrUpdate(crystalLossRecord);

            //发送钉钉

            StringBuffer content = new StringBuffer();
            content.append(". [MES推送]晶棒损耗:").append("\n");
            content.append(". ").append(drawLineDto.getCrystalNo()).append("\n");
            content.append(".时间：").append(DateUtil.formatDate1(drawLineDto.getEndTime())).append("\n");
            content.append(".单晶损耗").append("\n");
            content.append(".损耗工序：").append(EnumValuesFactory.WipStorageCode.划线.getValue()).append("\n");
            content.append(".损耗原因：").append(drawLineDto.getAssessment()).append("\n");
            content.append(".损耗长度：").append(drawLineDto.getLength()).append("\n");

            content.append(".剩余长度：0").append("\n");
            content.append(".录入人：").append(drawLineDto.getOperatorUser()).append("\n");
            content.append(".备注：").append(com.sw.mes.core.utils.StringUtils.isNotBlank(drawLineDto.getRemarks()) ? drawLineDto.getRemarks(): "").append("\n");
            ArrayList<String> sceneList = new ArrayList<>();
            ArrayList<String> groupNameList = new ArrayList<>();
            sceneList.add("prod");
            String groupName = "切方长度损耗实时推送群";
            groupNameList.add(groupName);
            String source = "晶棒损耗";
            if(null == lossLength){
                dingTalkService.robotSeedMessage(String.valueOf(content), groupNameList, source, sceneList, SeedMassageEnum.GROUP);
            }
        }
    }


    /**
     * 根据长棒编号获取长棒信息，并且进行划线前的一些验证
     *
     * @param crystalNo 长棒编号
     * @return 长棒信息实体与理论重量系数
     */
    private LineParamDataDto getLongCrystal(String crystalNo) {
        wipStorageService.selectWipStorage(crystalNo, EnumValuesFactory.WipStorageCode.划线.getKey(), true);
        ProductionPaintingLine productionPaintingLines = this.findByCrystalNo(crystalNo);
        if (productionPaintingLines != null) {
            throw new BusinessException("当前单晶已画线，无法操作");
        }
        if (com.sw.mes.core.utils.StringUtils.isBlank(crystalNo)) {
            throw new BusinessException("单晶编号参数不能为空");
        }
        LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
        if (longCrystal == null) {
            throw new BusinessException("单晶编号不存在");
        }
        //添加卡控 毛棒产出晶棒后 出炉时间卡控>9小时才可以进行划线作业。
        if (null == longCrystal.getGmtCreate()){
            throw new BusinessException("单晶编号:" + crystalNo + ",产出时间不存在！");
        }
        Date date = new Date();
        List<DictionaryItem> duration = dictionaryItemService.findByThemeValueAndEnable("duration", true);
        if(null != duration && duration.size() > 0){
            DictionaryItem dictionaryItem = duration.get(0);
            String value = dictionaryItem.getValue();
            long timeLong = Long.parseLong(value) * 60 * 1000;
            if (date.getTime() - longCrystal.getGmtCreate().getTime() < timeLong){
                throw new BusinessException("单晶编号:" + crystalNo + ",产出时间为： " + longCrystal.getGmtCreate() + ",产出时间小于【" + value + "】分钟！");
            }
        } else {
            if (date.getTime() - longCrystal.getGmtCreate().getTime() < 32400000){
                throw new BusinessException("单晶编号:" + crystalNo + ",产出时间为： " + longCrystal.getGmtCreate() + ",产出时间小于9小时！");
            }
        }
        //添加批次锁定校验
        crystalBatchOperationService.judgeCrystalNoIsLock(crystalNo, null, true);
        if (longCrystal.getLength() == null) {
            throw new BusinessException("该单晶的没有长度信息，请补充后重试");
        }
        if (longCrystal.getLength().longValue() <= 0) {
            throw new BusinessException("该单晶的长度小于等于0，请修正长棒信息后重试");
        }
        List<DictionaryItem> dictionaryItems = dictionaryItemService.findByThemeValueAndItemName(Constants.WEIGHT_RATIO, longCrystal.getSpecs(), true);
        if (dictionaryItems.size() == 0) {
            throw new BusinessException("请配置【" + longCrystal.getSpecs() + "】规格的理论重量系数");
        }
        BigDecimal weightLossCoefficient = NumberUtil.Object2BigDecimal(dictionaryItems.get(0).getValue());
        if (weightLossCoefficient == null || weightLossCoefficient.compareTo(new BigDecimal("1")) < 1) {
            throw new BusinessException("【" + dictionaryItems.get(0).getValue() + "】理论重量系数格式不正确，只能为大于0的数字类型");
        }
        //添加卡控，上一炉次未划线禁止划线
        LongCrystal deviceNoAndCreateTime = longCrystalService.findDeviceNoAndCreateTime(longCrystal.getEquipmentCode(), longCrystal.getGmtCreate(),EnumValuesFactory.CrystalStatus.已送验.getKey());
        if (null != deviceNoAndCreateTime){
            throw new BusinessException("该设备上一个送验单晶未划线，单晶编号为：" + deviceNoAndCreateTime.getCrystalNo());
        }

        LineParamDataDto lineParamDataDto = new LineParamDataDto();
        lineParamDataDto.setLongCrystal(longCrystal);
        lineParamDataDto.setWeightLossCoefficient(weightLossCoefficient);
        return lineParamDataDto;
    }
}