package cn.estsh.i3plus.ext.mes.apiservice.serviceimpl.busi.jx;

import cn.estsh.i3plus.ext.mes.api.base.bu.ISxBuBaseDataService;
import cn.estsh.i3plus.ext.mes.api.base.jx.IJxBadnessClassifyService;
import cn.estsh.i3plus.ext.mes.api.base.jx.IJxBadnessTypeService;
import cn.estsh.i3plus.ext.mes.api.busi.jx.IJxOqcReportFormService;
import cn.estsh.i3plus.ext.mes.api.busi.jx.IJxOutPutStatisticsService;
import cn.estsh.i3plus.ext.mes.apiservice.dao.jx.IJxOqcCheckReportDao;
import cn.estsh.i3plus.ext.mes.apiservice.dao.jx.IJxOutPutStatisticsDao;
import cn.estsh.i3plus.ext.mes.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pojo.model.bu.BuNumberRuleModel;
import cn.estsh.i3plus.ext.mes.pojo.model.jx.*;
import cn.estsh.i3plus.ext.mes.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pojo.sqlpack.MesExtHqlPack;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.impp.framework.boot.auth.AuthUtil;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : wangjie
 * @CreateDate : 2022-02-15
 * @Modify:
 **/
@Slf4j
@Service
public class JxOqcReportFormService implements IJxOqcReportFormService {

    @Autowired
    private MesOqcCheckRepository oqcCheckRepository;

    @Autowired
    private IJxBadnessTypeService buBadnessTypeService;

    @Autowired
    private IJxBadnessClassifyService badnessClassifyService;

    @Autowired
    private MesOqcCheckDetailRepository oqcCheckDetailRepository;

    @Autowired
    private IJxOutPutStatisticsDao outPutStatisticsDao;

    @Autowired
    private IJxOqcCheckReportDao oqcCheckReportDao;

    @Autowired
    private MesErrorLineOffRepository errorLineOffRepository;

    @Autowired
    private MesErrorLineOffDetailRepository errorLineOffDetailRepository;

    @Autowired
    private MesOqcCheckPackageDetailRepository oqcCheckPackageDetailRepository;

    @Autowired
    private MesOqcCheckPackageIfRepository oqcCheckPackageIfRepository;

    @Autowired
    private MesOqcCheckPackageDetailTravelRepository oqcCheckPackageDetailTravelRepository;

    @Autowired
    private IJxOqcCheckReportDao jxOqcCheckReportDao;

    @Autowired
    private MesOutPutStatisticsOqcRepository statisticsOqcRepository;

    @Autowired
    private MesWorkCenterExtRepository workCenterExtRepository;

    @Autowired
    private MesOqcCheckTravelRepository oqcCheckTravelRepository;

    @Autowired
    private IJxOutPutStatisticsService outPutStatisticsService;

    @Autowired
    private ISxBuBaseDataService buBaseDataService;

    @Override
    public ListPager<JxOqcCheckReportModel> queryOqcCheckReportPager(JxOqcCheckReportModel model, Pager pager) {
        List<JxOqcCheckReportModel> resultList = new ArrayList<>();

        DdlPackBean packBean = getDdlPackBean4OqcCheckReport(model);
        pager = PagerHelper.getPager(pager, oqcCheckRepository.findByHqlWhereCount(packBean));
        packBean.setOrderByStr(MesExtConstWords.ORDER_BY_MDT_DESC);
        List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWherePage(packBean, pager);

        if (!CollectionUtils.isEmpty(oqcCheckList)) {

            Map<String, List<MesBadnessType>> badnessTypeMap = buBadnessTypeService.getBadnessTypeMap(model.getOrganizeCode());
            Map<String, List<MesBadnessClassify>> badnessClassifyMap = badnessClassifyService.getBadnessClassifyMap(model.getOrganizeCode());

            for (MesOqcCheck oqcCheck : oqcCheckList) {
                if (null == oqcCheck) continue;

                resultList.add(packResult4OqcCheckReport(oqcCheck, badnessTypeMap, badnessClassifyMap));
            }
        }

        return new ListPager(resultList, pager);
    }

    @Override
    public void updateOqcCheckReport(JxOqcCheckReportModel model) {
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getById(model.getId());
        if(oqcCheckDb == null) {
            if (null == oqcCheckDb) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("检验单ID[%s]数据不存在", model.getId())
                        .build();
            }
        }

