package com.cf.imes.module.plan.service.orderImport.factory;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.dict.core.util.DictFrameworkUtils;
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
import com.cf.imes.framework.mybatis.core.generator.SnowFlakeGenerator;
import com.cf.imes.framework.mybatis.core.injector.BaseBatchMapper;
import com.cf.imes.module.executor.enums.DictTypeConstants;
import com.cf.imes.module.executor.enums.OrderImportStatusEnum;
import com.cf.imes.module.executor.enums.OrderImportTmpDataTypeEnum;
import com.cf.imes.module.executor.enums.OrderItemTypeEnum;
import com.cf.imes.module.plan.controller.admin.orderImport.vo.OrderImportTempDataReqVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.AssemblyXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.BlockXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.CorrelationXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.CorrelationXmlVOS;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.CuttingOutlineXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.EdgingXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.ExtraVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.GrooveXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.GrooveXmlVOS;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.GroupXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.HardwareXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.HoleXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.HoleXmlVOS;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.IsletXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.IsletXmlVOS;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.OffsetLineXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.OffsetLineXmlVOS;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.OutlineXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.PlateXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.PointXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.PointXmlVOS;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.RawOutlineXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.RectSealVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.RemarkXmlVO;
import com.cf.imes.module.plan.controller.admin.orderImport.xml.vo.RoomBoxXmlVO;
import com.cf.imes.module.plan.dal.dataobject.goods.GoodsDO;
import com.cf.imes.module.plan.dal.dataobject.order.OrderDO;
import com.cf.imes.module.plan.dal.dataobject.orderBody.OrderBodyDO;
import com.cf.imes.module.plan.dal.dataobject.orderGroup.OrderGroupDO;
import com.cf.imes.module.plan.dal.dataobject.orderImport.OrderImportTaskDO;
import com.cf.imes.module.plan.dal.dataobject.orderImport.OrderImportTempDataDO;
import com.cf.imes.module.plan.dal.dataobject.orderImport.OrderImportTempDataPartItemCodeGroupDO;
import com.cf.imes.module.plan.dal.dataobject.orderImport.OrderImportTempDataPartRoomBodyGroupGroupDO;
import com.cf.imes.module.plan.dal.dataobject.orderItem.OrderItemDO;
import com.cf.imes.module.plan.dal.dataobject.orderParts.OrderPartsDO;
import com.cf.imes.module.plan.dal.dataobject.ordermodel.OrderModelDO;
import com.cf.imes.module.plan.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.plan.dal.dataobject.plate.PlateGoodDO;
import com.cf.imes.module.plan.dal.dataobject.rawgoods.RawGoodsDO;
import com.cf.imes.module.plan.dal.elasticsearch.BasePosition;
import com.cf.imes.module.plan.dal.elasticsearch.HoleDetail;
import com.cf.imes.module.plan.dal.elasticsearch.IContourData;
import com.cf.imes.module.plan.dal.elasticsearch.IOriginModelingData;
import com.cf.imes.module.plan.dal.elasticsearch.ModelDetail;
import com.cf.imes.module.plan.dal.elasticsearch.OffSetList;
import com.cf.imes.module.plan.dal.elasticsearch.OrderPartsRemark;
import com.cf.imes.module.plan.dal.elasticsearch.PartsInfo;
import com.cf.imes.module.plan.dal.elasticsearch.Point;
import com.cf.imes.module.plan.dal.elasticsearch.PointDetail;
import com.cf.imes.module.plan.dal.elasticsearch.PointList;
import com.cf.imes.module.plan.dal.mysql.goods.GoodsMapper;
import com.cf.imes.module.plan.dal.mysql.orderBody.OrderBodyMapper;
import com.cf.imes.module.plan.dal.mysql.orderGroup.OrderGroupMapper;
import com.cf.imes.module.plan.dal.mysql.orderImport.OrderImportTaskMapper;
import com.cf.imes.module.plan.dal.mysql.orderImport.OrderImportTempDataMapper;
import com.cf.imes.module.plan.dal.mysql.orderItem.OrderItemMapper;
import com.cf.imes.module.plan.dal.mysql.orderParts.OrderPartsMapper;
import com.cf.imes.module.plan.dal.mysql.orderParts.PartsMapper;
import com.cf.imes.module.plan.dal.mysql.plate.PlateGoodMapper;
import com.cf.imes.module.plan.dal.mysql.plate.PlateMapper;
import com.cf.imes.module.plan.dal.mysql.rawgoods.RawGoodsMapper;
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
import com.cf.imes.module.plan.service.customplateno.vo.CustomPlateNoGenerateConfigVO;
import com.cf.imes.module.plan.service.order.OrderInputProcessor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.cf.imes.module.executor.enums.OrderImportConstants.NOT_ASSIGNED;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.ORDER_IMPORT_PLATE_GOODS_NOT_EXISTS;
import static com.cf.imes.module.plan.service.order.OrderInputProcessor.ORDER_PARTS_REMARK_MODEL;
import static com.cf.imes.module.plan.service.order.OrderInputProcessor.ORDER_PLATE_MODEL;

/**
 * 默认xml导入生产单工厂服务
 *
 * @author Gqr
 * @since 2025/2/19 16:26
 */
@Slf4j
public class DefaultXmlOrderImportFactory {
    /**
     * 分组中做分页的阈值，如：总数100以上就边分组边分页，否则一次性查出来
     */
    private static final int BATCH_THRESHOLD_NUMBER = 100;

    private Long organId;

    // 批次id
    private Long batchId;

    private Long orderId;

    private OrderDO orderDO;

    private Long taskId;

    private CustomPlateNoGenerateConfigVO plateNoGenerateConfigVO;

    // 是否入库的第一块板件
    private boolean isFirstPlate;

    private List<RawGoodsDO> rawGoodsDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<GoodsDO> goodsDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<OrderPartsDO> orderPartsDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<OrderBodyDO> orderBodyDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<OrderGroupDO> orderGroupDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<PlateDO> plateDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<OrderItemDO> orderItemDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<PlateGoodDO> plateGoodDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<OrderModelDO> orderModelDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
    private List<OrderPartsRemark> orderPartsRemarks = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
//    private List<PartsDO> partsDOS = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);

    private static final String EMPTY_STRING = new String();
    private static final BigDecimal BIG_ZERO = new BigDecimal(0);
    private static final Double DOUBLE_ZERO  = NumberUtil.parseDouble("0.0");

    private static final int GOODS_TYPE = OrderImportTmpDataTypeEnum.GOODS.getType();
    private static final int BODY_TYPE = OrderImportTmpDataTypeEnum.BODY.getType();
    private static final int GROUP_TYPE = OrderImportTmpDataTypeEnum.GROUP.getType();
    private static final int PLATE_TYPE = OrderImportTmpDataTypeEnum.PLATE.getType();
    private static final int PART_EDGING_TYPE = OrderImportTmpDataTypeEnum.PART_EDGING.getType();
    private static final int PART_HARDWARE_TYPE = OrderImportTmpDataTypeEnum.PART_HARDWARE.getType();
    private static final int PART_ASSEMBLY_TYPE = OrderImportTmpDataTypeEnum.PART_ASSEMBLY.getType();

    private SnowFlakeGenerator snowFlakeGenerator;

    private SnowflakeIdWorker3rd idWorker;

    private OrderImportTaskMapper orderImportTaskMapper;

    private OrderImportTempDataMapper orderImportTempDataMapper;

    private GoodsMapper goodsMapper;

    private RawGoodsMapper rawGoodsMapper;

    private OrderPartsMapper orderPartsMapper;

    private OrderBodyMapper orderBodyMapper;

    private OrderGroupMapper orderGroupMapper;

    private PlateMapper plateMapper;

    private OrderItemMapper orderItemMapper;

    private PlateGoodMapper plateGoodMapper;

    private OrderInputProcessor orderInputProcessor;

    private PartsMapper partsMapper;

    private String operatorName;

    private CustomPlateNoGenerateService customPlateNoGenerateService;

    public DefaultXmlOrderImportFactory(Long taskId,
                                        OrderDO orderDO,
                                        Long organId,
                                        String operatorName,
                                        SnowFlakeGenerator snowFlakeGenerator,
                                        SnowflakeIdWorker3rd idWorker,
                                        OrderImportTaskMapper orderImportTaskMapper,
                                        OrderImportTempDataMapper orderImportTempDataMapper,
                                        GoodsMapper goodsMapper,
                                        RawGoodsMapper rawGoodsMapper,
                                        OrderPartsMapper orderPartsMapper,
                                        OrderBodyMapper orderBodyMapper,
                                        OrderGroupMapper orderGroupMapper,
                                        PlateMapper plateMapper,
                                        OrderItemMapper orderItemMapper,
                                        PlateGoodMapper plateGoodMapper,
                                        OrderInputProcessor orderInputProcessor,
                                        PartsMapper partsMapper,
                                        CustomPlateNoGenerateService customPlateNoGenerateService) {
        this.taskId = taskId;
        this.orderDO = orderDO;
        this.orderId = orderDO.getId();
        this.organId = organId;
        this.operatorName = operatorName;
        this.snowFlakeGenerator = snowFlakeGenerator;
        this.idWorker = idWorker;
        this.orderImportTaskMapper = orderImportTaskMapper;
        this.orderImportTempDataMapper = orderImportTempDataMapper;
        this.goodsMapper = goodsMapper;
        this.rawGoodsMapper = rawGoodsMapper;
        this.orderPartsMapper = orderPartsMapper;
        this.orderBodyMapper = orderBodyMapper;
        this.orderGroupMapper = orderGroupMapper;
        this.plateMapper = plateMapper;
        this.orderItemMapper = orderItemMapper;
        this.plateGoodMapper = plateGoodMapper;
        this.orderInputProcessor = orderInputProcessor;
        this.partsMapper = partsMapper;
        this.customPlateNoGenerateService = customPlateNoGenerateService;
        batchId = (Long) snowFlakeGenerator.nextId(null);
    }

    private Map<String, Map<String, OrderImportTempDataDO>> roomBodyMap = new HashMap<>(); // 房间code: （柜体code：柜体数据）

    private Map<String, OrderImportTempDataDO> groupMap = new HashMap<>(); // 加工组code：加工组数据

    private Map<String, OrderPartsDO> orderPartsDOMap = new HashMap<>(); // 配件code：orderpartsdo

    /**
     * 解析临时表数据
     */
    public void analyzeTempData() {
        try {
            // 获取自定义板编号配置
            plateNoGenerateConfigVO = customPlateNoGenerateService.getPlateNoGenerateConfig(orderId);

            log.info("====================【生产单默认xml导入处理柜体开始】====================");
            // 解析柜体数据
            analyzeBodyNoPaging();
            log.info("====================【生产单默认xml导入处理柜体结束】====================");

            log.info("====================【生产单默认xml导入处理加工组开始】====================");
            // 解析加工组
            analyzeGroupNoPaging();
            log.info("====================【生产单默认xml导入处理加工组结束】====================");

            log.info("====================【生产单默认xml导入处理商品开始】====================");
            // 解析商品数据
            analyzeGoodsDetailNoPaging();
            log.info("====================【生产单默认xml导入处理商品结束】====================");

            log.info("====================【生产单默认xml导入处理板件开始】====================");
            // 解析板件
            analyzePlate();
            log.info("====================【生产单默认xml导入处理板件结束】====================");

            log.info("====================【生产单默认xml导入处理配件开始】====================");
            // 解析配件
            analyzeParts();
            log.info("====================【生产单默认xml导入处理配件结束】====================");

            log.info("====================【生产单默认xml导入处理回显开始】====================");
            // 把缓存数据回显到业务表
            writeBackToOrders();
            log.info("====================【生产单默认xml导入处理回显结束】====================");

            // 删除临时数据
            deleteTempData();
            // 完成所有流程后更新任务为导入成功
            updateTaskSuccess();
        } catch (Exception e) {
            // 数据库数据回滚，此时删除 ES 里的数据
            orderInputProcessor.deleteByOrderIdBatch(orderId, batchId, ORDER_PLATE_MODEL);
            orderInputProcessor.deleteByOrderIdBatch(orderId, batchId, ORDER_PARTS_REMARK_MODEL);
            throw e;
        } finally {
            clearAll();
        }
    }

