package com.cf.imes.module.executor.util.fileConversion.admin.files.excel;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.mybatis.core.generator.SnowFlakeGenerator;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.web.core.util.WebFrameworkUtils;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.dal.dataobject.orderImport.OrderImportTempDataDO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateGoodDO;
import com.cf.imes.module.executor.dal.mysql.orderImport.OrderImportTempDataMapper;
import com.cf.imes.module.executor.dal.mysql.plate.PlateGoodMapper;
import com.cf.imes.module.executor.enums.CategoryEnum;
import com.cf.imes.module.executor.enums.DataTypeEnum;
import com.cf.imes.module.executor.enums.DictTypeConstants;
import com.cf.imes.module.executor.enums.IsHavaeEnum;
import com.cf.imes.module.executor.enums.OrderImportConstants;
import com.cf.imes.module.executor.enums.OrderImportTmpDataTypeEnum;
import com.cf.imes.module.executor.enums.OrderStatusEnum;
import com.cf.imes.module.executor.enums.QuarrelEnum;
import com.cf.imes.module.executor.service.order.OrderService;
import com.cf.imes.module.executor.util.fileConversion.admin.ToolUtil;
import com.cf.imes.module.system.api.dict.DictDataApi;
import com.cf.imes.module.system.api.dict.dto.DictDataRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_IMPORT_DETAIL_VALID_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_IMPORT_ORDER_CUSTOMERNO_EXISTS;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_IMPORT_ORDER_FIELD_DATE_FORMAT_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_IMPORT_ORDER_FIELD_EMPTY;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_IMPORT_ORDER_FIELD_LENGTH_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_IMPORT_ORDER_FIELD_MOBILE_FORMAT_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_IMPORT_PLATEGOODS_NOT_EXIST_VALID_ERROR;

/**
 * 默认订单excel导入监听器
 *
 * @author Gqr
 * @since 2025/1/9 11:14
 */
@Slf4j
public final class DefaultOrderImportExcelListener extends AnalysisEventListener<Map<Integer, String>> {
    /**
     * 每500条操作入库一次
     */
    private static final int BATCH_COUNT = 500;
    private List<OrderImportTempDataDO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    /**
     * 存放订单orders信息
     */
    private OrderDO orderDO = OrderDO.builder().build();

    /**
     * 停止解析标志
     */
    private boolean stopParsing = false;

    private OrderImportTempDataMapper orderImportTempDataMapper;

    private OrderService orderService;

    private DictDataApi dictDataApi;

    private SnowFlakeGenerator snowFlakeGenerator;

    private PlateGoodMapper plateGoodMapper;

    /**
     * 补板用
     */
    private Long orderId;

    /**
     * 是否补板
     */
    boolean addToExistsOrder;

    /**
     * 导入任务id
     */
    private Long taskId;

    private int sort = 1;

    /**
     * 行号
     */
    private int rowIndex;

    private static final String NUMBER_TYPE_ERR = "数量类型错误";
    private static final String NOT_EMPTY = "不可为空";
    private static final String ACCORD_ENUM = "请按照提示词语选择填入";
    private static final String POSITIVE_ERR = "数据需为正数";
    private static final String NUMBER_LENGTH_ERR = "数据长度过长";

    private static final String EMPTY_STRING = new String();


    public DefaultOrderImportExcelListener(OrderImportTempDataMapper orderImportTempDataMapper, OrderService orderService, DictDataApi dictDataApi, SnowFlakeGenerator snowFlakeGenerator, PlateGoodMapper plateGoodMapper, Long orderId, Long taskId) {
        this.orderImportTempDataMapper = orderImportTempDataMapper;
        this.orderService = orderService;
        this.dictDataApi = dictDataApi;
        this.snowFlakeGenerator = snowFlakeGenerator;
        this.plateGoodMapper = plateGoodMapper;
        this.orderId = orderId;
        this.taskId = taskId;
        // 是否补板
        addToExistsOrder = ObjectUtil.isNotNull(orderId);
    }

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        log.info("解析到一条数据: {}", JSON.toJSONString(data));

        // 获取行号
        ReadRowHolder readRowHolder = context.readRowHolder();
        rowIndex = readRowHolder.getRowIndex();

        // 订单信息在1-5行间
        boolean isOrderInfo = (rowIndex >= 0 && rowIndex <= 4);
        // 板材/配件数据从第8行开始
        boolean isPlate = rowIndex > 6;