        if (StringUtils.isEmpty(oqcCheckDb.getCheckResult()) || null == MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]还未进行完出货检验,不能进行检验结果更改", oqcCheckDb.getOqcNo())
                    .build();
        }

        if(oqcCheckDb.getCheckResult() == MesExtEnumUtil.OQC_CHECK_RESULT.QUALIFIED.getValue()){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("合格的检验单不能保存不良信息")
                    .build();
        }

        oqcCheckDb.setBadnessTypeCode(model.getBadnessTypeCode());
        oqcCheckDb.setBadnessClassifyCode(model.getBadnessClassifyCode());
        oqcCheckDb.setBadnessClassifyDetailCode(model.getBadnessClassifyDetailCode());
        oqcCheckDb.setBadnessClassifyDetailName(model.getBadnessClassifyDetailName());
        oqcCheckDb.setRemark(model.getRemark());
        oqcCheckDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        oqcCheckRepository.save(oqcCheckDb);
    }

    private DdlPackBean getDdlPackBean4OqcCheckReport(JxOqcCheckReportModel model) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getWorkOrderNo(), MesExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getPartNo(), MesExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(model.getSerialNumber(), MesExtConstWords.SERIAL_NUMBER, packBean);
        DdlPreparedPack.getStringEqualPack(model.getSnType(), MesExtConstWords.SN_TYPE, packBean);
        DdlPreparedPack.getStringEqualPack(model.getBadnessTypeCode(), MesExtConstWords.BADNESS_TYPE_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(model.getBadnessClassifyCode(), MesExtConstWords.BADNESS_CLASSIFY_CODE, packBean);
        DdlPreparedPack.getStringLikerPack(model.getBadnessClassifyDetailName(), MesExtConstWords.BADNESS_CLASSIFY_DETAIL_NAME, packBean);
        DdlPreparedPack.getStringLikerPack(model.getOqcNo(), MesExtConstWords.OQC_NO, packBean);
        DdlPreparedPack.getNumEqualPack(model.getWorkOrderType(), MesExtConstWords.WORK_ORDER_TYPE, packBean);
        DdlPreparedPack.getNumEqualPack(model.getOqcNoType(), MesExtConstWords.OQC_NO_TYPE, packBean);
        DdlPreparedPack.getNumEqualPack(model.getOqcType(), MesExtConstWords.OQC_TYPE, packBean);
        //checkResult 为0 则是未检验的数据
        if(model.getCheckResult() != null){
            packBean.addColumnQuery(MesExtConstWords.CHECK_RESULT, " and model." + MesExtConstWords.CHECK_RESULT + " = :m_" + MesExtConstWords.CHECK_RESULT, model.getCheckResult());
        }
//        DdlPreparedPack.getNumEqualPack(model.getCheckResult(), MesExtConstWords.CHECK_RESULT, packBean);
        DdlPreparedPack.timeBuilder(model.getWorkTimeStart(), model.getWorkTimeEnd(), MesExtConstWords.WORK_TIME, packBean, false);
        DdlPreparedPack.getStringEqualPack(model.getShiftCode(), MesExtConstWords.SHIFT_CODE, packBean);
        return packBean;
    }

    private JxOqcCheckReportModel packResult4OqcCheckReport(MesOqcCheck oqcCheck,
                                                            Map<String, List<MesBadnessType>> badnessTypeMap,
                                                            Map<String, List<MesBadnessClassify>> badnessClassifyMap) {
        JxOqcCheckReportModel result = new JxOqcCheckReportModel();
        BeanUtils.copyProperties(oqcCheck, result);
        result.setWorkOrderTypeName(MesExtEnumUtil.WORK_ORDER_TYPE.valueOfDescription(result.getWorkOrderType()));
        result.setOqcNoTypeName(MesExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(result.getOqcNoType()));
        result.setSnTypeName(MesExtEnumUtil.OQC_MANAGE_ACTION_TYPE.valueOfDescription(result.getSnType()));
        result.setOqcTypeName(MesExtEnumUtil.OQC_TYPE.valueOfDescription(result.getOqcType()));
        result.setCheckResultName(!StringUtils.isEmpty(result.getCheckResult()) ? MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(result.getCheckResult()) : null);
        result.setBadnessTypeName((!StringUtils.isEmpty(result.getBadnessTypeCode()) && !CollectionUtils.isEmpty(badnessTypeMap) && badnessTypeMap.containsKey(result.getBadnessTypeCode())) ?
                badnessTypeMap.get(result.getBadnessTypeCode()).get(0).getBadnessTypeName() : null);
        result.setBadnessClassifyName((!StringUtils.isEmpty(result.getBadnessTypeCode()) && !StringUtils.isEmpty(result.getBadnessClassifyCode()) && !CollectionUtils.isEmpty(badnessClassifyMap) &&
                badnessClassifyMap.containsKey(new StringJoiner(MesExtConstWords.AND).add(result.getBadnessTypeCode()).add(result.getBadnessClassifyCode()).toString())) ?
                badnessClassifyMap.get(new StringJoiner(MesExtConstWords.AND).add(result.getBadnessTypeCode()).add(result.getBadnessClassifyCode()).toString()).get(0).getBadnessClassifyName() : null);

        if(result.getCheckResult() == null){
            result.setCheckResultColor("#ffd733");
        }else if(result.getCheckResult() == MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue()){
            result.setCheckResultColor("#ff6666");
        }else{
            result.setCheckResultColor("white");
        }
        return result;
    }

    @Override
    public ListPager<JxOqcCheckDetailReportModel> queryOqcCheckDetailReportPager(JxOqcCheckDetailReportModel model, Pager pager) {
        pager = PagerHelper.getPager(pager, jxOqcCheckReportDao.queryOqcCheckDetailReportPagerCount(model));
        List<JxOqcCheckDetailReportModel> resultList = jxOqcCheckReportDao.queryOqcCheckDetailReportPager(model , pager);
        return new ListPager(packResult4OqcCheckDetailReport(resultList), pager);
    }

    private DdlPackBean getDdlPackBean4OqcCheckDetailReport(JxOqcCheckDetailReportModel model) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getWorkOrderNo(), MesExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getPartNo(), MesExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(model.getSerialNumber(), MesExtConstWords.SERIAL_NUMBER, packBean);
        DdlPreparedPack.getStringEqualPack(model.getCheckValue(), MesExtConstWords.CHECK_VALUE, packBean);
        DdlPreparedPack.getStringEqualPack(model.getShiftCode(), MesExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringLikerPack(model.getCheckItem(), MesExtConstWords.CHECK_ITEM, packBean);
        DdlPreparedPack.getStringLikerPack(model.getStandard(), MesExtConstWords.STANDARD, packBean);
        DdlPreparedPack.getStringLikerPack(model.getOqcNo(), MesExtConstWords.OQC_NO, packBean);
        DdlPreparedPack.getNumEqualPack(model.getCheckResult(), MesExtConstWords.CHECK_RESULT, packBean);
        DdlPreparedPack.timeBuilder(model.getWorkTimeStart(), model.getWorkTimeEnd(), MesExtConstWords.WORK_TIME, packBean, false);
        return packBean;
    }

    private List<JxOqcCheckDetailReportModel> packResult4OqcCheckDetailReport(List<JxOqcCheckDetailReportModel> resultList) {
        //JxOqcCheckDetailReportModel result = new JxOqcCheckDetailReportModel();
        //BeanUtils.copyProperties(oqcCheckDetail, result);
        if(CollectionUtils.isEmpty(resultList)) return new ArrayList<>();
        for (JxOqcCheckDetailReportModel result : resultList) {
            result.setCheckResultName(!StringUtils.isEmpty(result.getCheckResult()) ? MesExtEnumUtil.OQC_CHECK_DETAIL_RESULT.valueOfDescription(result.getCheckResult()) : null);
            result.setCheckTypeName(MesExtEnumUtil.CHECK_JUDGE_TYPE.valueOfDescription(result.getCheckType()));
            result.setIdStr(result.getId().toString());
            /**
             * 合格：白色底色（不变）
             *
             * 不合格：红色（#ff6666）
             *
             * 未检验：黄色（#ffd733）
             */
            if(result.getCheckResult() == null){
                result.setCheckResultColor("#ffd733");
            }else if(result.getCheckResult() == MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue()){
                result.setCheckResultColor("#ff6666");
            }else{
                result.setCheckResultColor("white");
            }
            result.setOqcNoTypeName(MesExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(result.getOqcNoType()));
        }

        return resultList;
    }

    @Override
    public void updateOqcCheckDetailConfirmUser(String[] idStr, String userName) {
        for (String id : idStr) {
            if (StringUtils.isEmpty(id)) continue;
            MesOqcCheckDetail oqcCheckDetailDb = oqcCheckDetailRepository.getById(Long.valueOf(id));
            if (null == oqcCheckDetailDb ||
                    (MesExtEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == oqcCheckDetailDb.getIsDeleted() ||
                            CommonEnumUtil.IS_VAILD.INVAILD.getValue() == oqcCheckDetailDb.getIsValid())) {
                continue;
            }
            if (!StringUtils.isEmpty(oqcCheckDetailDb.getConfirmUser()) && !StringUtils.isEmpty(oqcCheckDetailDb.getConfirmTime())) {
                continue;
            }
            oqcCheckDetailDb.setConfirmUser(userName);
            oqcCheckDetailDb.setConfirmTime(oqcCheckDetailDb.getModifyDatetime());
            ConvertBean.serviceModelUpdate(oqcCheckDetailDb, userName);
            oqcCheckDetailDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            oqcCheckDetailRepository.save(oqcCheckDetailDb);
        }
    }
    @Override
    public void updateOqcCheckDetailEdit(JxOqcCheckDetailReportModel model) {
            MesOqcCheckDetail oqcCheckDetailDb = oqcCheckDetailRepository.getById(Long.valueOf(model.getId()));
            if (null == oqcCheckDetailDb) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("检验单明细ID[%s]数据不存在", model.getId())
                        .build();
            }
            oqcCheckDetailDb.setCheckValue(model.getCheckValue());
            oqcCheckDetailDb.setCheckTool(model.getCheckTool());
            oqcCheckDetailDb.setRemark(model.getRemark());
            oqcCheckDetailDb.setCheckResult(model.getCheckResult());
            oqcCheckDetailDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(oqcCheckDetailDb, AuthUtil.getSessionUser().getUserName());
            oqcCheckDetailRepository.save(oqcCheckDetailDb);
        }

    @Override
    public JxOqcCheckQualityEarlyWarningReportModel queryOqcCheckQualityEarlyWarningReport(JxOqcCheckQualityEarlyWarningReportModel model) {
        log.info("出货检验质量预警报表,参数[{}]", model.toBaseString());

        packDate4QualityEarlyWarningReport(model);

        List<MesBadnessType> badnessTypeList = buBadnessTypeService.getBadnessTypeList(model.getOrganizeCode());

        packAttributeList4QualityEarlyWarningReport(model, badnessTypeList);

        if (CollectionUtils.isEmpty(badnessTypeList)) return model;

        List<JxOqcCheckReportModel> oqcCheckList = getOqcCheckList4QualityEarlyWarning(model);

        if (CollectionUtils.isEmpty(oqcCheckList)) return model;

        log.info("出货检验质量预警报表,数据量[{}]", oqcCheckList.size());

        packWorkTime4QualityEarlyWarningReport(oqcCheckList, model);

        Map<String, List<JxOqcCheckReportModel>> dataMap = packMap4QualityEarlyWarningReport(oqcCheckList, model.getDimension1());

        if (CollectionUtils.isEmpty(dataMap)) return model;

        log.info("出货检验质量预警报表,分组后数据量[{}]", dataMap.size());

        Map<String, String> centerMap = getCenterMap4QualityEarlyWarningReport(model);

        model.setDataList(packDataList4QualityEarlyWarningReport(dataMap, badnessTypeList, centerMap, model.getDimension1()));

        return model;
    }

    private void packDate4QualityEarlyWarningReport(JxOqcCheckQualityEarlyWarningReportModel model) {
        model.setCheckTimeStart(model.getHappenTimeStart() + MesExtConstWords.APPEND_ZERO_HH_MM_SS);
        model.setCheckTimeEnd(model.getHappenTimeEnd() + MesExtConstWords.APPEND_24_HH_MM_SS);
    }

    private void packAttributeList4QualityEarlyWarningReport(JxOqcCheckQualityEarlyWarningReportModel model, List<MesBadnessType> badnessTypeList) {

        packBaseAttributeList4QualityEarlyWarningReport(model);

        if (CollectionUtils.isEmpty(badnessTypeList)) return;

        packDynamicAttributeList4QualityEarlyWarningReport(model, badnessTypeList);

    }

    private void packBaseAttributeList4QualityEarlyWarningReport(JxOqcCheckQualityEarlyWarningReportModel model) {
        model.addAttribute(new SxDynamicAttributeModel("发生时间", MesExtConstWords.HAPPEN_TIME));

        if (MesExtEnumUtil.REPORT_DIMENSION_DATE_OR_CENTER.CENTER.getValue() == model.getDimension1())
            model.addAttribute(new SxDynamicAttributeModel("生产线代码", MesExtConstWords.WORK_CENTER_CODE))
                    .addAttribute(new SxDynamicAttributeModel("生产线名称", MesExtConstWords.WORK_CENTER_NAME));

        model.addAttribute(new SxDynamicAttributeModel("不良批次", MesExtConstWords.QTY));
    }

    private void packDynamicAttributeList4QualityEarlyWarningReport(JxOqcCheckQualityEarlyWarningReportModel model, List<MesBadnessType> badnessTypeList) {
        for (MesBadnessType buBadnessType : badnessTypeList) {
            if (null == buBadnessType) continue;
            model.addAttribute(new SxDynamicAttributeModel(buBadnessType.getBadnessTypeName() + "发生次数", MesExtConstWords.QTY + buBadnessType.getBadnessTypeCode()));
        }
    }

    private List<JxOqcCheckReportModel> getOqcCheckList4QualityEarlyWarning(JxOqcCheckQualityEarlyWarningReportModel model) {
        List<JxOqcCheckReportModel> resultList = null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue(), MesExtConstWords.CHECK_RESULT, packBean);
        DdlPreparedPack.timeBuilder(model.getCheckTimeStart(), model.getCheckTimeEnd(), MesExtConstWords.CHECK_TIME, packBean, true);
        List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(oqcCheckList)) return resultList;

        Map<String, List<MesBadnessType>> badnessTypeMap = buBadnessTypeService.getBadnessTypeMap(model.getOrganizeCode());
        Map<String, List<MesBadnessClassify>> badnessClassifyMap = badnessClassifyService.getBadnessClassifyMap(model.getOrganizeCode());

        for (MesOqcCheck oqcCheck : oqcCheckList) {
            if (null == oqcCheck || StringUtils.isEmpty(oqcCheck.getBadnessTypeCode())) continue;

            if (CollectionUtils.isEmpty(resultList)) resultList = new ArrayList<>();

            JxOqcCheckReportModel result = packResult4OqcCheckReport(oqcCheck, badnessTypeMap, badnessClassifyMap);

            if (StringUtils.isEmpty(result.getSerialNumber())) result.setSerialNumber(MesExtConstWords.ONE_SPACE);

            if (StringUtils.isEmpty(result.getBadnessClassifyDetailName())) result.setBadnessClassifyDetailName(MesExtConstWords.ONE_SPACE);

            resultList.add(result);

        }

        return resultList;
    }

    private void packWorkTime4QualityEarlyWarningReport(List<JxOqcCheckReportModel> oqcCheckList, JxOqcCheckQualityEarlyWarningReportModel model) {
        oqcCheckList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()))).forEach(o -> {
            if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH_OR_YAER.YEAR.getValue() == model.getDimension()) {
                o.setWorkTimeBak(o.getWorkTime().substring(0, 4));
            } else if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH_OR_YAER.MONTH.getValue() == model.getDimension()) {
                o.setWorkTimeBak(o.getWorkTime().substring(0, 7));
            } else {
                o.setWorkTimeBak(o.getWorkTime());
            }
        });
    }

    private Map<String, List<JxOqcCheckReportModel>> packMap4QualityEarlyWarningReport(List<JxOqcCheckReportModel> oqcCheckList, Integer dimension) {
        Map<String, List<JxOqcCheckReportModel>> dataMap;
        switch (MesExtEnumUtil.REPORT_DIMENSION_DATE_OR_CENTER.getByValue(dimension)) {
            case CENTER:
                dataMap = oqcCheckList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTimeBak()) && !StringUtils.isEmpty(o.getWorkCenterCode())))
                        .collect(Collectors.groupingBy(o -> new StringJoiner(MesExtConstWords.AND).add(o.getWorkTimeBak()).add(o.getWorkCenterCode()).toString()));
                break;
            case DATE:
            default:
                dataMap = oqcCheckList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTimeBak()))).collect(Collectors.groupingBy(JxOqcCheckReportModel::getWorkTimeBak));
                break;
        }
        return dataMap;
    }

    private Map<String, String> getCenterMap4QualityEarlyWarningReport(JxOqcCheckQualityEarlyWarningReportModel model) {
        if (MesExtEnumUtil.REPORT_DIMENSION_DATE_OR_CENTER.DATE.getValue() == model.getDimension1()) return null;

        List<MesWorkCenterExt> workCenterExtList = workCenterExtRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue()});

        workCenterExtList = CollectionUtils.isEmpty(workCenterExtList) ? null :
                workCenterExtList.stream().filter(o -> null != o).distinct().collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesWorkCenterExt::getWorkCenterCode))), ArrayList::new)
                );
        return CollectionUtils.isEmpty(workCenterExtList) ? null :
                workCenterExtList.stream().filter(o -> null != o).collect(Collectors.toMap(MesWorkCenterExt::getWorkCenterCode, MesWorkCenterExt::getWorkCenterName));
    }

    private List<Map<String, Object>> packDataList4QualityEarlyWarningReport(Map<String, List<JxOqcCheckReportModel>> dataMap,
                                                                             List<MesBadnessType> badnessTypeList, Map<String, String> centerMap, Integer dimension) {
        List<Map<String, Object>> dataList = new ArrayList<>();
        Map<String, Integer> typeQtyMaxMap = new HashMap<>();
        Integer typeQty;
        for (Map.Entry<String, List<JxOqcCheckReportModel>> entry : dataMap.entrySet()) {
            if (null == entry) continue;

            String[] keyArr = entry.getKey().split(MesExtConstWords.AND);

            Map<String, Object> data = new HashMap<>();
            data.put(MesExtConstWords.HAPPEN_TIME, keyArr[0]);

            if (keyArr.length == 2) {
                data.put(MesExtConstWords.WORK_CENTER_CODE, keyArr[1]);
                data.put(MesExtConstWords.WORK_CENTER_NAME, (!CollectionUtils.isEmpty(centerMap) && centerMap.containsKey(keyArr[1])) ? centerMap.get(keyArr[1]) : null);
            }

            Map<String, List<JxOqcCheckReportModel>> itemMap = entry.getValue().stream()
                    .filter(o -> null != o).collect(Collectors.groupingBy(JxOqcCheckReportModel::getBadnessTypeCode));

            //当前批次总数量
            int qty = 0;

            for (MesBadnessType badnessType : badnessTypeList) {
                if (null == badnessType) continue;

                typeQty = itemMap.containsKey(badnessType.getBadnessTypeCode()) ? getTypeQty(itemMap.get(badnessType.getBadnessTypeCode())) : MesExtConstWords.ZERO;
                data.put(MesExtConstWords.QTY + badnessType.getBadnessTypeCode(), typeQty);

                qty += typeQty;

                if (!typeQtyMaxMap.containsKey(badnessType.getBadnessTypeCode()) || typeQtyMaxMap.get(badnessType.getBadnessTypeCode()).compareTo(typeQty) < 0) {
                    typeQtyMaxMap.put(badnessType.getBadnessTypeCode(), typeQty);
                }
            }
            data.put(MesExtConstWords.QTY, qty);
            data.put(MesExtConstWords.DETAIL_LIST, sortDetailList4OqcCheckStatistics(entry.getValue()));

            dataList.add(data);
        }

        dataList = sortDataList4QualityEarlyWarningReport(dataList, dimension);

        for (int i = 0; i < dataList.size(); i ++) {
            if (null == dataList.get(i)) continue;

            for (MesBadnessType badnessType : badnessTypeList) {
                if (null == badnessType) continue;

                if (typeQtyMaxMap.get(badnessType.getBadnessTypeCode()).compareTo((Integer)(dataList.get(i).get(MesExtConstWords.QTY + badnessType.getBadnessTypeCode()))) == 0) {
                    dataList.get(i).put(MesExtConstWords.COLOR,
                            StringUtils.isEmpty(dataList.get(i).get(MesExtConstWords.COLOR)) ? (MesExtConstWords.QTY + badnessType.getBadnessTypeCode()) :
                                    new StringJoiner(MesExtConstWords.COMMA).add(dataList.get(i).get(MesExtConstWords.COLOR).toString()).add(MesExtConstWords.QTY + badnessType.getBadnessTypeCode()).toString());
                }
            }

            if (i == 0) {
                dataList.get(i).put(MesExtConstWords.COLOR,
                        StringUtils.isEmpty(dataList.get(i).get(MesExtConstWords.COLOR)) ? MesExtConstWords.QTY :
                                new StringJoiner(MesExtConstWords.COMMA).add(dataList.get(i).get(MesExtConstWords.COLOR).toString()).add(MesExtConstWords.QTY).toString());
            }
        }

        return dataList;
    }

    private Object getQty(List<JxOqcCheckReportModel> itemList) {
        Map<String, List<JxOqcCheckReportModel>> itemMap = itemList.stream().filter(o -> null != o).collect(
                Collectors.groupingBy(o -> new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).toString()));
        return CollectionUtils.isEmpty(itemMap) ? MesExtConstWords.ZERO : itemMap.size();
    }

    private Integer getTypeQty(List<JxOqcCheckReportModel> itemList) {
        Map<String, List<JxOqcCheckReportModel>> typeGroupMap = itemList.stream().filter(o -> null != o).collect(
                Collectors.groupingBy(o -> new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).add(o.getWorkTime()).add(o.getBadnessTypeCode()).toString()));
        return CollectionUtils.isEmpty(typeGroupMap) ? MesExtConstWords.ZERO : typeGroupMap.size();
    }


    private List<Map<String, Object>> sortDataList4QualityEarlyWarningReport(List<Map<String, Object>> dataList, Integer dimension) {
        switch (MesExtEnumUtil.REPORT_DIMENSION_DATE_OR_CENTER.getByValue(dimension)) {
            case CENTER:
                dataList = dataList.stream().sorted(Comparator.comparing(JxOqcReportFormService::comparingByQty4QualityEarlyWarningReport).reversed()
                        .thenComparing(JxOqcReportFormService::comparingByDate4QualityEarlyWarningReport)
                        .thenComparing(JxOqcReportFormService::comparingByCenter4QualityEarlyWarningReport)).collect(Collectors.toList());
                break;
            case DATE:
            default:
                dataList = dataList.stream().sorted(Comparator.comparing(JxOqcReportFormService::comparingByQty4QualityEarlyWarningReport).reversed()
                        .thenComparing(JxOqcReportFormService::comparingByDate4QualityEarlyWarningReport)).collect(Collectors.toList());
                break;
        }
        return dataList;
    }

    private static Integer comparingByQty4QualityEarlyWarningReport(Map<String, Object> map) {
        return (Integer)(map.get(MesExtConstWords.QTY));
    }

    private static String comparingByDate4QualityEarlyWarningReport(Map<String, Object> map) {
        return (String) map.get(MesExtConstWords.HAPPEN_TIME);
    }

    private static String comparingByCenter4QualityEarlyWarningReport(Map<String, Object> map) {
        return (String) map.get(MesExtConstWords.WORK_CENTER_CODE);
    }

    @Override
    public ListPager<JxOqcLastCheckDetailReportModel> queryOqcLastCheckDetailReportPager(JxOqcLastCheckDetailReportModel model, Pager pager) {

        pager = PagerHelper.getPager(pager, outPutStatisticsDao.queryOqcLastCheckDetailPagerCount(model));
        List<JxOqcLastCheckDetailReportModel> resultList = outPutStatisticsDao.queryOqcLastCheckDetailPager(model , pager);

        if (!CollectionUtils.isEmpty(resultList)) {

            List<String> workOrderNoList = resultList.stream().filter(o -> null != o).map(JxOqcLastCheckDetailReportModel::getWorkOrderNo).collect(Collectors.toList());

            if (workOrderNoList.size() == 1) model.setWorkOrderNo(workOrderNoList.get(0));

            //获取PCN 产量统计数据
            List<JxOutPutStatisticsQtyModel> outPutStatisticsQtyList = getJxOutPutStatisticsQtyModels(model);
            Map<String, Double> outPutStatisticsMap = getOutPutStatisticsMap4OqcLastCheckDetail(outPutStatisticsQtyList);

            Map<String, Double> unFinishQtyMap = getOutPutStatisticsUnFinishMap4OqcLastCheckDetail(outPutStatisticsQtyList);

            DdlPackBean packBean = getDdlPackBean4OqcLastCheckDetail(model);

            Map<String, List<MesOqcCheck>> oqcCheckMap = getOqcCheckMap4OqcLastCheckDetail(packBean);
            packBean = getDdlPackBean4OqcLastCheckDetail(model);
            Map<String, List<MesOqcCheckDetail>> oqcCheckDetailMap = getOqcCheckDetailMap4OqcLastCheckDetail(packBean);

            Map<String, List<MesBadnessType>> badnessTypeMap = buBadnessTypeService.getBadnessTypeMap(model.getOrganizeCode());

            Map<String, List<MesBadnessClassify>> badnessClassifyMap = badnessClassifyService.getBadnessClassifyMap(model.getOrganizeCode());

            for (JxOqcLastCheckDetailReportModel result : resultList) {
                if (null == result) continue;

                result.setCheckResultName((StringUtils.isEmpty(result.getCheckResult()) || StringUtils.isEmpty(MesExtEnumUtil.OQC_TOTAL_STATUS.valueOfDescription(result.getCheckResult())))
                        ? MesExtEnumUtil.OQC_TOTAL_STATUS.UNTREATED.getDescription() : MesExtEnumUtil.OQC_TOTAL_STATUS.valueOfDescription(result.getCheckResult()));

                result.setWorkOrderTypeName(StringUtils.isEmpty(result.getWorkOrderType()) ? null : MesExtEnumUtil.WORK_ORDER_TYPE.valueOfDescription(result.getWorkOrderType()));

                result.setQty(getQty4OqcLastCheckDetail(outPutStatisticsMap, result));
                result.setUnFinishQty(getQty4OqcLastCheckDetail(unFinishQtyMap, result));

                List<MesOqcCheck> itemList = CollectionUtils.isEmpty(oqcCheckMap) ? null :
                        oqcCheckMap.get(new StringJoiner(MesExtConstWords.AND).add(result.getWorkOrderNo()).add(result.getWorkTime()).add(result.getShiftCode()).toString());

                if (!CollectionUtils.isEmpty(itemList)) {

                    result.setUnQcQty(getUnQcQtyOqcCheck4OqcLastCheckDetail(itemList));

                    result.setDetailList(getDetailList4OqcLastCheckDetail(itemList, oqcCheckDetailMap, badnessTypeMap, badnessClassifyMap));
                }

                /**
                 * 合格：白色底色（不变）
                 *
                 * 不合格：红色（#ff6666）
                 *
                 * 未检验：黄色（#ffd733）
                 */
                if(result.getCheckResult() == null || result.getCheckResult() == MesExtEnumUtil.OQC_TOTAL_STATUS.UNTREATED.getValue()){
                    result.setCheckResultColor("#ffd733");
                }else if(result.getCheckResult() == MesExtEnumUtil.OQC_TOTAL_STATUS.DEFECTED.getValue()){
                    result.setCheckResultColor("#ff6666");
                }else{
                    result.setCheckResultColor("white");
                }
            }
        }

        return new ListPager(resultList, pager);
    }

    private Map<String, Double> getOutPutStatisticsMap4OqcLastCheckDetail(List<JxOutPutStatisticsQtyModel> outPutStatisticsQtyList) {
        return CollectionUtils.isEmpty(outPutStatisticsQtyList) ? null :
                outPutStatisticsQtyList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                        new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).add(o.getShiftCode()).toString(), Collectors.summingDouble(JxOutPutStatisticsQtyModel::getQty)));
    }

    private List<JxOutPutStatisticsQtyModel> getJxOutPutStatisticsQtyModels(JxOqcLastCheckDetailReportModel model) {
        JxOutPutStatisticsQtyModel param = new JxOutPutStatisticsQtyModel();
        BeanUtils.copyProperties(model, param);
        return outPutStatisticsService.queryOutPutStatisticsQtyList(param);
    }

    private Map<String, Double> getOutPutStatisticsUnFinishMap4OqcLastCheckDetail(List<JxOutPutStatisticsQtyModel> outPutStatisticsQtyList) {
        return CollectionUtils.isEmpty(outPutStatisticsQtyList) ? null :
                outPutStatisticsQtyList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o ->
                        new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).add(o.getShiftCode()).toString(), Collectors.summingDouble(JxOutPutStatisticsQtyModel::getUnFinishQty)));
    }

    private DdlPackBean getDdlPackBean4OqcLastCheckDetail(JxOqcLastCheckDetailReportModel model) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getWorkOrderNo(), MesExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getPartNo(), MesExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getNumEqualPack(model.getWorkOrderType(), MesExtConstWords.WORK_ORDER_TYPE, packBean);
        if (!StringUtils.isEmpty(model.getWorkTimeStart()) || !StringUtils.isEmpty(model.getWorkTimeEnd())) {
            DdlPreparedPack.timeBuilder(model.getWorkTimeStart(), model.getWorkTimeEnd(), MesExtConstWords.WORK_TIME, packBean, false);
        }
        return packBean;
    }

    private Map<String, List<MesOqcCheck>> getOqcCheckMap4OqcLastCheckDetail(DdlPackBean packBean) {
        DdlPreparedPack.getNumNOEqualPack(MesExtEnumUtil.OQC_CHECK_TYPE.TEARDOWN_INSPECTION.getValue(), MesExtConstWords.OQC_NO_TYPE, packBean);
        List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWhere(packBean);
        return CollectionUtils.isEmpty(oqcCheckList) ? null :
                oqcCheckList.stream().filter(o -> (null != o))
                        .collect(Collectors.groupingBy(o -> new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).add(o.getShiftCode()).toString()));
    }

    private Map<String, List<MesOqcCheckDetail>> getOqcCheckDetailMap4OqcLastCheckDetail(DdlPackBean packBean) {
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.OQC_CHECK_DETAIL_RESULT.NG.getValue(), MesExtConstWords.CHECK_RESULT, packBean);
        List<MesOqcCheckDetail> oqcCheckDetailList = oqcCheckDetailRepository.findByHqlWhere(packBean);
        return CollectionUtils.isEmpty(oqcCheckDetailList) ? null :
                oqcCheckDetailList.stream().filter(o -> (null != o)).collect(Collectors.groupingBy(MesOqcCheckDetail::getOqcNo));
    }

    private Double getQty4OqcLastCheckDetail(Map<String, Double> outPutStatisticsMap, JxOqcLastCheckDetailReportModel result) {
        return CollectionUtils.isEmpty(outPutStatisticsMap) ? null :
                outPutStatisticsMap.get(new StringJoiner(MesExtConstWords.AND).add(result.getWorkOrderNo()).add(result.getWorkTime()).add(result.getShiftCode()).toString());
    }

    private Integer getUnQcQtyOqcCheck4OqcLastCheckDetail(List<MesOqcCheck> itemList) {
        List<String> unQcList;
        if (!StringUtils.isEmpty(itemList.get(0).getSerialNumber())) {
            //成品
            unQcList = (itemList.stream().filter(o ->
                    (null != o && !StringUtils.isEmpty(o.getCheckResult()) && MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue() == o.getCheckResult()))
                    .map(MesOqcCheck::getSerialNumber).collect(Collectors.toList()))
                    .stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        } else {
            //组件
            unQcList = itemList.stream().filter(o ->
                    (null != o && !StringUtils.isEmpty(o.getCheckResult()) && MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue() == o.getCheckResult()))
                    .map(MesOqcCheck::getOqcNo).collect(Collectors.toList());
        }
        return CollectionUtils.isEmpty(unQcList) ? MesExtConstWords.ZERO : unQcList.size();
    }

    private List<JxOqcLastCheckDetailReportModel> getDetailList4OqcLastCheckDetail(List<MesOqcCheck> itemList, Map<String, List<MesOqcCheckDetail>> oqcCheckDetailMap,
                                                                                   Map<String, List<MesBadnessType>> badnessTypeMap, Map<String, List<MesBadnessClassify>> badnessClassifyMap) {
        List<JxOqcLastCheckDetailReportModel> detailList = new ArrayList<>();
        for (MesOqcCheck oqcCheck : itemList) {
            if (null == oqcCheck) continue;

            JxOqcLastCheckDetailReportModel detail = new JxOqcLastCheckDetailReportModel();
            BeanUtils.copyProperties(oqcCheck, detail);
            detail.setOqcNoTypeName(MesExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(detail.getOqcNoType()));
            detail.setSnTypeName(MesExtEnumUtil.OQC_MANAGE_ACTION_TYPE.valueOfDescription(detail.getSnType()));
            detail.setOqcTypeName(MesExtEnumUtil.OQC_TYPE.valueOfDescription(detail.getOqcType()));
            detail.setCheckResultName(!StringUtils.isEmpty(detail.getCheckResult()) ? MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(detail.getCheckResult()) : null);
            detail.setBadnessTypeName((!StringUtils.isEmpty(detail.getBadnessTypeCode()) && !CollectionUtils.isEmpty(badnessTypeMap) && badnessTypeMap.containsKey(detail.getBadnessTypeCode())) ?
                    badnessTypeMap.get(detail.getBadnessTypeCode()).get(0).getBadnessTypeName() : null);
            detail.setBadnessClassifyName((!StringUtils.isEmpty(detail.getBadnessTypeCode()) && !StringUtils.isEmpty(detail.getBadnessClassifyCode()) && !CollectionUtils.isEmpty(badnessClassifyMap) &&
                    badnessClassifyMap.containsKey(new StringJoiner(MesExtConstWords.AND).add(detail.getBadnessTypeCode()).add(detail.getBadnessClassifyCode()).toString())) ?
                    badnessClassifyMap.get(new StringJoiner(MesExtConstWords.AND).add(detail.getBadnessTypeCode()).add(detail.getBadnessClassifyCode()).toString()).get(0).getBadnessClassifyName() : null);
            detail.setUnQcQty((!CollectionUtils.isEmpty(oqcCheckDetailMap) && oqcCheckDetailMap.containsKey(oqcCheck.getOqcNo())) ? oqcCheckDetailMap.get(oqcCheck.getOqcNo()).size() : MesExtConstWords.ZERO);
            /**
             * 合格：白色底色（不变）
             *
             * 不合格：红色（#ff6666）
             *
             * 未检验：黄色（#ffd733）
             */
            if(detail.getCheckResult() == null){
                detail.setCheckResultColor("#ffd733");
            }else if(detail.getCheckResult() == MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue()){
                detail.setCheckResultColor("#ff6666");
            }else{
                detail.setCheckResultColor("white");
            }
            detailList.add(detail);
        }
        return detailList;
    }

    @Override
    public ListPager<JxOqcCheckFreConfirmReportModel> queryOqcCheckFreConfirmReportPager(JxOqcCheckFreConfirmReportModel model, Pager pager) {
        List<JxOqcCheckFreConfirmReportModel> resultList = new ArrayList<>();
        DdlPackBean packBean = getDdlPackBean4FreConfirm(model);
        pager = PagerHelper.getPager(pager, errorLineOffRepository.findByHqlWhereCount(packBean));
        packBean.setOrderByStr(MesExtConstWords.ORDER_BY_MDT_DESC);
        List<MesErrorLineOff> errorLineOffList = errorLineOffRepository.findByHqlWherePage(packBean, pager);
        if (!CollectionUtils.isEmpty(errorLineOffList)) {
            for (MesErrorLineOff errorLineOff : errorLineOffList) {
                if (null == errorLineOff) {
                    continue;
                }
                JxOqcCheckFreConfirmReportModel result = new JxOqcCheckFreConfirmReportModel();
                BeanUtils.copyProperties(errorLineOff, result);
                result.setPartNameRdd(errorLineOff.getPartName());
                result.setFreStatusName(StringUtils.isEmpty(result.getFreStatus()) ? null :MesExtEnumUtil.TRUE_OR_FALSE.valueOfDescription(result.getFreStatus()));
                result.setConfirmStatusName(StringUtils.isEmpty(result.getConfirmStatus()) ? null :MesExtEnumUtil.TRUE_OR_FALSE.valueOfDescription(result.getConfirmStatus()));
                result.setIdStr(errorLineOff.getId().toString());
                resultList.add(result);
            }
        }
        return new ListPager(resultList, pager);
    }

    private DdlPackBean getDdlPackBean4FreConfirm(JxOqcCheckFreConfirmReportModel model) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(model.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(model.getWorkOrderNo(), MesExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getPartNo(), MesExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringLikerPack(model.getSerialNumber(), MesExtConstWords.SERIAL_NUMBER, packBean);
        DdlPreparedPack.getNumEqualPack(model.getFreStatus(), MesExtConstWords.FRE_STATUS, packBean);
        DdlPreparedPack.getNumEqualPack(model.getConfirmStatus(), MesExtConstWords.CONFIRM_STATUS, packBean);
        if (!StringUtils.isEmpty(model.getOutWcTimeStart()) || !StringUtils.isEmpty(model.getOutWcTimeEnd())) {
            DdlPreparedPack.timeBuilder(model.getOutWcTimeStart(), model.getOutWcTimeEnd(), MesExtConstWords.OUT_WC_TIME, packBean, true);
        }
        if (!StringUtils.isEmpty(model.getFreTimeStart()) || !StringUtils.isEmpty(model.getFreTimeEnd())) {
            DdlPreparedPack.timeBuilder(model.getFreTimeStart(), model.getFreTimeEnd(), MesExtConstWords.FRE_TIME, packBean, true);
        }
        if (!StringUtils.isEmpty(model.getConfirmTimeStart()) || !StringUtils.isEmpty(model.getConfirmTimeEnd())) {
            DdlPreparedPack.timeBuilder(model.getConfirmTimeStart(), model.getConfirmTimeEnd(), MesExtConstWords.CONFIRM_TIME, packBean, true);
        }
        return packBean;
    }

    @Override
    public List<JxOqcCheckFreConfirmDetailReportModel> queryOqcCheckFreConfirmDetailReport(JxOqcCheckFreConfirmDetailReportModel model) {
        List<JxOqcCheckFreConfirmDetailReportModel> resultList = null;
        List<MesErrorLineOffDetail> errorLineOffDetailList = errorLineOffDetailRepository.findByProperty(new String[]{MesExtConstWords.PID}, new Object[]{Long.parseLong(model.getIdStr())});
        if (!CollectionUtils.isEmpty(errorLineOffDetailList)) {
            for (MesErrorLineOffDetail errorLineOffDetail : errorLineOffDetailList) {
                if (null == errorLineOffDetail) {
                    continue;
                }
                JxOqcCheckFreConfirmDetailReportModel result = new JxOqcCheckFreConfirmDetailReportModel();
                BeanUtils.copyProperties(errorLineOffDetail, result);
                result.setPartNo(model.getPartNo());
                result.setPartNameRdd(model.getPartNameRdd());
                if (CollectionUtils.isEmpty(resultList)) {
                    resultList = new ArrayList<>();
                }
                resultList.add(result);
            }
        }
        return resultList;
    }

    @Override
    public JxOqcCheckStatisticsReportModel queryOqcCheckStatisticsReport(JxOqcCheckStatisticsReportModel model) {
        log.info("出货检验月报日报,参数[{}]", model.toBaseString());

        List<MesBadnessType> badnessTypeList = buBadnessTypeService.getBadnessTypeList(model.getOrganizeCode());

        packAttributeList4OqcCheckStatistics(model, badnessTypeList);

        model.setNeqWorkOrderType(MesExtEnumUtil.WORK_ORDER_TYPE.ATTEMPT_ORDER.getValue());     //过滤试制工单
        List<JxOqcCheckStatisticsReportModel> modelList = outPutStatisticsDao.queryOqcCheckStatisticsList(model);

        if (CollectionUtils.isEmpty(modelList)) return model;

        log.info("出货检验月报日报,modelList数据量[{}]", modelList.size());

        Map<String, Double> outPutStatisticsMap = getOutPutStatisticsMap4OqcCheckStatistics(model);

        log.info("出货检验月报日报,outPutStatisticsMap数据量[{}]", CollectionUtils.isEmpty(outPutStatisticsMap) ? MesExtConstWords.ZERO : outPutStatisticsMap.size());

        packOqcCheckStatisticsWorkTime(modelList, outPutStatisticsMap, model);

        Map<String, List<JxOqcCheckStatisticsReportModel>> modelMap = packOqcCheckStatisticsMap(modelList, model.getDimension1());

        if (CollectionUtils.isEmpty(modelMap)) return model;

        List<JxOqcCheckReportModel> oqcCheckList = oqcCheckReportDao.queryUnQcOqcCheckListByPart(model);

        log.info("出货检验月报日报,oqcCheckList数据量[{}]", CollectionUtils.isEmpty(oqcCheckList) ? MesExtConstWords.ZERO : oqcCheckList.size());

        packOqcCheckListWorkTime4OqcCheckStatistics(oqcCheckList, model);

        Map<String, List<JxOqcCheckReportModel>> oqcCheckMap = CollectionUtils.isEmpty(oqcCheckList) ? null : packOqcCheckMap4OqcCheckStatistics(oqcCheckList, model.getDimension1());

        packResult4OqcCheckStatistics(model, modelMap, oqcCheckMap, badnessTypeList);

        log.info("出货检验月报日报,封装数据完成");

        sortDataList4OqcCheckStatistics(model);

        return model;
    }

    @Override
    public ListPager<JxOqcCheckReportModel> queryOqcCheckPager(JxOqcCheckReportModel model, Pager pager) {
        List<JxOqcCheckReportModel> resultList = new ArrayList<>();
        DdlPackBean hqlPack = MesExtHqlPack.getOqcCheck(model);
        pager = PagerHelper.getPager(pager, oqcCheckRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(" order by createDatetime desc ");
        List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByHqlWherePage(hqlPack, pager);
        if (!CollectionUtils.isEmpty(oqcCheckList)) {

            Map<String, List<MesBadnessType>> badnessTypeMap = buBadnessTypeService.getBadnessTypeMap(model.getOrganizeCode());
            Map<String, List<MesBadnessClassify>> badnessClassifyMap = badnessClassifyService.getBadnessClassifyMap(model.getOrganizeCode());

            for (MesOqcCheck oqcCheck : oqcCheckList) {
                if (null == oqcCheck) {
                    continue;
                }
                resultList.add(packResult4OqcCheckReport(oqcCheck, badnessTypeMap, badnessClassifyMap));
            }
        }
        return new ListPager(resultList, pager);
    }

    //@Override
    //public ListPager queryOqcCheckTravelPager(MesOqcCheckTravel travel, Pager pager) {
    //    DdlPackBean hqlPack = MesExtHqlPack.getOqcCheckTravel(travel);
    //    pager = PagerHelper.getPager(pager, oqcCheckTravelRepository.findByHqlWhereCount(hqlPack));
    //    hqlPack.setOrderByStr(travel.orderBy());
    //    List<MesOqcCheckTravel> oqcCheckTravelList = oqcCheckTravelRepository.findByHqlWherePage(hqlPack, pager);
    //    return new ListPager(oqcCheckTravelList, pager);
    //}

    @Override
    public void updateOqcCheckResult(JxOqcCheckReportModel model, String userName) {
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getById(model.getId());
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单ID[%s]数据不存在", model.getId())
                    .build();
        }
        if (StringUtils.isEmpty(oqcCheckDb.getCheckResult()) || StringUtils.isEmpty(MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult()))) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]还未进行完出货检验,不能进行检验结果更改", oqcCheckDb.getOqcNo())
                    .build();
        }
        if (oqcCheckDb.getCheckResult() == model.getCheckResult() && oqcCheckDb.getCheckResult() == MesExtEnumUtil.OQC_CHECK_RESULT.QUALIFIED.getValue()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]已经是[%s]状态,操作失败",
                            oqcCheckDb.getOqcNo(), MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult()))
                    .build();
        }

        // 如果当前检验单已经为不合格，则不修改出货检验条码关联表数据，只修改不良数据。
        if(oqcCheckDb.getCheckResult() == model.getCheckResult() && oqcCheckDb.getCheckResult() == MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue()){
            oqcCheckDb.setBadnessTypeCode(model.getBadnessTypeCode());
            oqcCheckDb.setBadnessClassifyCode(model.getBadnessClassifyCode());
            oqcCheckDb.setBadnessClassifyDetailCode(model.getBadnessClassifyDetailCode());
            oqcCheckDb.setBadnessClassifyDetailName(model.getBadnessClassifyDetailName());
            oqcCheckDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            oqcCheckRepository.save(oqcCheckDb);
            insertOqcCheckTravel(userName, oqcCheckDb);
            return;
        }

        oqcCheckDb.setCheckResult(model.getCheckResult());
        if(oqcCheckDb.getCheckResult() == MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getValue()){
            oqcCheckDb.setBadnessTypeCode(model.getBadnessTypeCode());
            oqcCheckDb.setBadnessClassifyCode(model.getBadnessClassifyCode());
            oqcCheckDb.setBadnessClassifyDetailCode(model.getBadnessClassifyDetailCode());
            oqcCheckDb.setBadnessClassifyDetailName(model.getBadnessClassifyDetailName());
        }else{
            oqcCheckDb.setBadnessTypeCode("");
            oqcCheckDb.setBadnessClassifyCode("");
            oqcCheckDb.setBadnessClassifyDetailCode("");
            oqcCheckDb.setBadnessClassifyDetailName("");
        }

        ConvertBean.serviceModelUpdate(oqcCheckDb, userName);
        oqcCheckDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        oqcCheckRepository.save(oqcCheckDb);
        insertOqcCheckTravel(userName, oqcCheckDb);

        List<MesOqcCheckPackageDetail> oqcCheckPackageDetails = oqcCheckPackageDetailRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{oqcCheckDb.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), oqcCheckDb.getOqcNo()});

        List<MesOqcCheckPackageDetailTravel> oqcCheckPackageDetailTravels = new ArrayList<>();
        if(!CollectionUtils.isEmpty(oqcCheckPackageDetails)){
            oqcCheckPackageDetails.stream().forEach(sxQmsOqcCheckPackageDetail -> {
                sxQmsOqcCheckPackageDetail.setCheckResult(model.getCheckResult());

                MesOqcCheckPackageDetailTravel oqcCheckPackageDetailTravel = new MesOqcCheckPackageDetailTravel();
                BeanUtils.copyProperties(sxQmsOqcCheckPackageDetail, oqcCheckPackageDetailTravel);
                ConvertBean.serviceModelInitialize(oqcCheckPackageDetailTravel, userName);
                oqcCheckPackageDetailTravel.setLastCheckResult(model.getCheckResult());
                oqcCheckPackageDetailTravel.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
                oqcCheckPackageDetailTravels.add(oqcCheckPackageDetailTravel);
            });

            //新增出货检验管理条码履历信息
            oqcCheckPackageDetailTravelRepository.saveAll(oqcCheckPackageDetailTravels);
        }

        //修改检验结果 同步给 WMS

        //List<MesOqcCheckPackageIf> oqcCheckPackageIfList = oqcCheckPackageIfRepository.findByProperty(new String[]{MesExtConstWords.OQC_NO, MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_VALID, MesExtConstWords.IS_DELETED},
        //        new Object[]{oqcCheckDb.getOqcNo(), oqcCheckDb.getOrganizeCode(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), CommonEnumUtil.IS_DEAL.NO.getValue()});
        //if(!CollectionUtils.isEmpty(oqcCheckPackageIfList)) {
        //    String nowTime = TimeTool.getNowTime(true);
        //    oqcCheckPackageIfList.forEach(o -> {
        //        o.setCheckResult(model.getCheckResult());
        //        o.setModifyDatetime(nowTime);
        //        o.setModifyUser(userName);
        //        o.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        //        o.setSystemSyncStatus2(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        //    });
        //    oqcCheckPackageIfRepository.saveAll(oqcCheckPackageIfList);
        //    //reworkRangeService.saveReworkRangeByFinishProdAndDailyInspAndEmpInspAndCheckNG(oqcCheckDb, oqcCheckPackageIfList, null, false);
        //}

        oqcCheckPackageIfRepository.updateByProperties(new String[]{MesExtConstWords.OQC_NO, MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_VALID, MesExtConstWords.IS_DELETED},
                new Object[]{ oqcCheckDb.getOqcNo(), oqcCheckDb.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()},
                new String[]{MesExtConstWords.SYSTEM_SYNC_STATUS, "systemSyncStatus2", MesExtConstWords.CHECK_RESULT, MesExtConstWords.MODIFY_USER, MesExtConstWords.MODIFY_DATE_TIME, MesExtConstWords.SYSTEM_SYNC_STATUS},
                new Object[]{MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue(), MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue(), model.getCheckResult(), userName, TimeTool.getNowTime(true), MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue()});

    }

    private void insertOqcCheckTravel(String userName, MesOqcCheck oqcCheckDb) {
        MesOqcCheckTravel oqcCheckTravel = new MesOqcCheckTravel();
        BeanUtils.copyProperties(oqcCheckDb, oqcCheckTravel, MesExtConstWords.ID, MesExtConstWords.CREATE_USER, MesExtConstWords.MODIFY_USER, MesExtConstWords.CREATE_DATE_TIME, MesExtConstWords.MODIFY_DATE_TIME);
        ConvertBean.serviceModelInitialize(oqcCheckTravel, userName);
        oqcCheckTravelRepository.save(oqcCheckTravel);
    }

    @Override
    public List<JxOqcPackageDetailModel> queryOqcPackageDetailList(JxOqcCheckReportModel model) {
        List<JxOqcPackageDetailModel> resultList = null;
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getById(model.getId());
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单ID[%s]数据不存在", model.getId())
                    .build();
        }
        List<MesOqcCheckPackageDetail> oqcPackageDetailList = oqcCheckPackageDetailRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), oqcCheckDb.getOqcNo()},
                " order by createDatetime asc, serialNumber asc ");
        if (CollectionUtils.isEmpty(oqcPackageDetailList)) {
            return resultList;
        }
        if (!StringUtils.isEmpty(model.getBatchLimitStart())) {
            if (model.getBatchLimitStart().compareTo(0) < 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围起始必须大于0")
                        .build();
            }
        }
        if (!StringUtils.isEmpty(model.getBatchLimitEnd())) {
            if (model.getBatchLimitEnd().compareTo(0) < 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围截止必须大于0")
                        .build();
            }
        }
        if (!StringUtils.isEmpty(model.getBatchLimitStart()) && !StringUtils.isEmpty(model.getBatchLimitEnd())) {
            if (model.getBatchLimitStart().compareTo(model.getBatchLimitEnd()) > 0) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("抽检范围起始必须小于等于抽检范围截止")
                        .build();
            }
        }

        BuNumberRuleModel numberRuleModel = buBaseDataService.queryMesSnRule(model.getOrganizeCode(),
                oqcCheckDb.getPartNo(),
                MesExtEnumUtil.ENCODE_CODE_TYPE.PACK_SN.getValue(),
                MesExtEnumUtil.ENCODE_MATCH_TYPE.PART.getValue());

        if(numberRuleModel == null){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.QMS.getCode())
                    .setErrorCode(ImppExceptionEnum.IO_EXCEPTION_FILE.getCode())
                    .setErrorDetail("物料编码{}未配置生产编码规则",oqcCheckDb.getPartNo())
                    .build();
        }

        if (!StringUtils.isEmpty(numberRuleModel.getRuleLengthSpilt())) {
            //编码规则
            String[] serialNoArray = numberRuleModel.getNumberRule().split("}\\{");
            //规则属性长度拼接
            String[] ruleLengthSpiltArray = numberRuleModel.getRuleLengthSpilt().split(",");
            String serialNoStr = "serialno";
            int serialNoIndex = -1;
            for (int index = 0; index < serialNoArray.length; index++) {
                if(serialNoArray[index].contains(serialNoStr)) serialNoIndex = index;
            }

            int ruleLengthTotal = 0;
            if(serialNoIndex != -1){
                for (int index = 0; index < serialNoIndex; index++) {
                    ruleLengthTotal += Integer.parseInt(ruleLengthSpiltArray[index]);
                }
            }
            int finalRuleLengthTotal = ruleLengthTotal;
            int finalSerialNoIndex = serialNoIndex;

            if (!StringUtils.isEmpty(model.getBatchLimitStart()) && !StringUtils.isEmpty(model.getBatchLimitEnd())) {
                oqcPackageDetailList = oqcPackageDetailList.stream().filter(oqcCheckPackageDetail ->
                        model.getBatchLimitStart() <= Integer.parseInt(oqcCheckPackageDetail.getSerialNumber().substring(finalRuleLengthTotal, finalRuleLengthTotal + Integer.parseInt(ruleLengthSpiltArray[finalSerialNoIndex]))) &&
                                model.getBatchLimitEnd() >= Integer.parseInt(oqcCheckPackageDetail.getSerialNumber().substring(finalRuleLengthTotal, finalRuleLengthTotal + Integer.parseInt(ruleLengthSpiltArray[finalSerialNoIndex])))
                ).collect(Collectors.toList());
            } else if(!StringUtils.isEmpty(model.getBatchLimitStart())){
                oqcPackageDetailList = oqcPackageDetailList.stream().filter(oqcCheckPackageDetail ->
                        model.getBatchLimitStart() <= Integer.parseInt(oqcCheckPackageDetail.getSerialNumber().substring(finalRuleLengthTotal, finalRuleLengthTotal + Integer.parseInt(ruleLengthSpiltArray[finalSerialNoIndex])))
                ).collect(Collectors.toList());
            } else if(!StringUtils.isEmpty(model.getBatchLimitEnd())){
                oqcPackageDetailList = oqcPackageDetailList.stream().filter(oqcCheckPackageDetail ->
                        model.getBatchLimitEnd() >= Integer.parseInt(oqcCheckPackageDetail.getSerialNumber().substring(finalRuleLengthTotal, finalRuleLengthTotal + Integer.parseInt(ruleLengthSpiltArray[finalSerialNoIndex])))
                ).collect(Collectors.toList());
            }
        }

        if (!StringUtils.isEmpty(model.getSerialNumber())) {
            oqcPackageDetailList = oqcPackageDetailList.stream().filter(o -> (null != o && o.getSerialNumber().equals(model.getSerialNumber()))).collect(Collectors.toList());
        }
        if (!StringUtils.isEmpty(model.getPackageNo())) {
            oqcPackageDetailList = oqcPackageDetailList.stream().filter(o -> (null != o && o.getPackageNo().equals(model.getPackageNo()))).collect(Collectors.toList());
        }

        if (!CollectionUtils.isEmpty(oqcPackageDetailList)) {
            for (MesOqcCheckPackageDetail item : oqcPackageDetailList) {
                if (null == item) {
                    continue;
                }

                JxOqcPackageDetailModel result = new JxOqcPackageDetailModel();
                BeanUtils.copyProperties(item, result);
                result.setCheckResultName(StringUtils.isEmpty(item.getCheckResult())
                        ? MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult())
                        : MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(item.getCheckResult()));
                result.setOrderNo(item.getWorkOrderNo());
                if (CollectionUtils.isEmpty(resultList)) {
                    resultList = new ArrayList<>();
                }
                resultList.add(result);
            }
        }
        return resultList;
    }

    @Override
    public void updateOqcCheckDetailRemark(JxOqcCheckDetailReportModel detail, String userName) {
        MesOqcCheckDetail oqcCheckDetailDb = oqcCheckDetailRepository.getById(Long.parseLong(detail.getIdStr()));
        if (null == oqcCheckDetailDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单项目ID[%s]数据不存在", detail.getIdStr())
                    .build();
        }
        oqcCheckDetailDb.setRemark(detail.getRemark());
        ConvertBean.serviceModelUpdate(oqcCheckDetailDb, userName);
        oqcCheckDetailDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        oqcCheckDetailRepository.save(oqcCheckDetailDb);
    }

    @Override
    public void updateOqcCheckReportOqcQty(JxOqcCheckReportModel model, String userName) {
        List<JxOutPutStatisticsModel> buOutPutStatisticsQtyModel = getJxOutPutStatisticsQtyModel(model);
        List<MesOqcCheck> oqcCheckList = oqcCheckRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.WORK_ORDER_NO,MesExtConstWords.SHIFT_CODE,MesExtConstWords.WORK_TIME},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getWorkOrderNo(),model.getShiftCode(),model.getWorkTime()});
        double sumOqcQty = oqcCheckList.stream().filter(oqc -> !oqc.getOqcNo().equals(model.getOqcNo())).mapToDouble(MesOqcCheck::getOqcQty).sum() + model.getOqcQty();
        double sumCompleteQty = buOutPutStatisticsQtyModel.stream().mapToDouble(JxOutPutStatisticsModel::getQty).sum();
        if(sumOqcQty > sumCompleteQty){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单项目工单号[%s]检测范围合计大于工单生产数量,合计数量为[%s],生产数量[%s]", model.getWorkOrderNo(),sumOqcQty,sumCompleteQty)
                    .build();
        }
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getById(model.getId());
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单项目ID[%s]数据不存在", model.getId())
                    .build();
        }
        statisticsOqcRepository.updateByProperties(
                new String[]{MesExtConstWords.WORK_ORDER_NO,MesExtConstWords.WORK_TIME,MesExtConstWords.SHIFT_CODE,MesExtConstWords.IS_DELETED, MesExtConstWords.ORGANIZE_CODE,},
                new Object[]{model.getWorkOrderNo(),model.getWorkTime(),model.getShiftCode(),CommonEnumUtil.IS_DEAL.NO.getValue(),model.getOrganizeCode()},
                new String[]{MesExtConstWords.SYSTEM_SYNC_STATUS, "checkLimit",MesExtConstWords.MODIFY_USER,MesExtConstWords.MODIFY_DATE_TIME},
                new Object[]{MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue(), sumOqcQty,userName, TimeTool.getNowTime(true)});

        oqcCheckDb.setOqcQty(model.getOqcQty());
        ConvertBean.serviceModelUpdate(oqcCheckDb, userName);
        oqcCheckDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        oqcCheckRepository.save(oqcCheckDb);
    }

    private List<JxOutPutStatisticsModel> getJxOutPutStatisticsQtyModel(JxOqcCheckReportModel model) {
        OqcLastCheckModel param = new OqcLastCheckModel();
        param.setOrganizeCode(model.getOrganizeCode());
        param.setShiftCode(model.getShiftCode());
        param.setWorkCenterCode(model.getWorkCenterCode());
        param.setWorkOrderNo(model.getWorkOrderNo());
        param.setPartNo(model.getPartNo());
        param.setWorkTimeStart(model.getWorkTime());
        param.setWorkTimeEnd(model.getWorkTime());
        return outPutStatisticsService.queryOutPutStatisticsModelList(param,model.getOrganizeCode());
    }

    @Override
    public void updateOqcPackageDetailResult(JxOqcBatchModel model, String userName) {
        if (CollectionUtils.isEmpty(model.getIdList())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("请先勾选产品数据")
                    .build();
        }
        MesOqcCheck oqcCheckDb = oqcCheckRepository.getByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
        if (null == oqcCheckDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]数据不存在", model.getOqcNo())
                    .build();
        }
        if (StringUtils.isEmpty(oqcCheckDb.getCheckResult()) || null == MesExtEnumUtil.OQC_CHECK_RESULT.valueOfDescription(oqcCheckDb.getCheckResult())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("检验单[%s]还未进行完出货检验,不能进行检验结果更改", oqcCheckDb.getOqcNo())
                    .build();
        }

        List<MesOqcCheckPackageDetail> oqcPackageDetailList = oqcCheckPackageDetailRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
        Map<Long, MesOqcCheckPackageDetail> idMap = CollectionUtils.isEmpty(oqcPackageDetailList) ? new HashMap<>() :
                oqcPackageDetailList.stream().filter(o -> null != o).collect(Collectors.toMap(MesOqcCheckPackageDetail::getId, o -> o));

        List<MesOqcCheckPackageIf> oqcCheckPackageIfList = oqcCheckPackageIfRepository.findByProperty(
                new String[]{MesExtConstWords.ORGANIZE_CODE, MesExtConstWords.IS_DELETED, MesExtConstWords.IS_VALID, MesExtConstWords.OQC_NO},
                new Object[]{model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), model.getOqcNo()});
        Map<String, MesOqcCheckPackageIf> snMap = CollectionUtils.isEmpty(oqcCheckPackageIfList) ? new HashMap<>() :
                oqcCheckPackageIfList.stream().filter(o -> null != o).collect(Collectors.toMap(MesOqcCheckPackageIf::getSerialNumber, o -> o));

        List<MesOqcCheckPackageDetail> saveOqcCheckPackageDetailList = new ArrayList<>();
        List<MesOqcCheckPackageIf> saveOqcCheckPackageIfList = new ArrayList<>();
        List<MesOqcCheckPackageDetailTravel> insertOqcCheckPackageDetailTravelList = new ArrayList<>();
        String nowTime = TimeTool.getNowTime(true);
        for (Long id : model.getIdList()) {
            if (StringUtils.isEmpty(id)) {
                continue;
            }
            MesOqcCheckPackageDetail oqcPackageDetail = idMap.get(id);
            if (null == oqcPackageDetail) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("产品ID[%s]数据不存在", id)
                        .build();
            }

            oqcPackageDetail.setCheckResult(model.getCheckResult());
            oqcPackageDetail.setModifyDatetime(nowTime);
            oqcPackageDetail.setModifyUser(userName);
            oqcPackageDetail.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            saveOqcCheckPackageDetailList.add(oqcPackageDetail);

            //oqcCheckPackageDetailRepository.save(oqcPackageDetail);

            MesOqcCheckPackageIf sxQmsOqcCheckPackageIf = snMap.get(oqcPackageDetail.getSerialNumber());
            sxQmsOqcCheckPackageIf.setModifyDatetime(nowTime);
            sxQmsOqcCheckPackageIf.setModifyUser(userName);
            sxQmsOqcCheckPackageIf.setLastCheckResult(model.getCheckResult());
            sxQmsOqcCheckPackageIf.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            sxQmsOqcCheckPackageIf.setSystemSyncStatus2(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            saveOqcCheckPackageIfList.add(sxQmsOqcCheckPackageIf);

            // 修改条码结果 实际修改的是 最终检验结果 并同步给 WMS
            //oqcCheckPackageIfRepository.updateByProperties(new String[]{MesExtConstWords.OQC_NO, MesExtConstWords.SERIAL_NUMBER},
            //        new Object[]{ oqcPackageDetail.getOqcNo(), oqcPackageDetail.getSerialNumber(), model.getOrganizeCode()},
            //        new String[]{MesExtConstWords.LAST_CHECK_RESULT, MesExtConstWords.MODIFY_USER, MesExtConstWords.MODIFY_DATE_TIME, MesExtConstWords.SYSTEM_SYNC_STATUS},
            //        new Object[]{model.getCheckResult(), userName, TimeTool.getNowTime(true), MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue()});

            MesOqcCheckPackageDetailTravel oqcCheckPackageDetailTravel = new MesOqcCheckPackageDetailTravel();
            BeanUtils.copyProperties(oqcPackageDetail, oqcCheckPackageDetailTravel);
            ConvertBean.serviceModelInitialize(oqcCheckPackageDetailTravel, userName);
            oqcCheckPackageDetailTravel.setLastCheckResult(model.getCheckResult());
            oqcCheckPackageDetailTravel.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            insertOqcCheckPackageDetailTravelList.add(oqcCheckPackageDetailTravel);
            //oqcCheckPackageDetailTravelRepository.insert(oqcCheckPackageDetailTravel);

//            //最终检验结果
//            SxQmsOqcLastCheckIf oqcLastCheckIf = new SxQmsOqcLastCheckIf();
//            oqcLastCheckIf.setCheckResult(model.getCheckResult());
//            oqcLastCheckIf.setWorkOrderNo(oqcCheckDb.getWorkOrderNo());
//            oqcLastCheckIf.setOrganizeCode(oqcCheckDb.getOrganizeCode());
//            oqcLastCheckIf.setWorkTime(oqcCheckDb.getWorkTime());
//            oqcLastCheckIf.setShiftCode(oqcCheckDb.getShiftCode());
//            oqcLastCheckIf.setSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
//            ConvertBean.serviceModelInitialize(oqcLastCheckIf, userName);
//            oqcBatchRepository.insert(oqcLastCheckIf);
        }

        if(!CollectionUtils.isEmpty(saveOqcCheckPackageDetailList)) {
            oqcCheckPackageDetailRepository.saveAll(saveOqcCheckPackageDetailList);
            oqcCheckPackageIfRepository.saveAll(saveOqcCheckPackageIfList);
            oqcCheckPackageDetailTravelRepository.saveAll(insertOqcCheckPackageDetailTravelList);
        }

    }


    private void packAttributeList4OqcCheckStatistics(JxOqcCheckStatisticsReportModel model, List<MesBadnessType> badnessTypeList) {
        packBaseAttributeList4OqcCheckStatistics(model);

        if (CollectionUtils.isEmpty(badnessTypeList)) return;

        packDynamicAttributeList4OqcCheckStatistics(model, badnessTypeList);
    }

    private void packBaseAttributeList4OqcCheckStatistics(JxOqcCheckStatisticsReportModel model) {
        model.addAttribute(new SxDynamicAttributeModel("生产日期", MesExtConstWords.WORK_TIME))
                .addAttribute(new SxDynamicAttributeModel("产品类别", MesExtConstWords.CATEGORY_CODE3));

        if (MesExtEnumUtil.REPORT_DIMENSION_CATEGORY_OR_SALESTO_OR_PART.CATEGORY_CODE3.getValue() < model.getDimension1())
            model.addAttribute(new SxDynamicAttributeModel("销售向", MesExtConstWords.SALES_TO_NAME));

        if (MesExtEnumUtil.REPORT_DIMENSION_CATEGORY_OR_SALESTO_OR_PART.PART_NO.getValue() == model.getDimension1())
            model.addAttribute(new SxDynamicAttributeModel("物料编码", MesExtConstWords.PART_NO))
                    .addAttribute(new SxDynamicAttributeModel("物料名称", MesExtConstWords.PART_NAME_RDD));

        model.addAttribute(new SxDynamicAttributeModel("生产批量数", MesExtConstWords.WORK_TIMES_QTY))
                .addAttribute(new SxDynamicAttributeModel("检验批量数", MesExtConstWords.LAST_CHECKED_QTY))
                .addAttribute(new SxDynamicAttributeModel("检验台数", MesExtConstWords.CHECK_AMOUNT_QTY))
                .addAttribute(new SxDynamicAttributeModel("产量", MesExtConstWords.QTY))
                .addAttribute(new SxDynamicAttributeModel("抽样率", MesExtConstWords.SAMPLE_RATE))
                .addAttribute(new SxDynamicAttributeModel("缺点数", MesExtConstWords.UN_QC_QTY))
                .addAttribute(new SxDynamicAttributeModel("不良率", MesExtConstWords.UN_QC_RATE));
    }

    private void packDynamicAttributeList4OqcCheckStatistics(JxOqcCheckStatisticsReportModel model, List<MesBadnessType> badnessTypeList) {
        for (MesBadnessType buBadnessType : badnessTypeList) {
            if (null == buBadnessType) continue;
            model.addAttribute(new SxDynamicAttributeModel(buBadnessType.getBadnessTypeName() + "发生次数", MesExtConstWords.QTY + buBadnessType.getBadnessTypeCode()));
        }
    }

    private Map<String, Double> getOutPutStatisticsMap4OqcCheckStatistics(JxOqcCheckStatisticsReportModel model) {

        JxOutPutStatisticsQtyModel param = new JxOutPutStatisticsQtyModel();
        BeanUtils.copyProperties(model, param);
        List<JxOutPutStatisticsQtyModel> outPutStatisticsQtyList = outPutStatisticsService.queryOutPutStatisticsQtyList(param);

        Map<String, String> params = new HashMap<>();
        params.put(MesExtConstWords.MODEL, JSONObject.toJSONString(model));

        return CollectionUtils.isEmpty(outPutStatisticsQtyList) ? null :
                outPutStatisticsQtyList.stream().filter(o -> null != o).collect(Collectors.toMap(o ->
                        new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).add(o.getShiftCode()).toString(), JxOutPutStatisticsQtyModel::getQty));
    }

    private void packOqcCheckStatisticsWorkTime(List<JxOqcCheckStatisticsReportModel> modelList, Map<String, Double> outPutStatisticsMap, JxOqcCheckStatisticsReportModel model) {
        modelList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()))).forEach(o -> {

            o.setQty((!CollectionUtils.isEmpty(outPutStatisticsMap) &&
                    outPutStatisticsMap.containsKey(new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).add(o.getShiftCode()).toString())) ?
                    outPutStatisticsMap.get(new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTime()).add(o.getShiftCode()).toString()) : new Double(0));

            if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH_OR_YAER.YEAR.getValue() == model.getDimension()) {
                o.setWorkTimeFilter(o.getWorkTime().substring(0, 4));
            } else if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH_OR_YAER.MONTH.getValue() == model.getDimension()) {
                o.setWorkTimeFilter(o.getWorkTime().substring(0, 7));
            }else{
                o.setWorkTimeFilter(o.getWorkTime());
            }


            if (StringUtils.isEmpty(o.getSalesTo())) o.setSalesTo(MesExtConstWords.ONE_SPACE);

        });
    }

    private Map<String, List<JxOqcCheckStatisticsReportModel>> packOqcCheckStatisticsMap(List<JxOqcCheckStatisticsReportModel> modelList, Integer dimension) {
        Map<String, List<JxOqcCheckStatisticsReportModel>> modelMap;
        if (CollectionUtils.isEmpty(modelList)) {
            return null;
        }
        switch (MesExtEnumUtil.REPORT_DIMENSION_CATEGORY_OR_SALESTO_OR_PART.getByValue(dimension)) {
            case SALES_TO:
                modelMap = modelList.stream().filter(
                        o -> (null != o && !StringUtils.isEmpty(o.getWorkTimeFilter()) && !StringUtils.isEmpty(o.getCategoryCode3())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTimeFilter()).add(o.getCategoryCode3()).add(o.getSalesTo()).toString())));
                break;
            case PART_NO:
                modelMap = modelList.stream().filter(
                        o -> (null != o && !StringUtils.isEmpty(o.getWorkTimeFilter()) && !StringUtils.isEmpty(o.getCategoryCode3()) && !StringUtils.isEmpty(o.getPartNo())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTimeFilter()).add(o.getCategoryCode3()).add(o.getSalesTo()).add(o.getPartNo()).toString())));
                break;
            case CATEGORY_CODE3:
            default:
                modelMap = modelList.stream().filter(
                        o -> (null != o && !StringUtils.isEmpty(o.getWorkTimeFilter()) && !StringUtils.isEmpty(o.getCategoryCode3())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTimeFilter()).add(o.getCategoryCode3()).toString())));
                break;
        }
        return modelMap;
    }

    private void packOqcCheckListWorkTime4OqcCheckStatistics(List<JxOqcCheckReportModel> oqcCheckList, JxOqcCheckStatisticsReportModel model) {
        if (CollectionUtils.isEmpty(oqcCheckList)) {
            return;
        }

        Map<String, List<MesBadnessType>> badnessTypeMap = buBadnessTypeService.getBadnessTypeMap(model.getOrganizeCode());

        Map<String, List<MesBadnessClassify>> badnessClassifyMap = badnessClassifyService.getBadnessClassifyMap(model.getOrganizeCode());

        oqcCheckList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()))).forEach(o -> {

            o.setWorkTimeBak(o.getWorkTime());

            if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH_OR_YAER.YEAR.getValue() == model.getDimension()) {
                o.setWorkTime(o.getWorkTime().substring(0, 4));
            } else if (MesExtEnumUtil.REPORT_DIMENSION_DAY_OR_MONTH_OR_YAER.MONTH.getValue() == model.getDimension()) {
                o.setWorkTime(o.getWorkTime().substring(0, 7));
            }

            if (StringUtils.isEmpty(o.getSalesTo())) o.setSalesTo(MesExtConstWords.ONE_SPACE);

            if (StringUtils.isEmpty(o.getSerialNumber())) o.setSerialNumber(MesExtConstWords.ONE_SPACE);

            if (StringUtils.isEmpty(o.getBadnessClassifyDetailName())) o.setBadnessClassifyDetailName(MesExtConstWords.ONE_SPACE);

            o.setWorkOrderTypeName(StringUtils.isEmpty(o.getWorkOrderType()) ? null : MesExtEnumUtil.WORK_ORDER_TYPE.valueOfDescription(o.getWorkOrderType()));
            o.setOqcNoTypeName(MesExtEnumUtil.OQC_CHECK_TYPE.valueOfDescription(o.getOqcNoType()));
            o.setOqcTypeName(MesExtEnumUtil.OQC_TYPE.valueOfDescription(o.getOqcType()));
            o.setCheckResultName(MesExtEnumUtil.OQC_CHECK_RESULT.UNQUALIFIED.getDescription());
            o.setBadnessTypeName((!StringUtils.isEmpty(o.getBadnessTypeCode()) && !CollectionUtils.isEmpty(badnessTypeMap) && badnessTypeMap.containsKey(o.getBadnessTypeCode())) ?
                    badnessTypeMap.get(o.getBadnessTypeCode()).get(0).getBadnessTypeName() : null);
            o.setBadnessClassifyName((!StringUtils.isEmpty(o.getBadnessTypeCode()) && !StringUtils.isEmpty(o.getBadnessClassifyCode()) && !CollectionUtils.isEmpty(badnessClassifyMap) &&
                    badnessClassifyMap.containsKey(new StringJoiner(MesExtConstWords.AND).add(o.getBadnessTypeCode()).add(o.getBadnessClassifyCode()).toString())) ?
                    badnessClassifyMap.get(new StringJoiner(MesExtConstWords.AND).add(o.getBadnessTypeCode()).add(o.getBadnessClassifyCode()).toString()).get(0).getBadnessClassifyName() : null);

        });
    }

    private Map<String, List<JxOqcCheckReportModel>> packOqcCheckMap4OqcCheckStatistics(List<JxOqcCheckReportModel> oqcCheckList, Integer dimension) {
        Map<String, List<JxOqcCheckReportModel>> modelMap;
        if (CollectionUtils.isEmpty(oqcCheckList)) {
            return null;
        }
        switch (MesExtEnumUtil.REPORT_DIMENSION_CATEGORY_OR_SALESTO_OR_PART.getByValue(dimension)) {
            case SALES_TO:
                modelMap = oqcCheckList.stream().filter(
                        o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()) && !StringUtils.isEmpty(o.getCategoryCode3())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTime()).add(o.getCategoryCode3()).add(o.getSalesTo()).toString())));
                break;
            case PART_NO:
                modelMap = oqcCheckList.stream().filter(
                        o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()) && !StringUtils.isEmpty(o.getCategoryCode3()) && !StringUtils.isEmpty(o.getPartNo())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTime()).add(o.getCategoryCode3()).add(o.getSalesTo()).add(o.getPartNo()).toString())));
                break;
            case CATEGORY_CODE3:
            default:
                modelMap = oqcCheckList.stream().filter(
                        o -> (null != o && !StringUtils.isEmpty(o.getWorkTime()) && !StringUtils.isEmpty(o.getCategoryCode3())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND).add(o.getWorkTime()).add(o.getCategoryCode3()).toString())));
                break;
        }
        return modelMap;
    }

    private void packResult4OqcCheckStatistics(JxOqcCheckStatisticsReportModel model, Map<String, List<JxOqcCheckStatisticsReportModel>> modelMap,
                                               Map<String, List<JxOqcCheckReportModel>> oqcCheckMap, List<MesBadnessType> badnessTypeList) {

        List<Map<String, Object>> dataList = new ArrayList<>();

        for (String key : modelMap.keySet()) {
            if (StringUtils.isEmpty(key)) continue;

            List<JxOqcCheckStatisticsReportModel> itemList = modelMap.get(key);
            if (CollectionUtils.isEmpty(itemList)) continue;

            List<JxOqcCheckReportModel> detailList = CollectionUtils.isEmpty(oqcCheckMap) ? null : oqcCheckMap.get(key);
            Map<String, List<JxOqcCheckReportModel>> oqcCheckItemMap = getOqcCheckItemMap4OqcCheckStatistics(detailList);

            String[] keyArr = key.split(MesExtConstWords.AND);

            Map<String, Object> data = new HashMap<>();
            if (!CollectionUtils.isEmpty(detailList)) data.put(MesExtConstWords.DETAIL_LIST, sortDetailList4OqcCheckStatistics(detailList));

            //根据产线和物料编码分组统计 temListByWorkCenterCodeAndPartNo
            Map<String, List<JxOqcCheckStatisticsReportModel>> temMapByWorkCenterCodeAndPartNo = getOqcCheckStastisticsMap(itemList);
            packOqcCheckStatisticsData(data, keyArr, model.getDimension1(), itemList.get(0));
            //生产批量数=产量行
            log.info(" BU-出货检验月报日报 当前维度key: {}", key);
            data.put(MesExtConstWords.WORK_TIMES_QTY, String.valueOf(CollectionUtils.isEmpty(temMapByWorkCenterCodeAndPartNo) ? 0 :temMapByWorkCenterCodeAndPartNo.keySet().size()));
            //检验批量数=有检验结果的产量行数
            Double lastCheckedQty = getLastCheckedQty4OqcCheckStatistics(itemList);
            data.put(MesExtConstWords.LAST_CHECKED_QTY, String.valueOf(lastCheckedQty.intValue()));
            //检验台数=汇总产量数量的抽检数量
            Double checkAmountQty = itemList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getSpotCheckQty()))).mapToDouble(JxOqcCheckStatisticsReportModel::getSpotCheckQty).sum();
            data.put(MesExtConstWords.CHECK_AMOUNT_QTY, String.valueOf(checkAmountQty.intValue()));
            //产量=汇总产量数量的产量
            Double qty = itemList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getQty()))).mapToDouble(JxOqcCheckStatisticsReportModel::getQty).sum();
            data.put(MesExtConstWords.QTY, String.valueOf(qty.intValue()));
            //抽样率=检验台数/产量,保留2位小数
            data.put(MesExtConstWords.SAMPLE_RATE, getRateDecimalTwo(checkAmountQty, qty));
            //缺点数=汇总检验单不合格行数
            Double unQcQty = getOqcCheckStatisticsUnQcQty(detailList);
            data.put(MesExtConstWords.UN_QC_QTY, String.valueOf(unQcQty.intValue()));
            //不良率
            data.put(MesExtConstWords.UN_QC_RATE, getRateDecimalTwo(unQcQty, lastCheckedQty));
            //动态不良类型发生次数
            for (MesBadnessType buBadnessType : badnessTypeList) {
                if (null == buBadnessType) continue;
                data.put(MesExtConstWords.QTY + buBadnessType.getBadnessTypeCode(), getOqcCheckStatisticsTypeQty(oqcCheckItemMap, buBadnessType.getBadnessTypeCode()));
            }

            dataList.add(data);
        }

        model.setDataList(dataList);
    }

    private Map<String, List<JxOqcCheckStatisticsReportModel>> getOqcCheckStastisticsMap(List<JxOqcCheckStatisticsReportModel> itemList) {
        return itemList.stream().filter(item -> !StringUtils.isEmpty(item.getWorkTime()) && !StringUtils.isEmpty(item.getWorkCenterCode()) && !StringUtils.isEmpty(item.getPartNo()) && !StringUtils.isEmpty(item.getShiftCode()))
                .collect(Collectors.groupingBy(item -> new StringJoiner(MesExtConstWords.AND).add(item.getWorkTime()).add(item.getWorkCenterCode()).add(item.getShiftCode()).add(item.getPartNo()).toString()));
    }

    private Map<String, List<JxOqcCheckReportModel>> getOqcCheckItemMap4OqcCheckStatistics(List<JxOqcCheckReportModel> detailList) {
        return CollectionUtils.isEmpty(detailList) ? null :
                detailList.stream().filter(o -> null != o).collect(Collectors.groupingBy(JxOqcCheckReportModel::getBadnessTypeCode));
    }

    private List<JxOqcCheckReportModel> sortDetailList4OqcCheckStatistics(List<JxOqcCheckReportModel> detailList) {
        return detailList.stream().sorted(Comparator.comparing(JxOqcCheckReportModel::getWorkTime).reversed()
                .thenComparing(JxOqcCheckReportModel::getWorkCenterCode)
                .thenComparing(JxOqcCheckReportModel::getPartNo)
                .thenComparing(JxOqcCheckReportModel::getWorkOrderNo)
                .thenComparing(JxOqcCheckReportModel::getShiftCode)
                .thenComparing(JxOqcCheckReportModel::getSerialNumber)
                .thenComparing(JxOqcCheckReportModel::getOqcNoType)
                .thenComparing(JxOqcCheckReportModel::getBadnessTypeCode)
                .thenComparing(JxOqcCheckReportModel::getBadnessClassifyCode)
                .thenComparing(JxOqcCheckReportModel::getBadnessClassifyDetailName)).collect(Collectors.toList());
    }

    private void packOqcCheckStatisticsData(Map<String, Object> data, String[] keyArr, Integer dimension, JxOqcCheckStatisticsReportModel model) {
        data.put(MesExtConstWords.WORK_TIME, keyArr[0]);
        data.put(MesExtConstWords.CATEGORY_CODE3, keyArr[1]);

        switch (MesExtEnumUtil.REPORT_DIMENSION_CATEGORY_OR_SALESTO_OR_PART.getByValue(dimension)) {
            case SALES_TO:
                data.put(MesExtConstWords.SALES_TO, keyArr[2]);
                data.put(MesExtConstWords.SALES_TO_NAME, keyArr[2].equals(MesExtConstWords.ONE_SPACE) ? MesExtConstWords.ONE_SPACE : MesExtEnumUtil.SALES_TO_STR.valueOfDescription(keyArr[2]));
                break;
            case PART_NO:
                data.put(MesExtConstWords.SALES_TO, keyArr[2]);
                data.put(MesExtConstWords.SALES_TO_NAME, keyArr[2].equals(MesExtConstWords.ONE_SPACE) ? MesExtConstWords.ONE_SPACE : MesExtEnumUtil.SALES_TO_STR.valueOfDescription(keyArr[2]));
                data.put(MesExtConstWords.PART_NO, keyArr[3]);
                data.put(MesExtConstWords.PART_NAME_RDD, model.getPartNameRdd());
                break;
            case CATEGORY_CODE3:
            default:
                break;
        }

    }

    /**
     * 检查批次
     * @param itemList
     * @return
     */
    private Double getLastCheckedQty4OqcCheckStatistics(List<JxOqcCheckStatisticsReportModel> itemList) {
        List<JxOqcCheckStatisticsReportModel> lastCheckedList = itemList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCheckResult()))).collect(Collectors.toList());
        Map<String, List<JxOqcCheckStatisticsReportModel>> oqcCheckStastisticsMap = getOqcCheckStastisticsMap(lastCheckedList);
        return CollectionUtils.isEmpty(oqcCheckStastisticsMap) ? new Double(0) : new Double(oqcCheckStastisticsMap.size());
    }

    private String getRateDecimalTwo(Double d1, Double d2) {
        if (StringUtils.isEmpty(d2) || MathOperation.compareTo(d2, new Double(0)) == 0) {
            return null;
        }
        return MathOperation.div(MathOperation.mul(d1, 100), d2, 2) + MesExtConstWords.PERCENT;
    }

    private Double getOqcCheckStatisticsUnQcQty(List<JxOqcCheckReportModel> detailList) {
        List<String> unQcList = CollectionUtils.isEmpty(detailList) ? null :
                detailList.stream().filter(o -> null != o).map(o ->
                        new StringJoiner(MesExtConstWords.AND).add(o.getWorkOrderNo()).add(o.getWorkTimeBak()).add(o.getShiftCode()).toString()).collect(Collectors.toList());
        unQcList = CollectionUtils.isEmpty(unQcList) ? null : unQcList.stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        return CollectionUtils.isEmpty(unQcList) ? new Double(0) : new Double(unQcList.size());
    }

    private String getOqcCheckStatisticsTypeQty(Map<String, List<JxOqcCheckReportModel>> oqcCheckItemMap, String badnessTypeCode) {
        return (!CollectionUtils.isEmpty(oqcCheckItemMap) && oqcCheckItemMap.containsKey(badnessTypeCode)) ? String.valueOf(oqcCheckItemMap.get(badnessTypeCode).size()) : MesExtConstWords.ZERO_STR;
    }

    private void sortDataList4OqcCheckStatistics(JxOqcCheckStatisticsReportModel model) {
        switch (MesExtEnumUtil.REPORT_DIMENSION_CATEGORY_OR_SALESTO_OR_PART.getByValue(model.getDimension1())) {
            case SALES_TO:
                model.getDataList().sort(Comparator.comparing(JxOqcReportFormService::comparingByDate4OqcCheckStatistics)
                        .thenComparing(JxOqcReportFormService::comparingByCategoryCode4OqcCheckStatistics)
                        .thenComparing(JxOqcReportFormService::comparingBySalesTo4OqcCheckStatistics));
                break;
            case PART_NO:
                model.getDataList().sort(Comparator.comparing(JxOqcReportFormService::comparingByDate4OqcCheckStatistics)
                        .thenComparing(JxOqcReportFormService::comparingByCategoryCode4OqcCheckStatistics)
                        .thenComparing(JxOqcReportFormService::comparingBySalesTo4OqcCheckStatistics)
                        .thenComparing(JxOqcReportFormService::comparingByPartNo4OqcCheckStatistics));
                break;
            case CATEGORY_CODE3:
            default:
                model.getDataList().sort(Comparator.comparing(JxOqcReportFormService::comparingByDate4OqcCheckStatistics)
                        .thenComparing(JxOqcReportFormService::comparingByCategoryCode4OqcCheckStatistics));
                break;
        }
    }



    private static String comparingByDate4OqcCheckStatistics(Map<String, Object> map) {
        return (String) map.get(MesExtConstWords.WORK_TIME);
    }

    private static String comparingByCategoryCode4OqcCheckStatistics(Map<String, Object> map) {
        return (String) map.get(MesExtConstWords.CATEGORY_CODE3);
    }

    private static String comparingBySalesTo4OqcCheckStatistics(Map<String, Object> map) {
        return (String) map.get(MesExtConstWords.SALES_TO);
    }

    private static String comparingByPartNo4OqcCheckStatistics(Map<String, Object> map) {
        return (String) map.get(MesExtConstWords.PART_NO);
    }


}