    private void analyzeBodyNoPaging() {
        // 查询柜体列表
        List<OrderImportTempDataDO> bodyTempDataList = orderImportTempDataMapper.selectList(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, BODY_TYPE)
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        for (OrderImportTempDataDO bodyDO : bodyTempDataList) {
            String roomCode = bodyDO.getRoomCode();
            String bodyCode = bodyDO.getBodyCode();

            Map<String, OrderImportTempDataDO> bodyTempMap = roomBodyMap.get(roomCode);
            if (MapUtil.isNotEmpty(bodyTempMap)) {
                OrderImportTempDataDO bodyTempData = bodyTempMap.get(bodyCode);
                if (ObjectUtil.isNotNull(bodyTempData)) {
                    // 有房间有柜体，不再缓存
                    return;
                }
                // 有房间没柜体，取房间id，后续操作增加房间下柜体
                Map.Entry<String, OrderImportTempDataDO> anyBody = bodyTempMap.entrySet().iterator().next();
                bodyDO.setInnerRoomId(anyBody.getValue().getInnerRoomId());
            }

            // 创建order_body
            OrderBodyDO orderBodyDO = createOrderBodyDO(bodyDO);
            orderBodyDOS.add(orderBodyDO);
            // 批量插入orderGroup
            orderInfoBatchInsertWithinThreshold(orderBodyMapper, orderBodyDOS, false);
            // imes房间id、柜体id回显到临时数据
            bodyDO.setInnerBodyId(orderBodyDO.getId());
            bodyDO.setInnerRoomId(orderBodyDO.getRoomId());
            if (MapUtil.isNotEmpty(bodyTempMap)) {
                bodyTempMap.put(bodyCode, bodyDO);
            } else {
                // 缓存柜体
                roomBodyMap.put(roomCode, MapUtil.<String, OrderImportTempDataDO>builder().put(bodyCode, bodyDO).build());
            }
        }
        //最后批量插入一次，避免最后一页小于BATCH_THRESHOLD_NUMBER漏插入
        orderInfoBatchInsertWithinThreshold(orderBodyMapper, orderBodyDOS, true);
    }

    /**
     * 不分页解析商品id分组列表
     */
    private void analyzeGoodsDetailNoPaging() {
        // 查询商品列表
        List<OrderImportTempDataDO> goodsTempDataList = orderImportTempDataMapper.selectList(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, GOODS_TYPE)
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        for (OrderImportTempDataDO goodsTempData : goodsTempDataList) {
            String detail = goodsTempData.getDetail();
            if (StringUtils.isNotBlank(detail)) {
                PlateXmlVO plateXmlVO = JsonUtils.parseObject(JsonUtils.unzipString(detail), PlateXmlVO.class);
                if (StringUtils.equals(plateXmlVO.getGrained().trim(), "无")) {
                    plateXmlVO.setGrained("false");
                } else if (StringUtils.equals(plateXmlVO.getGrained().trim(), "有")) {
                    plateXmlVO.setGrained("true");
                }

                Long rawGoodsId = (Long) snowFlakeGenerator.nextId(null);
                Long goodsId = NumberUtil.parseLong(goodsTempData.getInnerGoodsId());
                RawGoodsDO rawGoodsDO = RawGoodsDO.builder()
                        .id(rawGoodsId)
                        .organId(organId)
                        .orderId(orderId)
                        .rawGoodsId(plateXmlVO.getItemCode())
                        .goodsName(plateXmlVO.getName())
                        .material(plateXmlVO.getMaterial())
                        .color(plateXmlVO.getCoatingObverse())
                        .colorBlack(plateXmlVO.getCoatingReverse())
                        .texture(Boolean.valueOf(plateXmlVO.getGrained()))
                        .thickness(Double.parseDouble(plateXmlVO.getThickness()))
                        .brand(plateXmlVO.getBrand())
                        .spec(plateXmlVO.getSpecs())
                        .price(0.00)
                        .deleted(false)
                        .build();
                rawGoodsDO.setCreator(operatorName);
                rawGoodsDO.setUpdater(operatorName);
                LocalDateTime now = LocalDateTime.now();
                rawGoodsDO.setCreateTime(now);
                rawGoodsDO.setUpdateTime(now);

                GoodsDO goodsDO = GoodsDO.builder()
                        .id(goodsId)
                        .organId(organId)
                        .orderId(orderId)
                        .rawGoodsId(String.valueOf(rawGoodsId))
                        .goodsId(plateXmlVO.getItemCode())
                        .goodsName(plateXmlVO.getName())
                        .material(plateXmlVO.getMaterial())
                        .color(plateXmlVO.getCoatingObverse())
                        .colorBlack(plateXmlVO.getCoatingReverse())
                        .texture(Boolean.valueOf(plateXmlVO.getGrained()))
                        .width(BigDecimal.valueOf(Double.parseDouble(plateXmlVO.getWidth())))
                        .height(BigDecimal.valueOf(Double.parseDouble(plateXmlVO.getLength())))
                        .thickness(BigDecimal.valueOf(Double.parseDouble(plateXmlVO.getThickness())))
                        .brand(plateXmlVO.getBrand())
                        .spec(plateXmlVO.getSpecs())
                        .remark(plateXmlVO.getMemo())
                        .planId(0L)
                        .price(0.00)
                        .deleted(false)
                        .build();
                goodsDO.setCreator(operatorName);
                goodsDO.setUpdater(operatorName);
                goodsDO.setCreateTime(now);
                goodsDO.setUpdateTime(now);

                goodsDOS.add(goodsDO);
                rawGoodsDOS.add(rawGoodsDO);
                // 批量插入rawgoods、goods
                orderInfoBatchInsertWithinThreshold(rawGoodsMapper, rawGoodsDOS, false);
                orderInfoBatchInsertWithinThreshold(goodsMapper, goodsDOS, false);
            }
        }
        // 最后批量插入rawgoods、goods、plategoods一次，避免最后一页小于BATCH_THRESHOLD_NUMBER漏插入
        orderInfoBatchInsertWithinThreshold(rawGoodsMapper, rawGoodsDOS, true);
        orderInfoBatchInsertWithinThreshold(goodsMapper, goodsDOS, true);
        orderInfoBatchInsertWithinThreshold(plateGoodMapper, plateGoodDOS, true);
    }

    /**
     * 不分页解析加工组
     */
    private void analyzeGroupNoPaging() {
        // 查询加工组列表
        List<OrderImportTempDataDO> groupTempDataList = orderImportTempDataMapper.selectList(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, GROUP_TYPE)
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        for (OrderImportTempDataDO groupDO : groupTempDataList) {
            // 创建order_group
            OrderGroupDO orderGroupDO = createOrderGroupDO(groupDO);
            orderGroupDOS.add(orderGroupDO);
            // 批量插入orderGroup
            orderInfoBatchInsertWithinThreshold(orderGroupMapper, orderGroupDOS, false);
            // imes柜体id回显到临时数据
            groupDO.setInnerGroupId(orderGroupDO.getId());
            // 缓存加工组
            groupMap.put(groupDO.getGroupCode(), groupDO);
        }
        //最后批量插入一次，避免最后一页小于BATCH_THRESHOLD_NUMBER漏插入
        orderInfoBatchInsertWithinThreshold(orderGroupMapper, orderGroupDOS, true);
    }