        // 标记结束，后续数据不再记录
        if (data.get(0) != null && data.get(0).equals("***")) {
            log.info("解析到结束标记 ***, 停止写入！");
            stopParsing = true;
        }

        // 缓存订单数据
        // 补板的时候不更新订单数据也就不缓存excel上的基础信息
        if (!stopParsing && isOrderInfo && !addToExistsOrder) {
            // 校验订单数据
            validOrderInfo(data, rowIndex);
        }

        // 缓存板材/配件数据
        if (!stopParsing && isPlate) {
            data.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
            cachedDataList.add(checkData(setOrderPlateProperty(data)));
        }
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        saveData();
        // 保存订单数据
        saveOrderTempData();
        log.info("所有数据解析完成！");
    }

    /**
     * 板材数据保存临时表
     */
    private void saveData() {
        log.info("{}条数据，开始保存临时板材数据！", cachedDataList.size());
        orderImportTempDataMapper.insertBatchSomeColumn(cachedDataList);
        log.info("excel导入临时板材数据保存成功！");
    }

    /**
     * 订单数据保存临时表
     */
    private void saveOrderTempData() {
        OrderImportTempDataDO orderInfoTempDataDO = OrderImportTempDataDO.builder()
                .id((Long) snowFlakeGenerator.nextId(null))
                .orderId(orderId)
                .taskId(taskId)
                .type(OrderImportTmpDataTypeEnum.ORDER.getType())
                .createTime(LocalDateTime.now())
                .sort(0)
                .build();
        // 非补板即新增生成单，记录基础信息
        if (!addToExistsOrder) {
            orderDO.setId(orderId);
            orderDO.setStatus(NumberUtil.compare(sort, 1) > 0 ? OrderStatusEnum.NEW_ORDER.getStatus() : OrderStatusEnum.EMPTY.getStatus());
            orderInfoTempDataDO.setDetail(JsonUtils.zipString(JSON.toJSONString(orderDO)));
        }
        orderImportTempDataMapper.insert(orderInfoTempDataDO);
        log.info("excel导入临时订单数据保存成功！");
    }


    /**
     * 订单信息校验
     *
     * @param data     行数据
     * @param rowIndex 行号
     */
    public void validOrderInfo(Map<Integer, String> data, Integer rowIndex) {
        // 左key
        String leftKey = data.get(0);
        // 左值
        String leftVal = data.get(1);
        // 右key
        String rightKey = data.get(19);
        // 右值
        String rightVal = data.get(20);
        // 左：自定义单号（非必填）、右：客户
        if (0 == rowIndex) {
            validOrderInfoLength(leftKey, leftVal, 32);
            validCustomOrderNo(leftKey, leftVal);
            validOrderInfoEmpty(rightKey, rightVal);
            validOrderInfoLength(rightKey, rightVal, 255);
            orderDO.setCustomOrderNo(leftVal);
            orderDO.setCustomer(rightVal);
        }
        // 左：经销商、右：客户地址
        if (1 == rowIndex) {
            validOrderInfoEmpty(rightKey, rightVal);
            validOrderInfoLength(rightKey, rightVal, 255);
            validOrderInfoEmpty(leftKey, leftVal);
            validOrderInfoLength(leftKey, leftVal, 255);
            orderDO.setDealer(leftVal);
            orderDO.setAddress(rightVal);
        }
        // 左：经销商电话（非必填）、右：客户电话
        if (2 == rowIndex) {
            validOrderInfoPhone(leftKey, leftVal);
            validOrderInfoEmpty(rightKey, rightVal);
            validOrderInfoPhone(rightKey, rightVal);
            orderDO.setDealerPhoneNumber(leftVal);
            orderDO.setPhoneNumber(rightVal);
        }
        // 左：业务员(非必填)、右：出货日期
        if (3 == rowIndex) {
            validOrderInfoLength(leftKey, leftVal, 64);
            validOrderInfoEmpty(rightKey, rightVal);
            LocalDate deliverDate = validOrderInfoDate(rightKey, rightVal);
            // 出货时间早于导入时间，自动延长30天
            if (deliverDate.isBefore(LocalDate.now())) {
                deliverDate = LocalDate.now().plus(30, ChronoUnit.DAYS);
            }
            orderDO.setSalesman(leftVal);
            orderDO.setDeliveryDate(deliverDate.atStartOfDay());
        }
        // 左：拆单员(非必填)、右：备注(非必填)
        if (4 == rowIndex) {
            validOrderInfoLength(leftKey, leftVal, 64);
            validOrderInfoLength(rightKey, rightVal, 255);
            orderDO.setSplitter(StringUtils.isNotEmpty(leftVal) ? leftVal : EMPTY_STRING);
            orderDO.setRemark(rightVal);
        }
        orderDO.setDataType(DataTypeEnum.FILE_IMPORT.getStatus());
        LocalDateTime now = LocalDateTime.now();
        orderDO.setOrderDate(now);
        orderDO.setOrganId(OrganContextHolder.getOrganId());
        String loginUserName = WebFrameworkUtils.getLoginUserName();
        orderDO.setCreator(loginUserName);
        orderDO.setUpdater(loginUserName);
        orderDO.setCreateTime(now);
        orderDO.setUpdateTime(now);
    }

    /**
     * 自定义单号校验
     *
     * @param key
     * @param val
     */
    private void validCustomOrderNo(String key, String val) {
        if (StringUtils.isNotEmpty(val) && !orderService.customOrderNoIsExists(val)) {
            throw new ServiceException(ORDER_IMPORT_ORDER_CUSTOMERNO_EXISTS, key, val);
        }
    }

    /**
     * 校验空
     *
     * @param key
     * @param val
     */
    private void validOrderInfoEmpty(String key, String val) {
        if (StringUtils.isEmpty(val)) {
            throw new ServiceException(ORDER_IMPORT_ORDER_FIELD_EMPTY, key);
        }
    }

    /**
     * 校验长度
     *
     * @param key
     * @param val
     * @param length
     */
    private void validOrderInfoLength(String key, String val, int length) {
        if (StringUtils.isNotEmpty(val) && length < val.length()) {
            throw new ServiceException(ORDER_IMPORT_ORDER_FIELD_LENGTH_ERROR, key, length);
        }
    }

    /**
     * 校验手机号格式
     *
     * @param key
     * @param val
     */
    private void validOrderInfoPhone(String key, String val) {
        if (StringUtils.isNotEmpty(val) && Boolean.FALSE.equals(ToolUtil.validatePhoneNumber(val))) {
            throw new ServiceException(ORDER_IMPORT_ORDER_FIELD_MOBILE_FORMAT_ERROR, key);
        }
    }

    /**
     * 校验时间格式
     *
     * @param key
     * @param val
     */
    private LocalDate validOrderInfoDate(String key, String val) {
        try {
            return LocalDateTimeUtil.parseDate(val, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        } catch (Exception e) {
            throw new ServiceException(ORDER_IMPORT_ORDER_FIELD_DATE_FORMAT_ERROR, key);
        }
    }

    /**
     * excel解析成importvo
     *
     * @param data
     */
    private OrderPlateImportExcelVO setOrderPlateProperty(Map<Integer, String> data) {
        OrderPlateImportExcelVO vo = new OrderPlateImportExcelVO();
        for (Map.Entry<Integer, String> entry : data.entrySet()) {
            Integer index = entry.getKey();
            String value = entry.getValue();
            switch (index) {
                case 0:
                    vo.setOrdinal(value);
                    break;
                case 1:// 类型
                    vo.setGoodType(value);
                    break;
                case 2:// 物料编码
                    vo.setGoodsId(value);
                    break;
                case 3:// 商品名称
                    vo.setGoodsName(value);
                    break;
                case 4:// 材质
                    vo.setMaterial(value);
                    break;
                case 5:// 纹理
                    vo.setWave(value);
                    break;
                case 6:// 颜色
                    vo.setColor(value);
                    break;
                case 7:// 复合部件
                    vo.setIsComposite(value);
                    break;
                case 8:// 配件类型
                    vo.setCategory(value);
                    break;
                case 9:// 子类
                    vo.setType(value);
                    break;
                case 10:// 厂家
                    vo.setFactory(value);
                    break;
                case 11:// 品牌
                    vo.setBrand(value);
                    break;
                case 12:// 型号
                    vo.setModel(value);
                    break;
                case 13:// 板材/配件长
                    vo.setGoodsHeight(value);
                    break;
                case 14:// 板材/配件宽
                    vo.setGoodsWidth(value);
                    break;
                case 15:// 板材/配件厚
                    vo.setGoodsThickness(value);
                    break;
                case 16:// 规格
                    vo.setSpec(value);
                    break;
                case 17:// 单位
                    vo.setUnit(value);
                    break;
                case 18:// 数量
                    vo.setGoodsNumber(value);
                    break;
                case 19:// 房间
                    vo.setRoomsName(value);
                    break;
                case 20:// 柜体
                    vo.setCabinetsName(value);
                    break;
                case 21:// 加工组类型
                    vo.setSynthesisTypeName(value);
                    break;
                case 22:// 加工组名称
                    vo.setCombinationName(value);
                    break;
                case 23://板名称
                    vo.setName(value);
                    break;
                case 24:// 自定义板编号
                    vo.setPlateNo(value);
                    break;
                case 25:// 成品长
                    vo.setHeight(value);
                    break;
                case 26:// 成品宽
                    vo.setWidth(value);
                    break;
                case 27:// 拆单长
                    vo.setSplitHeight(value);
                    break;
                case 28:// 拆单宽
                    vo.setSplitWidth(value);
                    break;
                case 29:// 厚
                    vo.setThickness(value);
                    break;
                case 30:// 左封边
                    vo.setSealLeft(value);
                    break;
                case 31:// 右封边
                    vo.setSealRight(value);
                    break;
                case 32:// 上封边
                    vo.setSealUp(value);
                    break;
                case 33:// 下封边
                    vo.setSealDown(value);
                    break;
                case 34:// 排版面
                    vo.setTypographicFace(value);
                    break;
                case 35:// 纹路
                    vo.setTexture(value);
                    break;
                case 36:// 开门方向
                    vo.setOpenDoorType(value);
                    break;
                case 37://备注1
                    vo.setRemark1(value);
                    break;
                case 38://备注2
                    vo.setRemark2(value);
                    break;
                case 39://备注3
                    vo.setRemark3(value);
                    break;
                case 40://备注4
                    vo.setRemark4(value);
                    break;
                case 41://备注5
                    vo.setRemark5(value);
                    break;
                case 42://备注6
                    vo.setRemark6(value);
                    break;
                case 43://备注7
                    vo.setRemark7(value);
                    break;
                case 44://备注8
                    vo.setRemark8(value);
                    break;
                case 45://备注9
                    vo.setRemark9(value);
                    break;
                case 46://备注10
                    vo.setRemark10(value);
                    break;
                default:
                    // 处理默认情况，可以选择忽略或者做其他处理
                    break;
            }
        }
        return vo;
    }

    private OrderImportTempDataDO checkData(OrderPlateImportExcelVO vo) {
        // 全部需要值的字段
        // 检查非空 类型、数量
        isEmpty(vo.getGoodType(), "类型", 32);
        isEmpty(vo.getGoodsNumber(), "数量", 10000000);

        // 检查商品物料编码或是商品名称、材质、颜色不可全为空
        if (StringUtils.isEmpty(vo.getGoodsName()) || StringUtils.isEmpty(vo.getMaterial()) || StringUtils.isEmpty(vo.getColor()) || StringUtils.isEmpty(vo.getUnit())) {
            throw new ServiceException(10000, "商品商品名称、材质、颜色、单位不可为空");
        }

        if (StringUtils.equals(vo.getGoodType(), "配件")) {
            // 复合部件
            isNotEmptyAndBack(StringUtils.isNotEmpty(vo.getIsComposite()) ? vo.getIsComposite() : "否", QuarrelEnum.class, "是否复合部件", 1); // 判断传入的值，是否符合字典中的枚举类
            // 配件类型必填
            isNotEmptyAndBack(vo.getCategory(), CategoryEnum.class, "配件类型", 32);
            // 配件长宽厚，存在判断是否可以转义
            isEmptyAndNumberSize(vo.getGoodsWidth(), Double.class, 5, 3, "配件宽");
            isEmptyAndNumberSize(vo.getGoodsHeight(), Double.class, 5, 3, "配件高");
            isEmptyAndNumberSize(vo.getGoodsThickness(), Double.class, 5, 3, "配件厚");
            // 配件类型为封边条的时候，需要填写配件宽厚
            if (StringUtils.equals(vo.getCategory(), CategoryEnum.EDGING.getValue())) { // 封边条必须有宽高
                isNotEmptyAndBack(vo.getGoodsWidth(), "封边条宽");
                isNotEmptyAndBack(vo.getGoodsThickness(), "封边条厚");
            }
            // 配件数量判断
            isEmptyAndPositiveNumber(vo.getGoodsNumber(), Double.class, "配件数量");
        }
        // 若商品类型为板材，需检查房间、柜体、板名称、成品长、成品宽、拆单长、拆单宽、厚、左封边、右封边、上封边、下封边、排版面、纹路、开门方向不能为空
        boolean isPlate = StringUtils.equals(vo.getGoodType(), "板材");
        BigDecimal area = null;
        if (isPlate) {
            checkPlate(vo);

            // 计算面积
            area = BigDecimal.valueOf(Double.parseDouble(vo.getGoodsWidth()))
                    .multiply(BigDecimal.valueOf(Double.parseDouble(vo.getGoodsHeight())))
                    .movePointLeft(6)
                    .setScale(2, RoundingMode.HALF_UP);
        }

        // 校验通过生成临时表实体
        OrderImportTempDataDO orderImportTempDataDO = OrderImportTempDataDO.builder()
                .id((Long) snowFlakeGenerator.nextId(null))
                .taskId(taskId)
                .orderId(orderId)
                .type(isPlate ? OrderImportTmpDataTypeEnum.PLATE.getType() : OrderImportTmpDataTypeEnum.PART.getType())
                .outerGoodsId(StringUtils.isNotEmpty(vo.getGoodsId()) ? vo.getGoodsId() : OrderImportConstants.DEFAULT_GOODS_ID)
                .goodsName(vo.getGoodsName())
                .material(vo.getMaterial())
                .color(vo.getColor())
                .wave(StringUtils.equals("有", vo.getWave()) ? "true" : "false")
                .width(vo.getGoodsWidth())
                .height(vo.getGoodsHeight())
                .thickness(vo.getGoodsThickness())
                .brand(vo.getBrand())
                .isComposite(vo.getIsComposite())
                .category(vo.getCategory())
                .subType(vo.getType())
                .factory(vo.getFactory())
                .spec(vo.getSpec())
                .model(vo.getModel())
                .unit(vo.getUnit())
                .roomName(StringUtils.isNotEmpty(vo.getRoomsName()) ? vo.getRoomsName() : OrderImportConstants.NOT_ASSIGNED)
                .bodyName(StringUtils.isNotEmpty(vo.getCabinetsName()) ? vo.getCabinetsName() : OrderImportConstants.NOT_ASSIGNED)
                .groupTypeName(vo.getSynthesisTypeName())
                .groupName(vo.getCombinationName())
                .detail(JsonUtils.zipString(JSON.toJSONString(vo)))
                .num(Double.parseDouble(vo.getGoodsNumber()))
                .area(area)
                .createTime(LocalDateTime.now())
                .sort(sort++)
                .build();
        return orderImportTempDataDO;
    }

    // 板材的数据以及长度的检验
    public void checkPlate(OrderPlateImportExcelVO vo) {
        // 数量类型判断
        isEmptyAndPositiveNumber(vo.getGoodsNumber(), Integer.class, "板材数量");
        // 板材纹理
        String wave = vo.getWave();
        isNotEmptyAndBack(StringUtils.isNotEmpty(wave) ? wave : "有", IsHavaeEnum.class, "板材纹理", 4);
        // 大板的长宽厚存在以及是否符合数个
        isEmptyAndPositiveNumberSize(vo.getGoodsWidth(), Double.class, 5, 3, "板材长度");
        isEmptyAndPositiveNumberSize(vo.getGoodsHeight(), Double.class, 5, 3, "板材宽度");
        isNotEmptyAndBack(vo.getGoodsThickness(), "板材厚度");
        isEmptyAndPositiveNumberSize(vo.getGoodsThickness(), Double.class, 5, 3, "板材厚度");
        // 房间、柜体校验长度
        isEmptyAndSize(vo.getRoomsName(), 64, "房间名称");
        isEmptyAndSize(vo.getCabinetsName(), 64, "柜体名称");
        // 板名称 不可以为空
        isEmpty(vo.getName(), "板材名称", 64);
        //成品长、成品宽、拆单长、拆单宽、厚、左封边、右封边、上封边、下封边 不能为空
        isNotEmptyAndBack(vo.getHeight(), "成品长度");
        isEmptyAndPositiveNumberSize(vo.getHeight(), Double.class, 5, 3, "成品长度");
        isNotEmptyAndBack(vo.getWidth(), "成品宽度");
        isEmptyAndPositiveNumberSize(vo.getWidth(), Double.class, 5, 3, "成品宽度");
        isEmptyAndPositiveNumberSize(vo.getSplitHeight(), Double.class, 5, 3, "拆单长度");
        isEmptyAndPositiveNumberSize(vo.getSplitWidth(), Double.class, 5, 3, "拆单宽度");
        isNotEmptyAndBack(vo.getThickness(), "厚度");
        isEmptyAndPositiveNumberSize(vo.getThickness(), Double.class, 5, 3, "厚度");
        isNotEmptyAndBack(vo.getSealLeft(), "左封边");
        isEmptyAndNumberSize(vo.getSealLeft(), Double.class, 2, 2, "左封边");
        isNotEmptyAndBack(vo.getSealRight(), "右封边");
        isEmptyAndNumberSize(vo.getSealRight(), Double.class, 2, 2, "右封边");
        isNotEmptyAndBack(vo.getSealUp(), "上封边");
        isEmptyAndNumberSize(vo.getSealUp(), Double.class, 2, 2, "上封边");
        isNotEmptyAndBack(vo.getSealDown(), "下封边");
        isEmptyAndNumberSize(vo.getSealDown(), Double.class, 2, 2, "下封边");
        // 排版面、纹路、开门方向
        isNotEmptyAndDict(vo.getTypographicFace(), DictTypeConstants.TYPOGRAPHY_TYPE, "排版面");
        isNotEmptyAndDict(vo.getTexture(), DictTypeConstants.GRAIN_TYPE, "纹路");
        isNotEmptyAndDict(vo.getOpenDoorType(), DictTypeConstants.DOOR_OPENING_DIRECTIONS, "开门方向");

        // 查询板材库是否有对应
        queryPlateExists(vo);
    }

    /**
     * 查询板材库是否有对应物料编码
     * 不存在再使用material、coatingObverse、thickness、brand、name查询是否存在匹配，还是不存在提示板材库先添加
     *
     * @param plate
     */
    private void queryPlateExists(OrderPlateImportExcelVO plate) {
        PlateGoodDO plateGoodDO = null;
        List<PlateGoodDO> plateGoodDOs;
        if (StringUtils.isNotEmpty(plate.getGoodsId())) {
            plateGoodDOs = plateGoodMapper.selectGoodOne(plate.getGoodsId(), OrganContextHolder.getOrganId());
        } else {
            plateGoodDOs = plateGoodMapper.selectGood(plate.getMaterial(), plate.getColor(),
                    BigDecimal.valueOf(Long.parseLong(plate.getThickness())),
                    plate.getBrand(), plate.getGoodsName(), OrganContextHolder.getOrganId());
        }

        if (CollUtil.isNotEmpty(plateGoodDOs)) {
            plateGoodDO = plateGoodDOs.get(0);
        }

        if (ObjectUtil.isNull(plateGoodDO)) {
            throw new ServiceException(ORDER_IMPORT_PLATEGOODS_NOT_EXIST_VALID_ERROR, rowIndex + 1);
        }
    }

    /**
     * 获取行数的提示，第rowIndex行
     *
     * @return
     */
    private String getRowIndexNotification() {
        return String.format("第%s行", rowIndex + 1);
    }

    // 判断非空，字典值判断
    public void isNotEmptyAndDict(String value, String dictType, String errValue) {
        if (StringUtils.isEmpty(value)) {
            throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NOT_EMPTY);
        } else {
            DictDataRespDTO dictDataRespDTO = dictDataApi.parseDictData(dictType, value).getData();
            if (dictDataRespDTO == null) {
                throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + ACCORD_ENUM);
            }
        }
    }

    // 非空判断，错误填入
    private void isEmpty(String value, String errValue, int length) {
        if (StringUtils.isEmpty(value)) {
            throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NOT_EMPTY);
        } else {
            // 字符串长度检查
            int size = value.length();
            if (size > length) {
                throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NUMBER_LENGTH_ERR);
            }
        }
    }

    // 错误判断通用方法
    // 判断非零，错误返回；不为空时，判断是否符合枚举类
    private void isNotEmptyAndBack(String value, Class<? extends Enum<?>> enumClass, String errValue, int length) {
        if (StringUtils.isEmpty(value)) {
            throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NOT_EMPTY);
        } else {
            isEmptyAndSize(value, length, errValue);
            try {
                // 获取枚举类的所有值
                Enum<?>[] enums = enumClass.getEnumConstants();
                boolean isValid = false;
                for (Enum<?> enumValue : enums) {
                    Field valueField = enumValue.getClass().getDeclaredField("value");
                    valueField.setAccessible(true);
                    String enumValueStr = (String) valueField.get(enumValue);
                    if (enumValueStr.equals(value)) {
                        isValid = true;
                        break;
                    }
                }
                if (!isValid) {
                    throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + ACCORD_ENUM);
                }
            } catch (IllegalArgumentException e) {
                throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + ACCORD_ENUM);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 检查值大于等于0、数据类型和长度
     *
     * @param value
     * @param targetType
     * @param length
     * @param decimalLength
     * @param errValue
     */
    private void isEmptyAndNumberSize(String value, Class<?> targetType, Integer length, Integer decimalLength, String errValue) {
        if (StringUtils.isNotEmpty(value)) {
            if (Boolean.TRUE.equals(ToolUtil.convertToType(value, targetType))) {
                if (Boolean.TRUE.equals(ToolUtil.checkNumber(value))) {
                    if (!ToolUtil.checkPrecision(value, length, decimalLength)) {
                        throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NUMBER_LENGTH_ERR);
                    }
                } else {
                    throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + POSITIVE_ERR);
                }
            } else {
                throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NUMBER_TYPE_ERR);
            }
        }
    }

    /**
     * 检查值大于0、数据类型和长度
     *
     * @param value
     * @param targetType
     * @param length
     * @param decimalLength
     * @param errValue
     */
    private void isEmptyAndPositiveNumberSize(String value, Class<?> targetType, Integer length, Integer decimalLength, String errValue) {
        if (StringUtils.isNotEmpty(value)) {
            if (Boolean.TRUE.equals(ToolUtil.convertToType(value, targetType))) {
                if (Boolean.TRUE.equals(checkPositiveNumber(value))) {
                    if (!ToolUtil.checkPrecision(value, length, decimalLength)) {
                        throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NUMBER_LENGTH_ERR);
                    }
                } else {
                    throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + "必须大于0");
                }
            } else {
                throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NUMBER_TYPE_ERR);
            }
        }
    }

    // 判断非零，错误返回
    private void isNotEmptyAndBack(String value, String errValue) {
        if (StringUtils.isEmpty(value)) {
            throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NOT_EMPTY);
        }
    }

    // 判断非空，有值判断字符串的长度
    private void isEmptyAndSize(String value, Integer length, String errValue) {
        if (StringUtils.isNotEmpty(value)) {
            int size = value.length();
            if (size > length) {
                throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NUMBER_LENGTH_ERR);
            }
        }
    }

    // 判断非空，大于零判断
    public void isEmptyAndPositiveNumber(String value, Class<?> targetType, String errValue) {
        if (StringUtils.isNotEmpty(value)) {
            if (Boolean.FALSE.equals(ToolUtil.convertToType(value, targetType))) {
                throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + NUMBER_TYPE_ERR);
            } else {
                if (Boolean.FALSE.equals(checkPositiveNumber(value))) {
                    throw new ServiceException(ORDER_IMPORT_DETAIL_VALID_ERROR, getRowIndexNotification() + errValue + "数量必须大于0");
                }
            }
        }
    }

    /**
     * 检查是否正数（不包含0）
     *
     * @param numberStr
     * @return
     */
    public static Boolean checkPositiveNumber(String numberStr) {
        try {
            double number = Double.parseDouble(numberStr);
            // 进行正负判断
            if (number > 0) {
                return true;
            } else {
                return false;
            }
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 检查是否正数（包含0）
     *
     * @param numberStr
     * @return
     */
    public static Boolean checkNumber(String numberStr) {
        try {
            double number = Double.parseDouble(numberStr);
            // 进行正负判断
            if (number >= 0) {
                return true;
            } else {
                return false;
            }
        } catch (NumberFormatException e) {
            return false;
        }
    }
}
