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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesMediaFileCfgService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesAssemblyExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionCustomContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionProcessContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProdRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionAssemblyNosortContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesProductionAssemblySortContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.repository.MesAssemblyNosortCfgRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesProductionAssemblyRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesProductionAssemblyUniqueRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderAssemblyRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
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;

@Slf4j
@Service
public class MesAssemblyExtService implements IMesAssemblyExtService {

    @Autowired
    private MesWorkOrderAssemblyRepository workOrderAssemblyRepository;

    @Autowired
    private MesProductionAssemblyRepository productionAssemblyRepository;

    @Autowired
    private MesProductionAssemblyUniqueRepository productionAssemblyUniqueRepository;

    @Autowired
    private MesAssemblyNosortCfgRepository assemblyNosortCfgRepository;

    @Autowired
    private IMesProductionCustomContextStepService productionCustomContextStepService;

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesMediaFileCfgService mediaFileCfgService;

    //【排序线】获取生产工单装配件绑定记录 -同时- 关联不可用规则 ; 判断是否剔除平行工位
    @Override
    public List<MesProductionAssemblySortContext> getProductionAssemblySortContextList(MesProdRuleContext prodRuleContext, Map<String, List<MesProdRuleIgnoreCfg>> prodRuleIgnoreCfgMap, Boolean isFilterParallel) {

        if (null == prodRuleContext) return null;

        if (StringUtils.isEmpty(prodRuleContext.getOrganizeCode()) || StringUtils.isEmpty(prodRuleContext.getWorkCenterCode()) ||
                StringUtils.isEmpty(prodRuleContext.getWorkCellCode()) || StringUtils.isEmpty(prodRuleContext.getProcessCode()) || StringUtils.isEmpty(prodRuleContext.getProductSn())) return null;

        //【排序线】获取生产工单装配件清单
        List<MesWorkOrderAssembly> workOrderAssemblyList = getWorkOrderAssemblyList(prodRuleContext, false);

        if (CollectionUtils.isEmpty(workOrderAssemblyList)) return null;

        //平行工位  获取当前工位的第一个装配件的工艺顺序号
        Integer processSeq = isFilterParallel ? getProcessSeq(workOrderAssemblyList, prodRuleContext.getWorkCellCode()) : null;
        if (!StringUtils.isEmpty(processSeq)) {
            prodRuleContext.setParallelInfo(String.format("{%s:%s}", MesPcnExtConstWords.PROCESS_SEQ, processSeq));
        }

        // 搜集待装配或者解绑的数据
        List<MesWorkOrderAssembly> unBindList = workOrderAssemblyList.stream().filter(o -> (null != o &&
                (o.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue()) == 0 ||
                        o.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_20.getValue()) == 0))).collect(Collectors.toList());

        //获取排序FILE文件URL
        Map<Long, String> fileMap = mediaFileCfgService.getMediaFileCfgMap(prodRuleContext.getOrganizeCode(), filterSortFileIdList(unBindList));

        List<MesProductionAssemblySortContext> productionAssemblySortContextList = new ArrayList<>();

        workOrderAssemblyList.forEach(o -> productionAssemblySortContextList.add(
                new MesProductionAssemblySortContext().copy(o).fileUrl(fileMap).foreignKey(prodRuleContext.getForeignKey())
                        .prodRuleIgnoreCfg(getProdRuleIgnoreCfg(prodRuleIgnoreCfgMap, o.getPid(), o.getEquipmentCode(), MesExtEnumUtil.PROD_RULE_IGNORE_DATA_SOURCE.DATA_SOURCE10.getValueStr()))
                )
        );

        return productionAssemblySortContextList;
    }

    //【排序线】获取生产工单装配件绑定记录 [前道所有装配件,无爆炸图与音频文件逻辑] -同时- 关联不可用规则 ; 判断是否剔除平行工位 ; 判断是否根据工序顺序号过滤后道
    @Override
    public List<MesProductionAssemblySortContext> getProductionAssemblySortPreCraftContextList(MesProdRuleContext prodRuleContext, Map<String, MesWorkCell> workCellMap,
                                                                                               Map<String, List<MesProdRuleIgnoreCfg>> prodRuleIgnoreCfgMap, Boolean isFilterParallel, Boolean isFilterAfterCraft) {

        if (null == prodRuleContext) return null;

        if (StringUtils.isEmpty(prodRuleContext.getOrganizeCode()) || StringUtils.isEmpty(prodRuleContext.getWorkCenterCode()) ||
                StringUtils.isEmpty(prodRuleContext.getWorkCellCode()) || StringUtils.isEmpty(prodRuleContext.getProcessCode()) || StringUtils.isEmpty(prodRuleContext.getProductSn())) return null;

        //【排序线】获取生产工单装配件清单 [前道所有装配件]
        List<MesWorkOrderAssembly> workOrderAssemblyList = getWorkOrderAssemblyListPreCraft(prodRuleContext, isFilterParallel, isFilterAfterCraft);

        if (CollectionUtils.isEmpty(workOrderAssemblyList)) return null;

        // 搜集非已装配的数据
        List<MesWorkOrderAssembly> unBindList = workOrderAssemblyList.stream().filter(o -> (null != o &&
                o.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_10.getValue()) != 0)).collect(Collectors.toList());

        //获取装配件绑定记录
        Map<Long, List<MesProductionAssembly>> productionAssemblyMap = groupProductionAssembly(getProductionAssemblySortList(prodRuleContext.getOrganizeCode(), prodRuleContext.getProductSn()));

        List<MesProductionAssemblySortContext> productionAssemblySortContextList = new ArrayList<>();

        workOrderAssemblyList.forEach(o -> productionAssemblySortContextList.add(
                new MesProductionAssemblySortContext()
                        .copy(o, getProductionAssembly(productionAssemblyMap, o.getId()), getIsCheckBindSeq(getWorkCell(workCellMap, o.getWorkCellCode())))
                        .foreignKey(prodRuleContext.getForeignKey())
                        .prodRuleIgnoreCfg(getProdRuleIgnoreCfg(prodRuleIgnoreCfgMap, o.getPid(), o.getEquipmentCode(), MesExtEnumUtil.PROD_RULE_IGNORE_DATA_SOURCE.DATA_SOURCE10.getValueStr()))
                )
        );

        return productionAssemblySortContextList;
    }

    //判断是否按序扫描
    private Integer getIsCheckBindSeq(MesWorkCell workCell) {
        return (null != workCell && !StringUtils.isEmpty(workCell.getIsSeqScan())) ? workCell.getIsSeqScan() : CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue();
    }

    //【排序线】获取生产工单装配件清单
    @Override
    public List<MesWorkOrderAssembly> getWorkOrderAssemblyList(MesProdRuleContext prodRuleContext, Boolean isShowAll) {

        if (null == prodRuleContext) return null;

        if (StringUtils.isEmpty(prodRuleContext.getOrganizeCode()) || StringUtils.isEmpty(prodRuleContext.getWorkCenterCode()) || StringUtils.isEmpty(prodRuleContext.getProductSn())) return null;

        if (!isShowAll && (StringUtils.isEmpty(prodRuleContext.getWorkCellCode()) || StringUtils.isEmpty(prodRuleContext.getProcessCode()))) return null;

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(prodRuleContext.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(prodRuleContext.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(prodRuleContext.getProductSn(), MesPcnExtConstWords.PRODUCT_SN, packBean);
        if (!isShowAll) {
            DdlPreparedPack.getStringEqualPack(prodRuleContext.getWorkCellCode(), MesPcnExtConstWords.WORK_CELL_CODE, packBean);
            DdlPreparedPack.getStringEqualPack(prodRuleContext.getProcessCode(), MesPcnExtConstWords.PROCESS_CODE, packBean);
        }

        return workOrderAssemblyRepository.findByHqlWhere(packBean);

    }

    //【排序线】获取生产工单装配件清单[前道所有装配件] 判断是否剔除平行工位 ; 判断是否根据工序顺序号过滤后道
    @Override
    public List<MesWorkOrderAssembly> getWorkOrderAssemblyListPreCraft(MesProdRuleContext prodRuleContext, Boolean isFilterParallel, Boolean isFilterAfterCraft) {

        //【排序线】获取生产工单装配件清单
        List<MesWorkOrderAssembly> workOrderAssemblyList = getWorkOrderAssemblyList(prodRuleContext, true);
        if (CollectionUtils.isEmpty(workOrderAssemblyList) || (!isFilterParallel && !isFilterAfterCraft)) return workOrderAssemblyList;

        //获取当前工位的第一个装配件的工艺顺序号
        Integer processSeq = isFilterAfterCraft ? getProcessSeq(workOrderAssemblyList, prodRuleContext.getWorkCellCode()) : null;

        //平行工位
        if (isFilterParallel) {
            //返回涉及到的平行工位代码集合
            List<String> parallelCellCodeList = checkIsExistParallelCellCode(workOrderAssemblyList, prodRuleContext.getWorkCellCode(), processSeq);
            if (!CollectionUtils.isEmpty(parallelCellCodeList)) {
                prodRuleContext.setParallelInfo(String.format("{%s:%s}", MesPcnExtConstWords.WORK_CELL_CODE, JSONObject.toJSONString(parallelCellCodeList)));
                //剔除平行工位的装配件
                workOrderAssemblyList = workOrderAssemblyList.stream().filter(o -> (null != o && (StringUtils.isEmpty(o.getProcessSeq())
                        || StringUtils.isEmpty(o.getWorkCellCode()) || !parallelCellCodeList.contains(o.getWorkCellCode())))).collect(Collectors.toList());
            }
        }

        if (CollectionUtils.isEmpty(workOrderAssemblyList)) return workOrderAssemblyList;

        //根据工序顺序号过滤后道
        if (isFilterAfterCraft && !StringUtils.isEmpty(processSeq)) {
            workOrderAssemblyList = workOrderAssemblyList.stream().filter(o -> (null != o &&
                    (StringUtils.isEmpty(o.getProcessSeq()) || o.getProcessSeq().compareTo(processSeq) <= 0))).collect(Collectors.toList());
        }

        return workOrderAssemblyList;
    }

    //获取当前工位的第一个装配件的工艺顺序号
    private Integer getProcessSeq(List<MesWorkOrderAssembly> workOrderAssemblyList, String workCellCode) {
        Optional<MesWorkOrderAssembly> optional = workOrderAssemblyList.stream().filter(o -> (null != o && workCellCode.equals(o.getWorkCellCode()) && !StringUtils.isEmpty(o.getProcessSeq()))).findFirst();
        return (null != optional && optional.isPresent()) ? optional.get().getProcessSeq() : null;
    }

    //返回涉及到的平行工位代码集合
    private List<String> checkIsExistParallelCellCode(List<MesWorkOrderAssembly> workOrderAssemblyList, String workCellCode, Integer processSeq) {
        //根据工艺顺序号分组
        Map<String, List<MesWorkOrderAssembly>> processSeqMap = CollectionUtils.isEmpty(workOrderAssemblyList) ? null :
                workOrderAssemblyList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkCellCode()) &&
                        !StringUtils.isEmpty(o.getProcessSeq()) && !StringUtils.isEmpty(o.getCraftCode())))
                        .collect(Collectors.groupingBy(o -> new StringJoiner(MesPcnExtConstWords.AND).add(o.getCraftCode()).add(o.getProcessSeq().toString()).toString()));
        if (CollectionUtils.isEmpty(processSeqMap)) return null;
        List<String> parallelCellCodeList = null;
        for (Map.Entry<String, List<MesWorkOrderAssembly>> entry : processSeqMap.entrySet()) {
            if (null == entry) continue;
            //搜集工位代码集合再去重
            List<String> workCellCodeList = (entry.getValue().stream().filter(o -> null != o).map(MesWorkOrderAssembly::getWorkCellCode)
                    .collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
            if (CollectionUtils.isEmpty(workCellCodeList) || workCellCodeList.size() == 1) continue;
            //判断是否是当前工位的平行工位
            if (!workCellCodeList.contains(workCellCode)) {
                //存在processSeq则表示需要过滤后道, 判断当前循环的工艺顺序号是否属于后道
                if (!StringUtils.isEmpty(processSeq)) {
                    List<Integer> processSeqList = (entry.getValue().stream().filter(o -> null != o).map(MesWorkOrderAssembly::getProcessSeq)
                            .collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
                    //工艺顺序号升序
                    processSeqList.sort(Comparator.naturalOrder());
                    if (processSeqList.get(0).compareTo(processSeq) > 0) continue;
                }
                //工艺顺序号升序
                workCellCodeList.sort(Comparator.naturalOrder());
                workCellCodeList.remove(0);
            } else {
                //当前工位
                workCellCodeList.remove(workCellCode);
            }

            if (CollectionUtils.isEmpty(parallelCellCodeList)) parallelCellCodeList = new ArrayList<>();
            parallelCellCodeList.addAll(workCellCodeList);
        }
        return parallelCellCodeList;
    }

    //获取装配件绑定记录【排序】
    @Override
    public List<MesProductionAssembly> getProductionAssemblySortList(String organizeCode, String productSn) {

        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(productSn)) return null;

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(productSn, MesPcnExtConstWords.PRODUCT_SN, packBean);

        return productionAssemblyRepository.findByHqlWhere(packBean);

    }

    @Override
    public List<MesProductionAssembly> getProductionAssemblyList(String organizeCode, String assemblySn) {
        return productionAssemblyRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.ASSEMBLY_SN},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), assemblySn});
    }

    @Override
    public List<MesProductionAssemblyUnique> getProductionAssemblyUniqueList(String organizeCode, String assemblySn) {
        return productionAssemblyUniqueRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.ASSEMBLY_SN},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), assemblySn});
    }

    @Override
    public List<MesProductionAssemblyUnique> getProductionAssemblyUniqueListByProductSn(String organizeCode, String productSn) {
        return productionAssemblyUniqueRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PRODUCT_SN},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), productSn});
    }

    //获取非排序装配件配置信息 -同时- 关联不可用规则
    @Override
    public List<MesProductionAssemblyNosortContext> getProductionAssemblyNosortContextList(MesProdRuleContext prodRuleContext, Map<String, List<MesProdRuleIgnoreCfg>> prodRuleIgnoreCfgMap) {

        if (null == prodRuleContext || StringUtils.isEmpty(prodRuleContext.getOrganizeCode()) || StringUtils.isEmpty(prodRuleContext.getPid())) return null;

        //获取非排序装配件配置信息
        List<MesAssemblyNosortCfg> assemblyNosortCfgList = getAssemblyNosortCfgList(prodRuleContext.getOrganizeCode(), prodRuleContext.getPid());

        if (CollectionUtils.isEmpty(assemblyNosortCfgList)) return null;

        //获取非排序FILE文件URL
        Map<Long, String> fileMap = mediaFileCfgService.getMediaFileCfgMap(prodRuleContext.getOrganizeCode(), filterNosortFileIdList(assemblyNosortCfgList));

        List<MesProductionAssemblyNosortContext> productionAssemblyNosortContextList = new ArrayList<>();

        //遍历装配件规则, 实例化装配件清单对象, 判断是否配置可复用
        assemblyNosortCfgList.forEach(o -> {
            MesProductionAssemblyNosortContext productionAssemblyNosortContext = new MesProductionAssemblyNosortContext().copy(prodRuleContext, o).fileUrl(fileMap).foreignKey(prodRuleContext.getForeignKey());
            productionAssemblyNosortContext.overrideAssemblyStatus(productionCustomContextStepService.getRepeatAssemblySn(prodRuleContext.getOrganizeCode(), prodRuleContext.getWorkCenterCode(), prodRuleContext.getWorkCellCode(), productionAssemblyNosortContext))
                    .prodRuleIgnoreCfg(getProdRuleIgnoreCfg(prodRuleIgnoreCfgMap, o.getId(), o.getEquipmentCode(), MesExtEnumUtil.PROD_RULE_IGNORE_DATA_SOURCE.DATA_SOURCE30.getValueStr()));
            productionAssemblyNosortContextList.add(productionAssemblyNosortContext);
        });

        return productionAssemblyNosortContextList;
    }

    //获取不可用规则
    @Override
    public String getProdRuleIgnoreCfg(Map<String, List<MesProdRuleIgnoreCfg>> prodRuleIgnoreCfgMap, Long id, String equipmentCode, String dataSorce) {
        if (CollectionUtils.isEmpty(prodRuleIgnoreCfgMap) || StringUtils.isEmpty(id) || StringUtils.isEmpty(dataSorce)) return null;
        String key = new StringJoiner(MesPcnExtConstWords.AND).add(dataSorce).add(equipmentCode).add(id.toString()).toString();
        return prodRuleIgnoreCfgMap.containsKey(key) ? JSONObject.toJSONString(prodRuleIgnoreCfgMap.get(key)) : null;
    }

    //获取非排序装配件配置信息
    @Override
    public List<MesAssemblyNosortCfg> getAssemblyNosortCfgList(String organizeCode, Long pid) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(pid)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getNumEqualPack(pid, MesPcnExtConstWords.PID, packBean);
        return assemblyNosortCfgRepository.findByHqlWhere(packBean);
    }

    //获取设备的装配件规则清单
    @Override
    public List<MesAssemblyNosortCfg> getAssemblyNosortCfgList(String organizeCode, String equipmentCode) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(equipmentCode)) return null;
        return assemblyNosortCfgRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.EQUIPMENT_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), equipmentCode});
    }

    //获取设备的装配件规则清单 -同时- 关联不可用规则
    @Override
    public List<MesProductionAssemblyNosortContext> getProductionAssemblyNosortContextList(String organizeCode, String equipmentCode, Map<String, List<MesProdRuleIgnoreCfg>> prodRuleIgnoreCfgMap) {

        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(equipmentCode)) return null;

        List<MesAssemblyNosortCfg> assemblyNosortCfgList = getAssemblyNosortCfgList(organizeCode, equipmentCode);
        if (CollectionUtils.isEmpty(assemblyNosortCfgList)) return null;

        List<MesProductionAssemblyNosortContext> productionAssemblyNosortContextList = new ArrayList<>();

        assemblyNosortCfgList.forEach(o -> productionAssemblyNosortContextList.add(
                new MesProductionAssemblyNosortContext().copy(o)
                        .prodRuleIgnoreCfg(getProdRuleIgnoreCfg(prodRuleIgnoreCfgMap, o.getId(), o.getEquipmentCode(), MesExtEnumUtil.PROD_RULE_IGNORE_DATA_SOURCE.DATA_SOURCE30.getValueStr()))
                )
        );

        return productionAssemblyNosortContextList;
    }

    //【排序线】获取生产工单装配件清单
    @Override
    public List<MesWorkOrderAssembly> getWorkOrderAssemblyList(String organizeCode, String workOrderNo, String productSn, String craftCode) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workOrderNo) || StringUtils.isEmpty(productSn) || StringUtils.isEmpty(craftCode)) return null;
        return workOrderAssemblyRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_ORDER_NO, MesPcnExtConstWords.PRODUCT_SN, MesPcnExtConstWords.CRAFT_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), workOrderNo, productSn, craftCode});
    }

    //【排序线】获取生产工单装配件清单
    @Override
    public List<MesWorkOrderAssembly> getWorkOrderAssemblyList(String organizeCode, String workCenterCode, String workCellCode, String workOrderNo, List<String> productSnList) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) || StringUtils.isEmpty(workCellCode) || (StringUtils.isEmpty(workOrderNo) && CollectionUtils.isEmpty(productSnList))) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(workCellCode, MesPcnExtConstWords.WORK_CELL_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(workOrderNo, MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        if (!CollectionUtils.isEmpty(productSnList)) {
            if (productSnList.size() == 1) DdlPreparedPack.getStringEqualPack(productSnList.get(0), MesPcnExtConstWords.PRODUCT_SN, packBean);
            else DdlPreparedPack.getInPackList(productSnList, MesPcnExtConstWords.PRODUCT_SN, packBean);
        }
        return workOrderAssemblyRepository.findByHqlWhere(packBean);
    }

    //获取工单装配件记录【排序】
    @Override
    public List<MesWorkOrderAssembly> getWorkOrderAssemblyList(String organizeCode, String workOrderNo) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workOrderNo)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workOrderNo, MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        return workOrderAssemblyRepository.findByHqlWhere(packBean);
    }

    //搜集非排序文件ID集合
    private List<Long> filterNosortFileIdList(List<MesAssemblyNosortCfg> assemblyNosortCfgList) {
        if (CollectionUtils.isEmpty(assemblyNosortCfgList)) return null;
        List<Long> imageFileIdList = assemblyNosortCfgList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getImageFileId()))).map(MesAssemblyNosortCfg::getImageFileId).collect(Collectors.toList());
        List<Long> audioFileIdList = assemblyNosortCfgList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getAudioFileId()))).map(MesAssemblyNosortCfg::getAudioFileId).collect(Collectors.toList());
        return filterFileIdList(imageFileIdList, audioFileIdList);
    }

    //搜集排序文件ID集合
    private List<Long> filterSortFileIdList(List<MesWorkOrderAssembly> workOrderAssemblyList) {
        if (CollectionUtils.isEmpty(workOrderAssemblyList)) return null;
        List<Long> imageFileIdList = workOrderAssemblyList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getImageFileId()))).map(MesWorkOrderAssembly::getImageFileId).collect(Collectors.toList());
        List<Long> audioFileIdList = workOrderAssemblyList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getAudioFileId()))).map(MesWorkOrderAssembly::getAudioFileId).collect(Collectors.toList());
        return filterFileIdList(imageFileIdList, audioFileIdList);
    }

    //搜集文件ID集合
    private List<Long> filterFileIdList(List<Long> imageFileIdList, List<Long> audioFileIdList) {
        if (!CollectionUtils.isEmpty(imageFileIdList) && CollectionUtils.isEmpty(audioFileIdList)) return imageFileIdList;
        if (CollectionUtils.isEmpty(imageFileIdList) && !CollectionUtils.isEmpty(audioFileIdList)) return audioFileIdList;
        imageFileIdList.addAll(audioFileIdList);
        return imageFileIdList;
    }

    //根据生产工单装配件清单ID分组
    private Map<Long, List<MesProductionAssembly>> groupProductionAssembly(List<MesProductionAssembly> productionAssemblyList) {
        return CollectionUtils.isEmpty(productionAssemblyList) ? null :
                productionAssemblyList.stream().filter(o -> (null != o && (o.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_30.getValue()) == 0 ||
                        o.getAssemblyStatus().compareTo(MesExtEnumUtil.ASSEMBLY_STATUS.ASSEMBLY_STATUS_40.getValue()) == 0))).collect(Collectors.groupingBy(MesProductionAssembly::getSourceId));
    }

    //根据装配件清单ID获取装配件绑定记录
    private MesProductionAssembly getProductionAssembly(Map<Long, List<MesProductionAssembly>> productionAssemblyMap, Long id) {
        return (CollectionUtils.isEmpty(productionAssemblyMap) || !productionAssemblyMap.containsKey(id)) ? null : productionAssemblyMap.get(id).get(0);
    }

    //获取工位
    private MesWorkCell getWorkCell(Map<String, MesWorkCell> workCellMap, String workCellCode) {
        return CollectionUtils.isEmpty(workCellMap) ? null : workCellMap.get(workCellCode);
    }

    //根据条件修改装配件绑定记录的装配状态
    @Override
    public void saveProductionAssemblyStatusByDdlPackBean(DdlPackBean packBean, String userInfo, Integer assemblyStatus) {
        if (StringUtils.isEmpty(userInfo) || StringUtils.isEmpty(assemblyStatus)) return;
        productionAssemblyRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.ASSEMBLY_STATUS},
                new Object[]{userInfo, TimeTool.getNowTime(true), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), assemblyStatus},
                packBean);
    }

    //根据条件修改装配件绑定唯一性记录的装配状态
    @Override
    public void saveProductionAssemblyUniqueStatusByDdlPackBean(DdlPackBean packBean, String userInfo, Integer assemblyStatus) {
        if (StringUtils.isEmpty(userInfo) || StringUtils.isEmpty(assemblyStatus)) return;
        productionAssemblyUniqueRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.ASSEMBLY_STATUS},
                new Object[]{userInfo, TimeTool.getNowTime(true), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), assemblyStatus},
                packBean);
    }

    //根据条件修改工单装配件记录的装配状态
    @Override
    public void saveWorkOrderAssemblyStatusByDdlPackBean(DdlPackBean packBean, String userInfo, Integer assemblyStatus) {
        if (StringUtils.isEmpty(userInfo) || StringUtils.isEmpty(assemblyStatus)) return;
        workOrderAssemblyRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.ASSEMBLY_STATUS},
                new Object[]{userInfo, TimeTool.getNowTime(true), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), assemblyStatus},
                packBean);
    }

    @Override
    public MesWorkOrderAssembly getWorkOrderAssembly(String organizeCode, Long id) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(id)) return null;
        return workOrderAssemblyRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.ID},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), id});
    }

}