    private void analyzePlate() {
        Page<OrderImportTempDataDO> page = new Page<>(1, BATCH_THRESHOLD_NUMBER);
        orderImportTempDataMapper.selectList(page, new LambdaQueryWrapper<OrderImportTempDataDO>()
                        .eq(OrderImportTempDataDO::getTaskId, taskId)
                        .eq(OrderImportTempDataDO::getType, PLATE_TYPE)
                        .eq(OrderImportTempDataDO::getOrganId, organId), new ResultHandler<>() {
                    int count = 0;

                    @Override
                    public void handleResult(ResultContext<? extends OrderImportTempDataDO> resultContext) {
                        OrderImportTempDataDO plateTempData = resultContext.getResultObject();

                        // 解析板件明细数据
                        String detail = JsonUtils.unzipString(plateTempData.getDetail());
                        BlockXmlVO blockXmlVO = JSON.parseObject(detail, BlockXmlVO.class);

                        long plateNo = idWorker.nextId();
                        long obtainingTime = idWorker.obtainingTime();
                        Long plateId = (Long) snowFlakeGenerator.nextId(null);

                        // 成品面积
                        Double length = changeUnit(blockXmlVO.getLength(), blockXmlVO.getUnit(), DictTypeConstants.UNIT_LENGTH);
                        Double width = changeUnit(blockXmlVO.getWidth(), blockXmlVO.getUnit(), DictTypeConstants.UNIT_LENGTH);
                        BigDecimal area = BigDecimal.valueOf((length / 1000) * (width / 1000));

                        // 获取开门类型
                        int doorType = Integer.parseInt(DictFrameworkUtils.parseDictDataValue(DictTypeConstants.DOOR_OPENING_DIRECTIONS, blockXmlVO.getOpenDirection()));

                        // 获取房间柜体缓存
                        String roomCode = plateTempData.getRoomCode();
                        String bodyCode = plateTempData.getBodyCode();

                        // 房间、柜体基点坐标
                        BasePosition roomBasePoint = null;
                        BasePosition bodyBasePoint = null;

                        Map<String, OrderImportTempDataDO> roomTempDataMap = roomBodyMap.get(roomCode);
                        OrderImportTempDataDO roomBodyTempDataDO = null;
                        // 板材数量和异形数量回显到柜体
                        if (MapUtil.isNotEmpty(roomTempDataMap)) {
                            roomBodyTempDataDO = roomTempDataMap.get(bodyCode);
                            if (ObjectUtil.isNotNull(roomBodyTempDataDO)) {
                                if (convertToBoolean(blockXmlVO.getUnregular())) {
                                    roomBodyTempDataDO.setUnregularNum(roomBodyTempDataDO.getUnregularNum() + 1);
                                    roomBasePoint = roomBodyTempDataDO.getRoomPosition();
                                    bodyBasePoint = roomBodyTempDataDO.getBodyPosition();
                                } else {
                                    roomBodyTempDataDO.setPlateNum(roomBodyTempDataDO.getPlateNum() + 1);
                                }
                            }
                        }

                        // 获取加工组缓存
                        String groupCode = plateTempData.getGroupCode();
                        OrderImportTempDataDO groupTempDataDO = groupMap.get(groupCode);
                        // 柜体id回显到加工组
                        if (ObjectUtil.isNotNull(groupTempDataDO) && ObjectUtil.isNull(groupTempDataDO.getInnerBodyId()) && ObjectUtil.isNotNull(roomBodyTempDataDO)) {
                            groupTempDataDO.setInnerBodyId(roomBodyTempDataDO.getInnerBodyId());
                        }

                        long goodsId = Long.parseLong(plateTempData.getInnerGoodsId());
                        // 板类型
                        int plateType = Integer.parseInt(DictFrameworkUtils.parseDictDataValue(DictTypeConstants.PLATE_TYPE, blockXmlVO.getType()));
                        PlateDO plateDO = PlateDO.builder()
                                .id(plateId)
                                .orderId(orderId)
                                .name(blockXmlVO.getName())
                                .plateNo((obtainingTime) + Long.toString(plateNo).substring(2))
                                .type(plateType)
                                .goodsId(goodsId)
                                .width(BigDecimal.valueOf(Double.parseDouble(blockXmlVO.getWidth())))
                                .height(BigDecimal.valueOf(Double.parseDouble(blockXmlVO.getLength())))
                                .thickness(BigDecimal.valueOf(Double.parseDouble(blockXmlVO.getThickness())))
                                .splitHeight(BigDecimal.valueOf(Double.parseDouble(blockXmlVO.getLength())))
                                .splitThickness(BigDecimal.valueOf(Double.parseDouble(blockXmlVO.getThickness())))
                                .splitWidth(BigDecimal.valueOf(Double.parseDouble(blockXmlVO.getWidth())))
                                .area(area)
                                .texture(Integer.valueOf(DictFrameworkUtils.parseDictDataValue(DictTypeConstants.GRAIN_TYPE, blockXmlVO.getTexture())))
                                .holeFace(Integer.valueOf(DictFrameworkUtils.parseDictDataValue(DictTypeConstants.TYPOGRAPHY_TYPE, blockXmlVO.getLayoutFace())))
                                .isDoor(doorType != 0)
                                .openDoorType(doorType)
                                .isSculpt(false)
                                .isSpecialShaped(convertToBoolean(blockXmlVO.getUnregular()))
                                .customPlateNoBuilder(new StringBuilder())
                                .organId(organId)
                                .holeArrange(0)
                                .holeFace(0)
                                .unregularPointCount(0)
                                .frontHoleCount(0)
                                .backHoleCount(0)
                                .sideHoleCount(0)
                                .frontModelCount(0)
                                .backModelCount(0)
                                .isDoor(false)
                                .offsetX(BIG_ZERO)
                                .offsetY(BIG_ZERO)
                                .isArcAcross(false)
                                .moduleTypeId(0L)
                                .isRowHole(false)
                                .isOptimized(false)
                                .isCutted(0)
                                .isCancel(false)
                                .filterType(EMPTY_STRING)
                                .sealLeft(BigDecimal.ZERO)
                                .sealRight(BigDecimal.ZERO)
                                .sealUp(BigDecimal.ZERO)
                                .sealDown(BigDecimal.ZERO)
                                .remark(EMPTY_STRING)
                                .deleted(false)
                                .build();
                        plateDO.setCreator(operatorName);
                        plateDO.setUpdater(operatorName);
                        LocalDateTime now = LocalDateTime.now();
                        plateDO.setCreateTime(now);
                        plateDO.setUpdateTime(now);

                        // 生成自定义板编号
                        generateCustomPlateNo(plateDO);

                        OrderItemDO orderItemDO = OrderItemDO.builder()
                                .id((Long) snowFlakeGenerator.nextId(null))
                                .orderId(orderId)
                                .type(OrderItemTypeEnum.PLATE_ITEM.getStatus())
                                .plateId(plateId)
                                .groupId(Optional.ofNullable(groupTempDataDO).map(OrderImportTempDataDO::getInnerGroupId).orElse(0L))
                                .roomId(roomBodyTempDataDO.getInnerRoomId())
                                .bodyId(roomBodyTempDataDO.getInnerBodyId())
                                .num(1.0)
                                .organId(organId)
                                .packageId(0L)
                                .partsId(0L)
                                .build();
                        // 批量插入order_item
                        orderItemDOS.add(orderItemDO);
                        orderInfoBatchInsertWithinThreshold(orderItemMapper, orderItemDOS, false);

                        // 基点坐标
                        BasePosition plateBasePosition = BasePosition.builder()
                                .basePoint(String.valueOf(plateId))
                                .basePointX(Double.valueOf(blockXmlVO.getBasePointX()))
                                .basePointY(Double.valueOf(blockXmlVO.getBasePointY()))
                                .basePointZ(Double.valueOf(blockXmlVO.getBasePointZ()))
                                .axisXrotate(Double.valueOf(blockXmlVO.getAxisXrotate()))
                                .axisYrotate(Double.valueOf(blockXmlVO.getAxisYrotate()))
                                .axisZrotate(Double.valueOf(blockXmlVO.getAxisZrotate()))
                                .build();

                        // 板件es数据
                        OrderModelDO orderModelDO = OrderModelDO.builder()
                                .orderId(orderId)
                                .batchId(batchId)
                                .plateId(plateId)
                                .has2DModel(false)
                                .has3DModel(false)
                                .texture(plateDO.getTexture())
                                .typographicFace(plateDO.getHoleFace())
                                .openDoorType(plateDO.getOpenDoorType())
                                .boardType(blockXmlVO.getType())
                                .roomBasePosition(roomBasePoint)
                                .bodyBasePosition(bodyBasePoint)
                                .plateBasePosition(plateBasePosition)
                                .splitLength(BigDecimal.valueOf(Long.parseLong(blockXmlVO.getCuttingLength())))
                                .splitWidth(BigDecimal.valueOf(Long.parseLong(blockXmlVO.getCuttingWidth())))
                                .pointDetail(new ArrayList<>())
                                .rawPointDetail(new ArrayList<>())
                                .basePointDetail(new ArrayList<>())
                                .holeCount(new HashMap<>())
                                .holeDetail(new ArrayList<>())
                                .contourCount(new HashMap<>())
                                .contourDetail(new ArrayList<>())
                                .sideHoleDetail(new ArrayList<>())
                                .sideRemark(new HashMap<>())
                                .plateExtraRemark(new JSONObject())
                                .build();

                        // 小板、es 封边值
                        addSealEdge(plateDO, orderModelDO, blockXmlVO.getOutlineXmlVO(), orderItemDO);
                        // 偏移量 不含封边
                        addPointDetail(plateDO, orderModelDO, blockXmlVO.getCuttingOutlineXmlVO());
                        addPointDetail(orderModelDO, blockXmlVO.getRawOutlineXmlVO()); // 坯料
                        // 孔数据
                        addHole(plateDO, orderModelDO, blockXmlVO.getHoleXmlVOS());
                        // 造型数据 (槽）, 加孤岛信息
                        addContourDetail(plateDO, orderModelDO, blockXmlVO.getGrooveXmlVOS(), blockXmlVO.getIsletXmlVOS());
                        // 小板关联配件
                        addParts(orderModelDO, blockXmlVO.getCorrelationXmlVOS());
                        // 小板备注信息
                        addRemark(plateDO, orderModelDO, blockXmlVO);

                        // 查询大板id用于小板轮廓goodsId
                        GoodsDO goodsDO = goodsMapper.selectById(goodsId);
                        Optional.ofNullable(goodsDO).orElseThrow(() -> ServiceExceptionUtil.exception(ORDER_IMPORT_PLATE_GOODS_NOT_EXISTS, orderId, goodsId));
                        orderModelDO.setGoodsId(goodsDO.getGoodsId());
                        orderModelDO.setPlateGoodsId(goodsId);
                        orderModelDO.setOrganId(organId);
                        orderModelDO.setCreator(operatorName);
                        orderModelDO.setUpdater(operatorName);
                        orderModelDOS.add(orderModelDO);

                        // 批量插入order_plate
                        plateDOS.add(plateDO);
                        orderInfoBatchInsertWithinThreshold(plateMapper, plateDOS, false);
                        // 批量插入造型数据
                        orderModelsBatchInsertWithinThreshold(false);
                    }
                }
        );
        //最后批量插入一次，避免最后一页小于BATCH_THRESHOLD_NUMBER漏插入
        orderInfoBatchInsertWithinThreshold(plateMapper, plateDOS, true);
        // 批量插入造型数据
        orderModelsBatchInsertWithinThreshold(true);

        // 所有自定义板编号生成完成后更新配置到生产单
        customPlateNoGenerateService.updateCustomPlateNoGenerateConfig(plateNoGenerateConfigVO, orderDO);
    }

    /**
     * 生成自定义板编号
     *
     * @param plateDO
     */
    private void generateCustomPlateNo(PlateDO plateDO) {
        if (!isFirstPlate) {
            isFirstPlate = true;
        }
        // 配置不为空时，生成自定义板编号
        if (ObjectUtil.isNotNull(plateNoGenerateConfigVO)) {
            customPlateNoGenerateService.generateCustomPlateNo(orderId, plateDO, plateNoGenerateConfigVO, isFirstPlate);
        }
    }

    /**
     * 封边值相关信息添加 (原始点明细)
     *
     * @param plateDO
     * @param plateDetail
     * @param outlineXmlVO
     * @param orderItemDO
     */
    private void addSealEdge(PlateDO plateDO, OrderModelDO plateDetail, OutlineXmlVO outlineXmlVO, OrderItemDO orderItemDO) {
        BigDecimal[] sealPositions = new BigDecimal[4];
        Arrays.fill(sealPositions, BigDecimal.ZERO);

        if (outlineXmlVO != null && outlineXmlVO.getPointXmlVOList() != null && !outlineXmlVO.getPointXmlVOList().isEmpty()) {
            ExtraVO extraVO = ExtraVO.builder()
                    .edgeRemarks(new ArrayList<>())
                    .rectSealDetail(new ArrayList<>())
                    .build();
            int indexId = 0;
            for (PointXmlVO pointXmlVO : outlineXmlVO.getPointXmlVOList()) {
                if (!(pointXmlVO.getItemCode() == null && pointXmlVO.getEdgingName() == null && pointXmlVO.getEdgingColor() == null
                        && pointXmlVO.getEdgingMaterial() == null && (pointXmlVO.getEdgingThickness() == null || pointXmlVO.getEdgingThickness().trim().equals("0")))) {
                    double x = Double.parseDouble(pointXmlVO.getPointX());
                    double y = Double.parseDouble(pointXmlVO.getPointY());
                    BigDecimal size = new BigDecimal(pointXmlVO.getEdgingThickness());

                    String itemCode = pointXmlVO.getItemCode();
                    if (StringUtils.isNotEmpty(itemCode)) {
                        // 配件编码匹配，不存在需要新增
                        addSealEdgePart(orderItemDO, pointXmlVO);
                    }

                    // 计算封边条厚度
                    calculateSealPositions(plateDO, pointXmlVO, sealPositions);

                    plateDetail.getRawPointDetail().add(PointDetail.builder()
                            .pointX(x)
                            .pointY(y)
                            .curve(Double.parseDouble(pointXmlVO.getCurvature()))
                            .radius(Double.parseDouble(pointXmlVO.getRadius()))
                            .sealSize(size)
                            .build());
                    extraVO.getEdgeRemarks().add(pointXmlVO.getRemark());
                    extraVO.getRectSealDetail().add(RectSealVO.builder()
                            .pointID(String.valueOf(indexId))
                            .reservedEdge(pointXmlVO.getScale())
                            .sealColor(pointXmlVO.getEdgingColor())
                            .sealSize(pointXmlVO.getEdgingThickness())
                            .build());
                    indexId++;
                }

            }
            String jsonString = JSON.toJSONString(extraVO);
            JSONObject jsonObject = JSON.parseObject(jsonString);
            plateDetail.setPlateExtraRemark(jsonObject);
        }
        plateDO.setSealLeft(sealPositions[0]).setSealRight(sealPositions[1]).setSealUp(sealPositions[2]).setSealDown(sealPositions[3]);
    }

    /**
     * 计算封边条上下左右厚度
     *
     * @param plateDO
     * @param pointXmlVO
     * @param sealPositions
     */
    private void calculateSealPositions(PlateDO plateDO, PointXmlVO pointXmlVO, BigDecimal[] sealPositions) {
        if (!plateDO.getIsSpecialShaped()) {
            double x = Double.parseDouble(pointXmlVO.getPointX());
            double y = Double.parseDouble(pointXmlVO.getPointY());
            BigDecimal size = new BigDecimal(pointXmlVO.getEdgingThickness());

            if (x == 0 && y != 0) {
                sealPositions[0] = size; // sealLeft
            }
            if (x != 0 && y == 0) {
                sealPositions[1] = size; // sealRight
            }
            if (x != 0 && y != 0) {
                sealPositions[2] = size; // sealUp
            }
            if (x == 0 && y == 0) {
                sealPositions[3] = size; // sealDown
            }
        }
    }

    /**
     * 新增封边条配件
     *
     * @param pointXmlVO
     */
    private void addSealEdgePart(OrderItemDO orderItemDO, PointXmlVO pointXmlVO) {
        String itemCode = pointXmlVO.getItemCode();
        OrderPartsDO orderPartsDOinMap = orderPartsDOMap.get(itemCode);
        if (ObjectUtil.isNull(orderPartsDOinMap)) {
            String edgingMaterial = pointXmlVO.getEdgingMaterial();
            String edgingColor = pointXmlVO.getEdgingColor();
            OrderPartsDO orderPartsDO = OrderPartsDO.builder()
                    .id((Long) snowFlakeGenerator.nextId(null))
                    .name(pointXmlVO.getEdgingName())
                    .goodsId(itemCode)
                    .type("封边条")
                    .category("封边条")
                    .orderId(orderId)
                    .material(StringUtils.isNotEmpty(edgingMaterial) ? edgingMaterial : EMPTY_STRING)
                    .color(StringUtils.isNotEmpty(edgingColor) ? edgingColor : EMPTY_STRING)
                    .unit(pointXmlVO.getCountUnit())
                    .isComposite(false)
                    .width(DOUBLE_ZERO)
                    .length(DOUBLE_ZERO)
                    .spec(EMPTY_STRING)
                    .brand(EMPTY_STRING)
                    .factory(EMPTY_STRING)
                    .thickness(NumberUtil.parseDouble(pointXmlVO.getEdgingThickness()))
                    .subparts(EMPTY_STRING)
                    .remark(EMPTY_STRING)
                    .model(EMPTY_STRING)
                    .subparts(EMPTY_STRING)
                    .price(0.0)
                    .deleted(false)
                    .organId(organId)
                    .build();
            orderPartsDO.setCreator(operatorName);
            orderPartsDO.setUpdater(operatorName);
            LocalDateTime now = LocalDateTime.now();
            orderPartsDO.setCreateTime(now);
            orderPartsDO.setUpdateTime(now);

            // 批量插入orderParts
            orderPartsDOS.add(orderPartsDO);
            // 缓存配件
            orderPartsDOMap.put(itemCode, orderPartsDO);
            orderInfoBatchInsertWithinThreshold(orderPartsMapper, orderPartsDOS, false);

            // 封边总长度单位换算
            Double count = changeUnit(pointXmlVO.getCount(), pointXmlVO.getCountUnit(), DictTypeConstants.UNIT_LENGTH);
            OrderItemDO newEdgePartOrderItem = OrderItemDO.builder()
                    .id((Long) snowFlakeGenerator.nextId(null))
                    .orderId(orderId)
                    .type(OrderItemTypeEnum.PARTS_ITEM.getStatus())
                    .partsId(orderPartsDO.getId())
                    .groupId(orderItemDO.getGroupId())
                    .roomId(orderItemDO.getRoomId())
                    .bodyId(orderItemDO.getBodyId())
                    .num(count)
                    .organId(organId)
                    .packageId(0L)
                    .plateId(0L)
                    .build();
            // 批量插入order_item
            orderItemDOS.add(newEdgePartOrderItem);
            orderInfoBatchInsertWithinThreshold(orderItemMapper, orderItemDOS, false);
        }
    }

    /**
     * 点明细（不含封边）
     *
     * @param plateDO
     * @param plateDetail
     * @param cuttingOutlineXmlVO
     */
    private void addPointDetail(PlateDO plateDO, OrderModelDO plateDetail, CuttingOutlineXmlVO cuttingOutlineXmlVO) {
        if (cuttingOutlineXmlVO != null) {
            plateDO.setOffsetX(BigDecimal.valueOf(Double.parseDouble(cuttingOutlineXmlVO.getReferenceOffsetX()))).
                    setOffsetY(BigDecimal.valueOf(Double.parseDouble(cuttingOutlineXmlVO.getReferenceOffsetY())));
            plateDetail.setOffsetX(plateDO.getOffsetX()).setOffsetY(plateDO.getOffsetY());
            if (cuttingOutlineXmlVO.getPointXmlVOList() != null && cuttingOutlineXmlVO.getPointXmlVOList().size() > 0) {
                for (PointXmlVO pointXmlVO : cuttingOutlineXmlVO.getPointXmlVOList()) {
                    plateDetail.getPointDetail().add(PointDetail.builder()
                            .pointX(Double.parseDouble(pointXmlVO.getPointX()))
                            .pointY(Double.parseDouble(pointXmlVO.getPointY()))
                            .curve(Double.parseDouble(pointXmlVO.getCurvature()))
                            .radius(Double.parseDouble(pointXmlVO.getRadius()))
                            .process(pointXmlVO.getProcess())
                            .build());
                }
            }
        }
    }

    /**
     * 坯料
     *
     * @param plateDetail
     * @param rawOutlineXmlVO
     */
    private void addPointDetail(OrderModelDO plateDetail, RawOutlineXmlVO rawOutlineXmlVO) {
        if (rawOutlineXmlVO != null) {
            if (rawOutlineXmlVO.getPointXmlVOList() != null && rawOutlineXmlVO.getPointXmlVOList().size() > 0) {
                for (PointXmlVO pointXmlVO : rawOutlineXmlVO.getPointXmlVOList()) {
                    plateDetail.getBasePointDetail().add(PointDetail.builder()
                            .pointX(Double.parseDouble(pointXmlVO.getPointX()))
                            .pointY(Double.parseDouble(pointXmlVO.getPointY()))
                            .curve(Double.parseDouble(pointXmlVO.getCurvature()))
                            .radius(Double.parseDouble(pointXmlVO.getRadius()))
                            .process(pointXmlVO.getProcess())
                            .build());
                }
            }
        }
    }

    /**
     * 孔
     *
     * @param plateDO
     * @param plateDetail
     * @param holeXmlVOS
     */
    private void addHole(PlateDO plateDO, OrderModelDO plateDetail, HoleXmlVOS holeXmlVOS) {
        if (holeXmlVOS == null || holeXmlVOS.getHoleXmlVOList() == null || holeXmlVOS.getHoleXmlVOList().isEmpty()) {
            return;
        }

        Map<String, Integer> holeCountMap = extractHoleCount(holeXmlVOS);
        updatePlateDetailHoleCount(plateDetail, holeCountMap);
        updatePlateDOHoleCount(plateDO, holeXmlVOS);
        updatePlateDOFilterTypeIfThroughHolesExist(plateDO, holeXmlVOS);
        addHoleDetailsToPlateDetail(plateDetail, holeXmlVOS.getHoleXmlVOList());
    }

    /**
     * 孔数量
     *
     * @param holeXmlVOS
     * @return
     */
    private Map<String, Integer> extractHoleCount(HoleXmlVOS holeXmlVOS) {
        Map<String, Integer> holeCountMap = new HashMap<>();
        holeCountMap.put("count", Integer.valueOf(holeXmlVOS.getCount()));
        holeCountMap.put("countFaceA", Integer.valueOf(holeXmlVOS.getCountFaceA()));
        holeCountMap.put("countFaceB", Integer.valueOf(holeXmlVOS.getCountFaceB()));
        holeCountMap.put("countSide", Integer.valueOf(holeXmlVOS.getCountSide()));
        holeCountMap.put("countSideL", Integer.valueOf(holeXmlVOS.getCountSideL()));
        holeCountMap.put("countSideD", Integer.valueOf(holeXmlVOS.getCountSideD()));
        holeCountMap.put("countSideR", Integer.valueOf(holeXmlVOS.getCountSideR()));
        holeCountMap.put("countSideU", Integer.valueOf(holeXmlVOS.getCountSideU()));
        holeCountMap.put("countBevelled", Integer.valueOf(holeXmlVOS.getCountBevelled()));
        holeCountMap.put("countLocking", Integer.valueOf(holeXmlVOS.getCountLocking()));
        holeCountMap.put("countBuildIn", Integer.valueOf(holeXmlVOS.getCountBuildIn()));
        holeCountMap.put("countHinge", Integer.valueOf(holeXmlVOS.getCountHinge()));
        holeCountMap.put("countThrough", Integer.valueOf(holeXmlVOS.getCountThrough()));
        return holeCountMap;
    }

    private void updatePlateDetailHoleCount(OrderModelDO plateDetail, Map<String, Integer> holeCountMap) {
        plateDetail.getHoleCount().putAll(holeCountMap);
    }

    private void updatePlateDOHoleCount(PlateDO plateDO, HoleXmlVOS holeXmlVOS) {
        plateDO.setFrontHoleCount(Integer.valueOf(holeXmlVOS.getCountFaceA()));
        plateDO.setBackHoleCount(Integer.valueOf(holeXmlVOS.getCountFaceB()));
        plateDO.setSideHoleCount(Integer.valueOf(holeXmlVOS.getCountSide()));
    }

    private void updatePlateDOFilterTypeIfThroughHolesExist(PlateDO plateDO, HoleXmlVOS holeXmlVOS) {
        if (holeXmlVOS.getCountThrough() != null && Integer.parseInt(holeXmlVOS.getCountThrough()) > 0) {
            plateDO.setFilterType(plateDO.getFilterType() + ",2");
        }
    }

    private void addHoleDetailsToPlateDetail(OrderModelDO plateDetail, List<HoleXmlVO> holeXmlVOList) {
        for (HoleXmlVO holeXmlVO : holeXmlVOList) {
            HoleDetail holeDetail = createHoleDetail(holeXmlVO);
            plateDetail.getHoleDetail().add(holeDetail);
        }
    }

    private HoleDetail createHoleDetail(HoleXmlVO holeXmlVO) {
        String faceType = DictFrameworkUtils.parseDictDataValue(DictTypeConstants.HOLE_FACE, holeXmlVO.getFace());
        Integer faceTypeValue = StringUtils.isNotEmpty(faceType) ? Integer.parseInt(faceType) : 2;
        Integer direction = Integer.valueOf(DictFrameworkUtils.parseDictDataValue(DictTypeConstants.HOLE_DIRECTION, holeXmlVO.getDirection()));
        Double radius = holeXmlVO.getDiameter() != null ? Double.parseDouble(holeXmlVO.getDiameter()) / 2 : 0;
        Double depth = holeXmlVO.getDepth() != null ? Double.parseDouble(holeXmlVO.getDepth()) : 0;

        return HoleDetail.builder()
                .holeName(holeXmlVO.getName())
                .faceType(faceTypeValue)
                .direction(direction)
                .holeTypeStr(holeXmlVO.getType())
                .radius(radius)
                .depth(depth)
                .startX(holeXmlVO.getStartX() != null ? Double.parseDouble(holeXmlVO.getStartX()) : 0)
                .startY(holeXmlVO.getStartY() != null ? Double.parseDouble(holeXmlVO.getStartY()) : 0)
                .startZ(holeXmlVO.getStartZ() != null ? Double.parseDouble(holeXmlVO.getStartZ()) : 0)
                .endX(holeXmlVO.getEndX() != null ? Double.parseDouble(holeXmlVO.getEndX()) : 0)
                .endY(holeXmlVO.getEndY() != null ? Double.parseDouble(holeXmlVO.getEndY()) : 0)
                .endZ(holeXmlVO.getEndZ() != null ? Double.parseDouble(holeXmlVO.getEndZ()) : 0)
                .build();
    }

    /**
     * 造型
     *
     * @param plateDO
     * @param plateDetail
     * @param grooveXmlVOS
     * @param isletXmlVOS
     */
    private void addContourDetail(PlateDO plateDO, OrderModelDO plateDetail, GrooveXmlVOS grooveXmlVOS, IsletXmlVOS isletXmlVOS) {
        if (grooveXmlVOS == null || org.apache.commons.lang3.ObjectUtils.allNull(grooveXmlVOS)) {
            return;
        }

        Map<String, Integer> contourCount = extractContourCount(grooveXmlVOS);
        updatePlateDetailWithContourCount(plateDetail, contourCount);
        updatePlateDOWithContourCount(plateDO, grooveXmlVOS);
        updatePlateDOFilterTypeIfThroughGroovesExist(plateDO, grooveXmlVOS);

        if (grooveXmlVOS.getGrooveXmlVOList() != null && !grooveXmlVOS.getGrooveXmlVOList().isEmpty()) {
            addGrooveDetailsToPlateDetail(plateDetail, grooveXmlVOS.getGrooveXmlVOList(), isletXmlVOS);
        }
    }

    /**
     * 轮廓数量
     *
     * @param grooveXmlVOS
     * @return
     */
    private Map<String, Integer> extractContourCount(GrooveXmlVOS grooveXmlVOS) {
        Map<String, Integer> contourCount = new HashMap<>();
        contourCount.put("count", Integer.valueOf(grooveXmlVOS.getCount()));
        contourCount.put("countFaceA", Integer.valueOf(grooveXmlVOS.getCountFaceA()));
        contourCount.put("countFaceB", Integer.valueOf(grooveXmlVOS.getCountFaceB()));
        contourCount.put("countSide", Integer.valueOf(grooveXmlVOS.getCountSide()));
        contourCount.put("countSideL", Integer.valueOf(grooveXmlVOS.getCountSideL()));
        contourCount.put("countSideD", Integer.valueOf(grooveXmlVOS.getCountSideD()));
        contourCount.put("countSideR", Integer.valueOf(grooveXmlVOS.getCountSideR()));
        contourCount.put("countSideU", Integer.valueOf(grooveXmlVOS.getCountSideU()));
        contourCount.put("countBevelled", Integer.valueOf(grooveXmlVOS.getCountBevelled()));
        contourCount.put("countRectangle", Integer.valueOf(grooveXmlVOS.getCountRectangle()));
        contourCount.put("count2V", Integer.valueOf(grooveXmlVOS.getCount2V()));
        contourCount.put("count3D", Integer.valueOf(grooveXmlVOS.getCount3D()));
        contourCount.put("countThrough", Integer.valueOf(grooveXmlVOS.getCountThrough()));
        return contourCount;
    }

    private void updatePlateDetailWithContourCount(OrderModelDO plateDetail, Map<String, Integer> contourCount) {
        plateDetail.getContourCount().putAll(contourCount);
        plateDetail.setHas2DModel(contourCount.getOrDefault("count2V", 0) > 0);
        plateDetail.setHas3DModel(contourCount.getOrDefault("count3D", 0) > 0);
    }

    private void updatePlateDOWithContourCount(PlateDO plateDO, GrooveXmlVOS grooveXmlVOS) {
        plateDO.setFrontModelCount(Integer.valueOf(grooveXmlVOS.getCountFaceA()));
        plateDO.setBackModelCount(Integer.valueOf(grooveXmlVOS.getCountFaceB()));
    }

    private void updatePlateDOFilterTypeIfThroughGroovesExist(PlateDO plateDO, GrooveXmlVOS grooveXmlVOS) {
        if (grooveXmlVOS.getCountThrough() != null && Integer.parseInt(grooveXmlVOS.getCountThrough()) > 0) {
            plateDO.setFilterType(plateDO.getFilterType() + ",1");
        }
    }

    private void addGrooveDetailsToPlateDetail(OrderModelDO plateDetail, List<GrooveXmlVO> grooveXmlVOList, IsletXmlVOS isletXmlVOS) {
        for (GrooveXmlVO grooveXmlVO : grooveXmlVOList) {
            ModelDetail modelDetail = createModelDetail(grooveXmlVO, isletXmlVOS);
            plateDetail.getContourDetail().add(modelDetail);
        }
    }

    private ModelDetail createModelDetail(GrooveXmlVO grooveXmlVO, IsletXmlVOS isletXmlVOS) {
        // 槽内孤岛id转换
        String[] subIDs = null;
        if (grooveXmlVO.getSubIDs() != null) {
            subIDs = Arrays.stream(grooveXmlVO.getSubIDs().split(",")).map(String::valueOf).toArray(String[]::new);
        }
        return ModelDetail.builder()
                .modelID(Integer.valueOf(grooveXmlVO.getId()))
                .subIDs(subIDs)
                .type(grooveXmlVO.getType())
                .grooveFace(grooveXmlVO.getFace())
                .width(Double.parseDouble(grooveXmlVO.getWidth()))
                .length(Double.parseDouble(grooveXmlVO.getLength()))
                .depth(Double.parseDouble(grooveXmlVO.getDepth()))
                .knifeName(grooveXmlVO.getToolName())
                .toolNo(grooveXmlVO.getToolNo())
                .knifeRadius(Double.parseDouble(grooveXmlVO.getToolDiameter()) / 2)
                .round(Double.parseDouble(grooveXmlVO.getRound()))
                .redundance(Double.parseDouble(grooveXmlVO.getRedundance()))
                .tangentAngle(Double.parseDouble(grooveXmlVO.getTangentAngle()))
                .originModeling(getOriginModelingData(grooveXmlVO, subIDs, isletXmlVOS))
                .pointList(addPointDetail(grooveXmlVO.getPointXmlVOS()))
                .offSetList(addOffSetDetail(grooveXmlVO.getOffsetLineXmlVOS()))
                .mode(grooveXmlVO.getMode())
                .build();
    }

    /**
     * 造型轮廓数据
     *
     * @param grooveXmlVO
     * @param subIDs
     * @param isletXmlVOS
     * @return
     */
    private IOriginModelingData getOriginModelingData(GrooveXmlVO grooveXmlVO, String[] subIDs, IsletXmlVOS isletXmlVOS) {
        // 孤岛信息
        List<List<IContourData>> holes = null;
        if (subIDs != null && isletXmlVOS != null && isletXmlVOS.getIsletXmlVOList() != null) {
            holes = new ArrayList<>();
            // 孤岛信息整合
            Map<String, IsletXmlVO> isletMap = isletXmlVOS.getIsletXmlVOList().stream().collect(Collectors.toMap(IsletXmlVO::getId, Function.identity()));
            // 遍历subIDs
            for (String subID : subIDs) {
                // 获取孤岛信息
                List<IContourData> hole = getHole(subID, isletMap);
                holes.add(hole);
            }

        }
        return IOriginModelingData.builder()
                .knifeRadius(Double.parseDouble(grooveXmlVO.getToolDiameter()) / 2)
                .direction(grooveXmlVO.getDirection())
                .outline(addOutlineDetail(grooveXmlVO.getOutlineXmlVO()))
                .holes(holes)
                .addLen(Double.valueOf(grooveXmlVO.getLengthExtend()))
                .addDepth(Double.valueOf(grooveXmlVO.getDepthExtend()))
                .addWidth(Double.valueOf(grooveXmlVO.getWidthExtend()))
                .build();
    }

    /**
     * 孤岛信息
     *
     * @param subID
     * @param isletMap
     * @return
     */
    private List<IContourData> getHole(String subID, Map<String, IsletXmlVO> isletMap) {
        return isletMap.get(subID).getPointXmlVOS().getPointXmlVOList().stream().map(pointXmlVO -> IContourData.builder()
                .pts(new Point(Double.parseDouble(pointXmlVO.getPointX()), Double.parseDouble(pointXmlVO.getPointY()), Double.parseDouble(pointXmlVO.getPointZ())))
                .buls(Double.parseDouble(pointXmlVO.getCurvature())).radius(Double.parseDouble(pointXmlVO.getRadius())).build()).collect(Collectors.toList());
    }

    /**
     * 原始造型(外)轮廓信息
     *
     * @param outlineXmlVO
     * @return
     */
    private List<IContourData> addOutlineDetail(OutlineXmlVO outlineXmlVO) {
        if (outlineXmlVO == null || outlineXmlVO.getPointXmlVOList() == null) {
            return null;
        }
        return outlineXmlVO.getPointXmlVOList().stream().map(pointXmlVO -> IContourData.builder()
                .pts(new Point(Double.parseDouble(pointXmlVO.getPointX()), Double.parseDouble(pointXmlVO.getPointY()), Double.parseDouble(pointXmlVO.getPointZ())))
                .buls(Double.parseDouble(pointXmlVO.getCurvature()))
                .radius(Double.parseDouble(pointXmlVO.getRadius()))
                .build()).collect(Collectors.toList());
    }

    /**
     * 赋值点列表
     *
     * @param pointXmlVOS
     * @return
     */
    private List<PointList> addPointDetail(PointXmlVOS pointXmlVOS) {
        List<PointList> pointLists = new ArrayList<>();
        if (pointXmlVOS != null && pointXmlVOS.getPointXmlVOList() != null && !pointXmlVOS.getPointXmlVOList().isEmpty()) {
            for (PointXmlVO pointXmlVO : pointXmlVOS.getPointXmlVOList()) {
                pointLists.add(PointList.builder()
                        .pointX(Double.parseDouble(pointXmlVO.getPointX()))
                        .pointY(Double.parseDouble(pointXmlVO.getPointY()))
                        .pointZ(Double.parseDouble(pointXmlVO.getPointZ()))
                        .radius(Double.parseDouble(pointXmlVO.getRadius()))
                        .holeRadius(Double.parseDouble(pointXmlVO.getRadius()))
                        .build());
            }
        }
        return pointLists;
    }

    /**
     * 偏移量列表
     *
     * @param offsetLineXmlVOS
     * @return
     */
    private List<OffSetList> addOffSetDetail(OffsetLineXmlVOS offsetLineXmlVOS) {
        List<OffSetList> offSetList = new ArrayList<>();
        if (offsetLineXmlVOS != null && offsetLineXmlVOS.getOffsetLineXmlVOList() != null && offsetLineXmlVOS.getOffsetLineXmlVOList().size() > 0) {
            for (OffsetLineXmlVO offsetLineXmlVO : offsetLineXmlVOS.getOffsetLineXmlVOList()) {
                offSetList.add(OffSetList.builder()
                        .value(Double.parseDouble(offsetLineXmlVO.getOffset()))
                        .depth(Double.parseDouble(offsetLineXmlVO.getDepth()))
                        .angle(Double.parseDouble(offsetLineXmlVO.getTangentAngle()))
                        .name(offsetLineXmlVO.getToolName())
                        .radius(Double.parseDouble(offsetLineXmlVO.getToolDiameter()) / 2)
                        .build());
            }
        }
        return offSetList;
    }

    /**
     * 小板关联配件添加
     *
     * @param plateDetail
     * @param correlationXmlVOS
     */
    private void addParts(OrderModelDO plateDetail, CorrelationXmlVOS correlationXmlVOS) {
        List<PartsInfo> partsInfos = new ArrayList<>();
        if (correlationXmlVOS != null && correlationXmlVOS.getCorrelationXmlVOList() != null && correlationXmlVOS.getCorrelationXmlVOList().size() > 0) {
            for (CorrelationXmlVO correlationXmlVO : correlationXmlVOS.getCorrelationXmlVOList()) {
                String partCode;
                if (correlationXmlVO.getItemCode() == null) {
                    partCode = correlationXmlVO.getName() + correlationXmlVO.getColor() + correlationXmlVO.getMaterial() + correlationXmlVO.getSpecs()
                            + correlationXmlVO.getMaterial() + correlationXmlVO.getBrand() + correlationXmlVO.getType();
                } else {
                    partCode = correlationXmlVO.getItemCode();
                }
                // 获取配件信息
                OrderPartsDO orderPartsDO = orderPartsDOMap.get(partCode);
                // 板件上面添加配件信息
                if (ObjectUtil.isNotNull(orderPartsDO)) {
                    partsInfos.add(PartsInfo.builder()
                            .id(orderPartsDO.getId())
                            .name(orderPartsDO.getName())
                            .partNum(Double.valueOf(correlationXmlVO.getCount()))
                            .unit(orderPartsDO.getUnit())
                            .build());
                }
            }
            plateDetail.setPartsInfos(partsInfos);
        }
    }

    /**
     * 小板备注
     *
     * @param plateDO
     * @param plateDetail
     * @param blockXmlVO
     */
    private void addRemark(PlateDO plateDO, OrderModelDO plateDetail, BlockXmlVO blockXmlVO) {
        if (blockXmlVO.getRemarkXmlVOS() != null && blockXmlVO.getRemarkXmlVOS().getRemarkXmlVOList() != null
                && !blockXmlVO.getRemarkXmlVOS().getRemarkXmlVOList().isEmpty()) {
            for (RemarkXmlVO remarkXmlVO : blockXmlVO.getRemarkXmlVOS().getRemarkXmlVOList()) {
                plateDetail.getSideRemark().put(remarkXmlVO.getName(), remarkXmlVO.getInfo());
            }
            plateDO.setRemark(JSON.toJSONString(plateDetail.getSideRemark()));
        }
    }

    /**
     * 解析配件列表
     */
    private void analyzeParts() {
        // 查询配件itemCode分组
        OrderImportTempDataReqVO partItemCodeGroupReqVO = OrderImportTempDataReqVO.builder().taskId(taskId).build();
        List<OrderImportTempDataPartItemCodeGroupDO> partItemCodeGroupList = orderImportTempDataMapper.selectPartItemCodeGroup(partItemCodeGroupReqVO);
        for (OrderImportTempDataPartItemCodeGroupDO itemCodeGroupDO : partItemCodeGroupList) {
            int type = itemCodeGroupDO.getType();
            if (PART_EDGING_TYPE == type) {
                createEdging(itemCodeGroupDO);
            }
            if (PART_HARDWARE_TYPE == type) {
                createHardware(itemCodeGroupDO);
            }
            if (PART_ASSEMBLY_TYPE == type) {
                createAssembly(itemCodeGroupDO);
            }
        }
        // 最后批量插入一次，避免最后一页小于BATCH_THRESHOLD_NUMBER漏插入
        orderInfoBatchInsertWithinThreshold(orderPartsMapper, orderPartsDOS, true);
        orderInfoBatchInsertWithinThreshold(orderItemMapper, orderItemDOS, true);
        // 批量插入配件备注
        orderPartsRemarksBatchInsertWithinThreshold(true);
    }

    /**
     * 创建封边条配件
     *
     * @param itemCodeGroupDO
     */
    private void createEdging(OrderImportTempDataPartItemCodeGroupDO itemCodeGroupDO) {
        String itemCode = itemCodeGroupDO.getItemCode();
        // 查询itemcode所属edging
        OrderImportTempDataDO edgingTempData = orderImportTempDataMapper.selectOne(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, OrderImportTmpDataTypeEnum.PART_EDGING.getType())
                .eq(OrderImportTempDataDO::getOuterId, itemCode)
                .eq(OrderImportTempDataDO::getSort, itemCodeGroupDO.getSortn())
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        if (ObjectUtil.isNull(edgingTempData)) {
            return;
        }
        Long partId = (Long) snowFlakeGenerator.nextId(null);
        EdgingXmlVO edgingXmlVO = JSON.parseObject(JsonUtils.unzipString(edgingTempData.getDetail()), EdgingXmlVO.class);

        OrderPartsDO orderPartsDO = OrderPartsDO.builder()
                .id(partId)
                .orderId(orderId)
                .goodsId(edgingXmlVO.getItemCode())
                .name(edgingXmlVO.getName())
                .color(edgingXmlVO.getColor())
                .material(edgingXmlVO.getMaterial())
                .category("封边条")
                .type("封边条")
                .width(Double.valueOf(edgingXmlVO.getWidth()))
                .length(Double.valueOf(edgingXmlVO.getLength()))
                .thickness(Double.valueOf(edgingXmlVO.getThickness()))
                .brand(edgingXmlVO.getBrand())
                .factory(edgingXmlVO.getManufacturer())
                .spec(edgingXmlVO.getSpecs())
                .unit(edgingXmlVO.getUnit())
                .isComposite(false)
                .subparts(EMPTY_STRING)
                .remark(EMPTY_STRING)
                .model(EMPTY_STRING)
                .subparts(EMPTY_STRING)
                .price(0.0)
                .deleted(false)
                .organId(organId)
                .build();
        orderPartsDO.setCreator(operatorName);
        orderPartsDO.setUpdater(operatorName);
        LocalDateTime now = LocalDateTime.now();
        orderPartsDO.setCreateTime(now);
        orderPartsDO.setUpdateTime(now);

        // 查询itemCode下的房间、柜体、加工组分组和数量
        OrderImportTempDataReqVO partItemCodeGroupReqVO = OrderImportTempDataReqVO.builder().taskId(taskId).type(OrderImportTmpDataTypeEnum.PART_EDGING.getType()).outerId(itemCode).build();
        List<OrderImportTempDataPartRoomBodyGroupGroupDO> partRoomBodyGroupGroupDOS = orderImportTempDataMapper.selectPartRoomBodyGroupGroup(partItemCodeGroupReqVO);
        for (OrderImportTempDataPartRoomBodyGroupGroupDO partRoomBodyGroupGroupDO : partRoomBodyGroupGroupDOS) {
            // 获取房间柜体缓存
            String roomCode = edgingXmlVO.getRoomCode();
            String bodyCode = edgingXmlVO.getBoxCode();

            Map<String, OrderImportTempDataDO> roomTempDataMap = roomBodyMap.get(roomCode);
            OrderImportTempDataDO roomBodyTempDataDO = null;
            if (MapUtil.isNotEmpty(roomTempDataMap)) {
                roomBodyTempDataDO = roomTempDataMap.get(bodyCode);
            }

            // 获取加工组缓存
            String groupCode = partRoomBodyGroupGroupDO.getGroupCode();
            OrderImportTempDataDO groupTempDataDO = groupMap.get(groupCode);
            // 柜体id回显到加工组
            if (ObjectUtil.isNotNull(groupTempDataDO) && ObjectUtil.isNull(groupTempDataDO.getInnerBodyId()) && ObjectUtil.isNotNull(roomBodyTempDataDO)) {
                groupTempDataDO.setInnerBodyId(roomBodyTempDataDO.getInnerBodyId());
            }

            OrderItemDO orderItemDO = OrderItemDO.builder()
                    .id((Long) snowFlakeGenerator.nextId(null))
                    .organId(organId)
                    .orderId(orderId)
                    .type(OrderItemTypeEnum.PARTS_ITEM.getStatus())
                    .partsId(partId)
                    .groupId(ObjectUtil.isNotNull(groupTempDataDO) ? groupTempDataDO.getInnerGroupId() : 0L)
                    .roomId(roomBodyTempDataDO.getInnerRoomId())
                    .bodyId(roomBodyTempDataDO.getInnerBodyId())
                    .num(NumberUtil.toDouble(partRoomBodyGroupGroupDO.getPartsNum()))
                    .packageId(0L)
                    .plateId(0L)
                    .build();
            // 批量插入order_item
            orderItemDOS.add(orderItemDO);
            orderInfoBatchInsertWithinThreshold(orderItemMapper, orderItemDOS, false);
        }

        // 查询配件备注
        List<OrderImportTempDataDO> partRemarkTempDataList = orderImportTempDataMapper.selectList(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, OrderImportTmpDataTypeEnum.PART_REMARK.getType())
                .eq(OrderImportTempDataDO::getOuterSubId, edgingXmlVO.getItemCode())
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        List<RemarkXmlVO> partRemarkXmlVOList = new ArrayList<>();
        for (OrderImportTempDataDO partRemarkXmlTempData : partRemarkTempDataList) {
            String partRemarkDetail = partRemarkXmlTempData.getDetail();
            if (StringUtils.isNotEmpty(partRemarkDetail)) {
                partRemarkXmlVOList.add(JSON.parseObject(JsonUtils.unzipString(partRemarkDetail), RemarkXmlVO.class));
            }
        }
        // 记录备注到order_parts
        String partRemark = getRemark(partRemarkXmlVOList);
        orderPartsDO.setRemark(partRemark);

        // 解析配件商品
//        analyzePartsGoods(orderPartsDO);
        // 批量插入orderParts
        orderPartsDOS.add(orderPartsDO);
        // 缓存配件
        orderPartsDOMap.put(itemCode, orderPartsDO);
        orderInfoBatchInsertWithinThreshold(orderPartsMapper, orderPartsDOS, false);
        // 批量插入配件备注
        orderPartsRemarks.add(OrderPartsRemark.builder()
                .partsId(partId)
                .batchId(batchId)
                .orderId(orderId)
                .remark(partRemarkXmlVOList.toString())
                .build());
        orderPartsRemarksBatchInsertWithinThreshold(false);
    }

    /**
     * 创建五金配件
     *
     * @param itemCodeGroupDO
     */
    private void createHardware(OrderImportTempDataPartItemCodeGroupDO itemCodeGroupDO) {
        String itemCode = itemCodeGroupDO.getItemCode();
        // 查询itemcode所属edging
        OrderImportTempDataDO hardwareTempData = orderImportTempDataMapper.selectOne(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, OrderImportTmpDataTypeEnum.PART_HARDWARE.getType())
                .eq(OrderImportTempDataDO::getOuterId, itemCode)
                .eq(OrderImportTempDataDO::getSort, itemCodeGroupDO.getSortn())
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        if (ObjectUtil.isNull(hardwareTempData)) {
            return;
        }

        Long partId = (Long) snowFlakeGenerator.nextId(null);
        HardwareXmlVO hardwareXmlVO = JSON.parseObject(JsonUtils.unzipString(hardwareTempData.getDetail()), HardwareXmlVO.class);
        OrderPartsDO orderPartsDO = OrderPartsDO.builder()
                .id(partId)
                .orderId(orderId)
                .goodsId(hardwareXmlVO.getItemCode())
                .name(hardwareXmlVO.getName())
                .color(hardwareXmlVO.getColor())
                .material(hardwareXmlVO.getMaterial())
                .category("五金")
                .type(hardwareXmlVO.getType())
                .width(Double.valueOf(hardwareXmlVO.getWidth()))
                .length(Double.valueOf(hardwareXmlVO.getLength()))
                .thickness(Double.valueOf(hardwareXmlVO.getThickness()))
                .brand(hardwareXmlVO.getBrand())
                .factory(hardwareXmlVO.getManufacturer())
                .spec(hardwareXmlVO.getSpecs())
                .unit(hardwareXmlVO.getUnit())
                .isComposite(false)
                .subparts(hardwareXmlVO.getSubCodes())
                .remark(EMPTY_STRING)
                .model(EMPTY_STRING)
                .subparts(EMPTY_STRING)
                .price(0.0)
                .deleted(false)
                .organId(organId)
                .build();
        orderPartsDO.setCreator(operatorName);
        orderPartsDO.setUpdater(operatorName);
        LocalDateTime now = LocalDateTime.now();
        orderPartsDO.setCreateTime(now);
        orderPartsDO.setUpdateTime(now);

        // 查询itemCode下的房间、柜体、加工组分组和数量
        OrderImportTempDataReqVO partItemCodeGroupReqVO = OrderImportTempDataReqVO.builder().taskId(taskId).type(OrderImportTmpDataTypeEnum.PART_HARDWARE.getType()).outerId(itemCode).build();
        List<OrderImportTempDataPartRoomBodyGroupGroupDO> partRoomBodyGroupGroupDOS = orderImportTempDataMapper.selectPartRoomBodyGroupGroup(partItemCodeGroupReqVO);
        for (OrderImportTempDataPartRoomBodyGroupGroupDO partRoomBodyGroupGroupDO : partRoomBodyGroupGroupDOS) {
            // 获取房间柜体缓存
            String roomCode = hardwareXmlVO.getRoomCode();
            String bodyCode = hardwareXmlVO.getBoxCode();

            Map<String, OrderImportTempDataDO> roomTempDataMap = roomBodyMap.get(roomCode);
            OrderImportTempDataDO roomBodyTempDataDO = null;
            if (MapUtil.isNotEmpty(roomTempDataMap)) {
                roomBodyTempDataDO = roomTempDataMap.get(bodyCode);
            }

            // 获取加工组缓存
            String groupCode = partRoomBodyGroupGroupDO.getGroupCode();
            OrderImportTempDataDO groupTempDataDO = groupMap.get(groupCode);
            // 柜体id回显到加工组
            if (ObjectUtil.isNotNull(groupTempDataDO) && ObjectUtil.isNull(groupTempDataDO.getInnerBodyId()) && ObjectUtil.isNotNull(roomBodyTempDataDO)) {
                groupTempDataDO.setInnerBodyId(roomBodyTempDataDO.getInnerBodyId());
            }

            OrderItemDO orderItemDO = OrderItemDO.builder()
                    .id((Long) snowFlakeGenerator.nextId(null))
                    .organId(organId)
                    .orderId(orderId)
                    .type(OrderItemTypeEnum.PARTS_ITEM.getStatus())
                    .partsId(partId)
                    .groupId(ObjectUtil.isNotNull(groupTempDataDO) ? groupTempDataDO.getInnerGroupId() : 0L)
                    .roomId(roomBodyTempDataDO.getInnerRoomId())
                    .bodyId(roomBodyTempDataDO.getInnerBodyId())
                    .num(NumberUtil.toDouble(partRoomBodyGroupGroupDO.getPartsNum()))
                    .packageId(0L)
                    .plateId(0L)
                    .build();
            // 批量插入order_item
            orderItemDOS.add(orderItemDO);
            orderInfoBatchInsertWithinThreshold(orderItemMapper, orderItemDOS, false);
        }

        // 查询配件备注
        List<OrderImportTempDataDO> partRemarkTempDataList = orderImportTempDataMapper.selectList(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, OrderImportTmpDataTypeEnum.PART_REMARK.getType())
                .eq(OrderImportTempDataDO::getOuterSubId, itemCode)
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        List<RemarkXmlVO> partRemarkXmlVOList = new ArrayList<>();
        for (OrderImportTempDataDO partRemarkXmlTempData : partRemarkTempDataList) {
            String partRemarkDetail = partRemarkXmlTempData.getDetail();
            if (StringUtils.isNotEmpty(partRemarkDetail)) {
                partRemarkXmlVOList.add(JSON.parseObject(JsonUtils.unzipString(partRemarkDetail), RemarkXmlVO.class));
            }
        }
        // 记录备注到order_parts
        String partRemark = getRemark(partRemarkXmlVOList);
        orderPartsDO.setRemark(partRemark);

        // 解析配件商品
//        analyzePartsGoods(orderPartsDO);
        // 批量插入orderParts
        orderPartsDOS.add(orderPartsDO);
        // 缓存配件
        orderPartsDOMap.put(itemCode, orderPartsDO);
        orderInfoBatchInsertWithinThreshold(orderPartsMapper, orderPartsDOS, false);
        // 批量插入配件备注
        orderPartsRemarks.add(OrderPartsRemark.builder()
                .partsId(partId)
                .orderId(orderId)
                .remark(partRemarkXmlVOList.toString())
                .build());
        orderPartsRemarksBatchInsertWithinThreshold(false);
    }

    /**
     * 创建组件配件
     *
     * @param itemCodeGroupDO
     */
    private void createAssembly(OrderImportTempDataPartItemCodeGroupDO itemCodeGroupDO) {
        String itemCode = itemCodeGroupDO.getItemCode();
        // 查询itemcode所属edging
        OrderImportTempDataDO assemblyTempData = orderImportTempDataMapper.selectOne(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, OrderImportTmpDataTypeEnum.PART_HARDWARE.getType())
                .eq(OrderImportTempDataDO::getOuterId, itemCode)
                .eq(OrderImportTempDataDO::getSort, itemCodeGroupDO.getSortn())
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        if (ObjectUtil.isNull(assemblyTempData)) {
            return;
        }
        Long partId = (Long) snowFlakeGenerator.nextId(null);
        AssemblyXmlVO assemblyXmlVO = JSON.parseObject(JsonUtils.unzipString(assemblyTempData.getDetail()), AssemblyXmlVO.class);
        OrderPartsDO orderPartsDO = OrderPartsDO.builder()
                .id(partId)
                .orderId(orderId)
                .goodsId(assemblyXmlVO.getItemCode())
                .name(assemblyXmlVO.getName())
                .color(assemblyXmlVO.getColor())
                .material(assemblyXmlVO.getMaterial())
                .category("组件")
                .type(assemblyXmlVO.getType())
                .width(Double.valueOf(assemblyXmlVO.getWidth()))
                .length(Double.valueOf(assemblyXmlVO.getLength()))
                .thickness(Double.valueOf(assemblyXmlVO.getHeight()))
                .brand(assemblyXmlVO.getBrand())
                .factory(assemblyXmlVO.getManufacturer())
                .spec(assemblyXmlVO.getSpecs())
                .unit(assemblyXmlVO.getUnit())
                .isComposite(true)
                .subparts(assemblyXmlVO.getSubCodes())
                .remark(EMPTY_STRING)
                .model(EMPTY_STRING)
                .subparts(EMPTY_STRING)
                .price(0.0)
                .deleted(false)
                .organId(organId)
                .build();
        orderPartsDO.setCreator(operatorName);
        orderPartsDO.setUpdater(operatorName);
        LocalDateTime now = LocalDateTime.now();
        orderPartsDO.setCreateTime(now);
        orderPartsDO.setUpdateTime(now);

        // 查询itemCode下的房间、柜体、加工组分组和数量
        OrderImportTempDataReqVO partItemCodeGroupReqVO = OrderImportTempDataReqVO.builder().taskId(taskId).type(OrderImportTmpDataTypeEnum.PART_ASSEMBLY.getType()).outerId(itemCode).build();
        List<OrderImportTempDataPartRoomBodyGroupGroupDO> partRoomBodyGroupGroupDOS = orderImportTempDataMapper.selectPartRoomBodyGroupGroup(partItemCodeGroupReqVO);
        for (OrderImportTempDataPartRoomBodyGroupGroupDO partRoomBodyGroupGroupDO : partRoomBodyGroupGroupDOS) {
            // 获取房间柜体缓存
            String roomCode = assemblyXmlVO.getRoomCode();
            String bodyCode = assemblyXmlVO.getBoxCode();

            Map<String, OrderImportTempDataDO> roomTempDataMap = roomBodyMap.get(roomCode);
            OrderImportTempDataDO roomBodyTempDataDO = null;
            if (MapUtil.isNotEmpty(roomTempDataMap)) {
                roomBodyTempDataDO = roomTempDataMap.get(bodyCode);
            }

            // 获取加工组缓存
            String groupCode = partRoomBodyGroupGroupDO.getGroupCode();
            OrderImportTempDataDO groupTempDataDO = groupMap.get(groupCode);
            // 柜体id回显到加工组
            if (ObjectUtil.isNotNull(groupTempDataDO) && ObjectUtil.isNull(groupTempDataDO.getInnerBodyId()) && ObjectUtil.isNotNull(roomBodyTempDataDO)) {
                groupTempDataDO.setInnerBodyId(roomBodyTempDataDO.getInnerBodyId());
            }

            OrderItemDO orderItemDO = OrderItemDO.builder()
                    .id((Long) snowFlakeGenerator.nextId(null))
                    .organId(organId)
                    .orderId(orderId)
                    .type(OrderItemTypeEnum.PARTS_ITEM.getStatus())
                    .partsId(partId)
                    .groupId(ObjectUtil.isNotNull(groupTempDataDO) ? groupTempDataDO.getInnerGroupId() : 0L)
                    .roomId(roomBodyTempDataDO.getInnerRoomId())
                    .bodyId(roomBodyTempDataDO.getInnerBodyId())
                    .num(NumberUtil.toDouble(partRoomBodyGroupGroupDO.getPartsNum()))
                    .packageId(0L)
                    .plateId(0L)
                    .build();
            // 批量插入order_item
            orderItemDOS.add(orderItemDO);
            orderInfoBatchInsertWithinThreshold(orderItemMapper, orderItemDOS, false);
        }

        // 查询配件备注
        List<OrderImportTempDataDO> partRemarkTempDataList = orderImportTempDataMapper.selectList(new LambdaQueryWrapper<OrderImportTempDataDO>()
                .eq(OrderImportTempDataDO::getTaskId, taskId)
                .eq(OrderImportTempDataDO::getType, OrderImportTmpDataTypeEnum.PART_REMARK.getType())
                .eq(OrderImportTempDataDO::getOuterSubId, itemCode)
                .eq(OrderImportTempDataDO::getOrganId, organId)
        );
        List<RemarkXmlVO> partRemarkXmlVOList = new ArrayList<>();
        for (OrderImportTempDataDO partRemarkXmlTempData : partRemarkTempDataList) {
            String partRemarkDetail = partRemarkXmlTempData.getDetail();
            if (StringUtils.isNotEmpty(partRemarkDetail)) {
                partRemarkXmlVOList.add(JSON.parseObject(JsonUtils.unzipString(partRemarkDetail), RemarkXmlVO.class));
            }
        }
        // 记录备注到order_parts
        String partRemark = getRemark(partRemarkXmlVOList);
        orderPartsDO.setRemark(partRemark);

        // 解析配件商品
//        analyzePartsGoods(orderPartsDO);
        // 批量插入orderParts
        orderPartsDOS.add(orderPartsDO);
        // 缓存配件
        orderPartsDOMap.put(itemCode, orderPartsDO);
        orderInfoBatchInsertWithinThreshold(orderPartsMapper, orderPartsDOS, false);
        // 批量插入配件备注
        orderPartsRemarks.add(OrderPartsRemark.builder()
                .partsId(partId)
                .batchId(batchId)
                .orderId(orderId)
                .remark(partRemarkXmlVOList.toString())
                .build());
        orderPartsRemarksBatchInsertWithinThreshold(false);
    }

    private void writeBackToOrders() {
        // 回显柜体id到加工组
        for (Map.Entry<String, OrderImportTempDataDO> groupEntry : groupMap.entrySet()) {
            OrderImportTempDataDO groupTempData = groupEntry.getValue();
            Long innerBodyId = groupTempData.getInnerBodyId();
            if (ObjectUtils.isNotNull(innerBodyId)) {
                orderGroupMapper.update(new LambdaUpdateWrapper<OrderGroupDO>()
                        .eq(OrderGroupDO::getId, groupTempData.getInnerGroupId())
                        .eq(OrderGroupDO::getOrganId, organId)
                        .set(OrderGroupDO::getBodyId, innerBodyId)
                        .set(OrderGroupDO::getGroupTypeId, innerBodyId)
                );
            }
        }
        // 回显板件数、异形数到柜体
        for (Map.Entry<String, Map<String, OrderImportTempDataDO>> bodyEntry : roomBodyMap.entrySet()) {
            Map<String, OrderImportTempDataDO> bodyTempDataMap = bodyEntry.getValue();
            for (Map.Entry<String, OrderImportTempDataDO> bodyTempDataEntry : bodyTempDataMap.entrySet()) {
                OrderImportTempDataDO bodyTempData = bodyTempDataEntry.getValue();
                int plateNum = bodyTempData.getPlateNum();
                int unregularNum = bodyTempData.getUnregularNum();
                if (plateNum > 0 || unregularNum > 0) {
                    orderBodyMapper.update(new LambdaUpdateWrapper<OrderBodyDO>()
                            .eq(OrderBodyDO::getId, bodyTempData.getInnerBodyId())
                            .eq(OrderBodyDO::getOrganId, organId)
                            .set(OrderBodyDO::getPlateNum, plateNum + unregularNum)
                            .set(OrderBodyDO::getUnregularNum, unregularNum)
                    );
                }
            }
        }
    }

    /**
     * 创建生产单柜体orderBody
     *
     * @param groupDO
     * @return
     */
    private OrderBodyDO createOrderBodyDO(OrderImportTempDataDO groupDO) {
        Long innerRoomId = groupDO.getInnerRoomId();
        Long bodyId = (Long) snowFlakeGenerator.nextId(null);
        Long roomId = (Long) snowFlakeGenerator.nextId(null);
        String detail = groupDO.getDetail();
        RoomBoxXmlVO roomBoxXmlVO = new RoomBoxXmlVO();
        if (StringUtils.isNotEmpty(detail)) {
            roomBoxXmlVO = JSON.parseObject(JsonUtils.unzipString(detail), RoomBoxXmlVO.class);
            groupDO.setRoomPosition(BasePosition.builder()
                    .basePoint(String.valueOf(roomId))
                    .basePointX(Double.valueOf(roomBoxXmlVO.getRoomBasePointX()))
                    .basePointY(Double.valueOf(roomBoxXmlVO.getRoomBasePointY()))
                    .basePointZ(Double.valueOf(roomBoxXmlVO.getRoomBasePointZ()))
                    .axisXrotate(Double.valueOf(roomBoxXmlVO.getRoomAxisXrotate()))
                    .axisYrotate(Double.valueOf(roomBoxXmlVO.getRoomAxisYrotate()))
                    .axisZrotate(Double.valueOf(roomBoxXmlVO.getRoomAxisZrotate()))
                    .build());

            groupDO.setBodyPosition(BasePosition.builder()
                    .basePoint(String.valueOf(bodyId))
                    .basePointX(Double.valueOf(roomBoxXmlVO.getBasePointX()))
                    .basePointY(Double.valueOf(roomBoxXmlVO.getBasePointY()))
                    .basePointZ(Double.valueOf(roomBoxXmlVO.getBasePointZ()))
                    .axisXrotate(Double.valueOf(roomBoxXmlVO.getAxisXrotate()))
                    .axisYrotate(Double.valueOf(roomBoxXmlVO.getAxisYrotate()))
                    .axisZrotate(Double.valueOf(roomBoxXmlVO.getAxisZrotate()))
                    .build());
        }
        OrderBodyDO orderBodyDO = OrderBodyDO.builder()
                .id(bodyId)
                .orderId(orderId)
                .roomId(ObjectUtil.isNotNull(innerRoomId) ? innerRoomId : roomId)
                .roomName(groupDO.getRoomName())
                .name(groupDO.getBodyName())
                .width(NumberUtil.parseDouble(roomBoxXmlVO.getWidth()))
                .height(NumberUtil.parseDouble(roomBoxXmlVO.getHeight()))
                .depth(NumberUtil.parseDouble(roomBoxXmlVO.getLength()))
                .multiNum(0)
                .unregularNum(0)
                .filename("无")
                .remark("无")
                .organId(organId)
                .plateNum(0)
                .deleted(false)
                .build();
        orderBodyDO.setCreator(operatorName);
        orderBodyDO.setUpdater(operatorName);
        LocalDateTime now = LocalDateTime.now();
        orderBodyDO.setCreateTime(now);
        orderBodyDO.setUpdateTime(now);
        return orderBodyDO;
    }

    /**
     * 创建生产单加工组orderGroup
     *
     * @param groupDO
     * @return
     */
    private OrderGroupDO createOrderGroupDO(OrderImportTempDataDO groupDO) {
        String detail = groupDO.getDetail();
        GroupXmlVO groupXmlVO = new GroupXmlVO();
        if (StringUtils.isNotEmpty(detail)) {
            groupXmlVO = JSON.parseObject(JsonUtils.unzipString(detail), GroupXmlVO.class);
        }
        OrderGroupDO orderGroupDO = OrderGroupDO.builder()
                .id((Long) snowFlakeGenerator.nextId(null))
                .orderId(orderId)
                .organId(organId)
                .bodyId(0L)
                .groupTypeId(0L)
                .groupTypeName(NOT_ASSIGNED)
                .name(groupDO.getGroupName())
                .width(NumberUtil.parseDouble(groupXmlVO.getWidth()))
                .height(NumberUtil.parseDouble(groupXmlVO.getHeight()))
                .depth(NumberUtil.parseDouble(groupXmlVO.getLength()))
                .multiNum(0)
                .plateNum(0)
                .unregularNum(0)
                .filename("无")
                .remark("无")
                .deleted(false)
                .build();
        orderGroupDO.setCreator(operatorName);
        orderGroupDO.setUpdater(operatorName);
        LocalDateTime now = LocalDateTime.now();
        orderGroupDO.setCreateTime(now);
        orderGroupDO.setUpdateTime(now);
        return orderGroupDO;
    }

    /**
     * 每达到阈值就批量插入一次
     *
     * @param baseBatchMapper
     * @param list
     * @param isLast          是否最后一次插入，不是就需要清理list
     */
    private void orderInfoBatchInsertWithinThreshold(BaseBatchMapper baseBatchMapper, List list, boolean isLast) {
        // 达到批量的阈值就做一次插入
        if (CollUtil.isNotEmpty(list) && (list.size() >= BATCH_THRESHOLD_NUMBER || isLast)) {
            baseBatchMapper.insertBatchSomeColumn(list);
            if (!isLast) {
                // 存储完成清理 list
                list.clear();
            }
        }
    }

    /**
     * 每达到阈值就批量插入一次生产单造型数据和压缩数据
     *
     * @param isLast 是否最后一次插入，不是就需要清理list
     */
    private void orderModelsBatchInsertWithinThreshold(boolean isLast) {
        // 达到批量的阈值就做一次插入
        if (CollUtil.isNotEmpty(orderModelDOS) && (orderModelDOS.size() >= BATCH_THRESHOLD_NUMBER || isLast)) {
            // 保存生产单造型数据
            orderInputProcessor.batchSaveModel(orderModelDOS);
            if (!isLast) {
                // 存储完成清理 list
                orderModelDOS.clear();
            }
        }
    }

    /**
     * 每达到阈值就批量插入一次生产单造型数据和压缩数据
     *
     * @param isLast 是否最后一次插入，不是就需要清理list
     */
    private void orderPartsRemarksBatchInsertWithinThreshold(boolean isLast) {
        // 达到批量的阈值就做一次插入
        if (CollUtil.isNotEmpty(orderPartsRemarks) && (orderPartsRemarks.size() >= BATCH_THRESHOLD_NUMBER || isLast)) {
            orderInputProcessor.batchSaveOrderPartsModel(orderPartsRemarks);
            if (!isLast) {
                // 存储完成清理 list
                orderPartsRemarks = ListUtils.newArrayListWithExpectedSize(BATCH_THRESHOLD_NUMBER);
            }
        }
    }

    /**
     * 长度面积数值按单位转换
     *
     * @param lengthStr
     * @param unit
     * @param type
     * @return
     */
    public Double changeUnit(String lengthStr, String unit, String type) {
        String dictData = DictFrameworkUtils.parseDictDataValue(type, unit);
        Double length = Double.parseDouble(lengthStr);
        return length * Double.parseDouble(dictData);
    }

    /**
     * 是否转换布尔值
     *
     * @param str
     * @return
     */
    public Boolean convertToBoolean(String str) {
        Boolean isTrue;
        switch (str) {
            case "是":
                isTrue = true;
                break;
            default:
                isTrue = false;
                break;
        }
        return isTrue;
    }

    /**
     * 备注信息提取，判断长度是否超过255，超过255则截取255，并保存在备注中
     *
     * @param finalRemarkXmlVOS
     * @return
     */
    private String getRemark(List<RemarkXmlVO> finalRemarkXmlVOS) {
        StringBuilder sb = new StringBuilder();
        for (RemarkXmlVO remarkXmlVO : finalRemarkXmlVOS) {
            String info = remarkXmlVO.getInfo();
            if (info.length() > 255) {
                info = info.substring(0, 255);
            }
            sb.append(info);
        }
        return sb.toString();
    }

    /**
     * 查询大板信息
     *
     * @param goodsId
     * @return
     */
    private PlateGoodDO getPlateGood(String goodsId) {
        List<PlateGoodDO> plateGoodDOs = plateGoodMapper.selectGoodOne(goodsId, organId);
        if (!plateGoodDOs.isEmpty()) {
            return plateGoodDOs.get(0);
        }
        return null;
    }

    /**
     * 解析配件
     * 配件库没有新增，有就赋值goodsId
     *
     * @param partsDO
     * @return
     */
//    private void analyzePartsGoods(OrderPartsDO partsDO) {
//        if (partsDO.getGoodsId() != null && !partsDO.getGoodsId().isEmpty()) { // 有goodsId
//            PartsDO parts = partsMapper.selectByGoodID(partsDO.getGoodsId(), OrganContextHolder.getOrganId());
//            if (ObjectUtil.isNull(parts)) { // 不存在记录，存入数据库
//                // 批量插入parts
//                partsDOS.add(BeanUtils.toBean(partsDO, PartsDO.class).setOrganId(organId));
//                orderInfoBatchInsertWithinThreshold(partsMapper, partsDOS, false);
//            }
//        }
//    }

    /**
     * 清空所有列表
     */
    private void clearAll() {
        rawGoodsDOS.clear();
        goodsDOS.clear();
        orderPartsDOS.clear();
        orderBodyDOS.clear();
        orderGroupDOS.clear();
        plateDOS.clear();
        orderItemDOS.clear();
        plateGoodDOS.clear();
        orderModelDOS.clear();
        orderPartsRemarks.clear();
//        partsDOS.clear();
    }

    /**
     * 移除taskId下所有临时数据
     */
    private void deleteTempData() {
        orderImportTempDataMapper.delete(new LambdaQueryWrapper<OrderImportTempDataDO>().eq(OrderImportTempDataDO::getTaskId, taskId));
    }

    /**
     * 更新为导入成功
     */
    private void updateTaskSuccess() {
        orderImportTaskMapper.update(new LambdaUpdateWrapper<OrderImportTaskDO>().eq(OrderImportTaskDO::getId, taskId).set(OrderImportTaskDO::getImportStatus, OrderImportStatusEnum.IMPORT_SUCCESS.getStatus()));
    }
}
